[#19] Implement Home Assistant state events listener
This commit is contained in:
		| @@ -1,5 +1,11 @@ | ||||
| part of 'main.dart'; | ||||
|  | ||||
| class StateChangedEvent { | ||||
|   String entityId; | ||||
|  | ||||
|   StateChangedEvent(this.entityId); | ||||
| } | ||||
|  | ||||
| class HassioDataModel { | ||||
|   String _hassioAPIEndpoint; | ||||
|   String _hassioPassword; | ||||
| @@ -28,7 +34,8 @@ class HassioDataModel { | ||||
|     if ((_fetchCompleter != null) && (!_fetchCompleter.isCompleted)) { | ||||
|       debugPrint("Previous fetch is not complited"); | ||||
|     } else { | ||||
|       _fetchingTimer = new Timer(new Duration(seconds: 10), () { | ||||
|       //Fetch timeout timer | ||||
|       _fetchingTimer = Timer(Duration(seconds: 10), () { | ||||
|         _fetchCompleter.completeError({"message": "Data fetching timeout."}); | ||||
|         _hassioChannel.sink.close(); | ||||
|         _hassioChannel = null; | ||||
| @@ -76,15 +83,15 @@ class HassioDataModel { | ||||
|   } | ||||
|  | ||||
|   _handleMessage(Completer connectionCompleter, String message) { | ||||
|     debugPrint("<[Receive]Message from Home Assistant:"); | ||||
|     var data = json.decode(message); | ||||
|     debugPrint("   type: ${data['type']}"); | ||||
|     debugPrint("[Received]Message type: ${data['type']}"); | ||||
|     if (data["type"] == "auth_required") { | ||||
|       debugPrint("   sending auth!"); | ||||
|       _sendMessageRaw('{"type": "auth","api_password": "$_hassioPassword"}'); | ||||
|     } else if (data["type"] == "auth_ok") { | ||||
|       debugPrint("   auth done"); | ||||
|       debugPrint("Connection done"); | ||||
|       debugPrint("Connection done."); | ||||
|       sendSubscribe(); | ||||
|       connectionCompleter.complete(); | ||||
|     } else if (data["type"] == "auth_invalid") { | ||||
|       connectionCompleter.completeError({message: "Auth error: ${data["message"]}"}); | ||||
| @@ -99,18 +106,35 @@ class HassioDataModel { | ||||
|         } else if (data["id"] == _currentMssageId) { | ||||
|           debugPrint("Request id:$_currentMssageId was successful"); | ||||
|         } else { | ||||
|           _handleErrorMessage({"message" : "Wrong message ID"}); | ||||
|           debugPrint("Skipped message due to messageId:"); | ||||
|           debugPrint(message); | ||||
|         } | ||||
|       } else { | ||||
|         _handleErrorMessage(data["error"]); | ||||
|       } | ||||
|     } else if (data["type"] == "event") { | ||||
|       if ((data["event"] != null) && (data["event"]["event_type"] == "state_changed")) { | ||||
|         _handleEntityStateChange(data["event"]["data"]); | ||||
|       } else if (data["event"] != null) { | ||||
|         debugPrint("Unhandled event type: ${data["event"]["event_type"]}"); | ||||
|       } else { | ||||
|         debugPrint("Event is null"); | ||||
|       } | ||||
|     } else { | ||||
|       debugPrint("Unknown message type"); | ||||
|       debugPrint(message); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   _handleErrorMessage(Object error) { | ||||
|     debugPrint("Error: ${error.toString()}"); | ||||
|     if (!_statesCompleter.isCompleted) _statesCompleter.completeError(error); | ||||
|     if (!_servicesCompleter.isCompleted) _servicesCompleter.completeError(error); | ||||
|     if ((_statesCompleter != null) && (!_statesCompleter.isCompleted)) _statesCompleter.completeError(error); | ||||
|     if ((_servicesCompleter != null) && (!_servicesCompleter.isCompleted)) _servicesCompleter.completeError(error); | ||||
|   } | ||||
|  | ||||
|   void sendSubscribe() { | ||||
|     _incrementMessageId(); | ||||
|     _sendMessageRaw('{"id": $_currentMssageId, "type": "subscribe_events"}'); | ||||
|   } | ||||
|  | ||||
|   Future _getStates() { | ||||
| @@ -137,14 +161,19 @@ class HassioDataModel { | ||||
|  | ||||
|   _sendMessageRaw(message) { | ||||
|     _reConnectSocket().then((r) { | ||||
|       debugPrint(">[Send]Sending to Home Assistant:"); | ||||
|       debugPrint("   $message"); | ||||
|       debugPrint("[Sent]$message"); | ||||
|       _hassioChannel.sink.add(message); | ||||
|     }).catchError((e){ | ||||
|       debugPrint("Unable to connect for sending: $e"); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   void _handleEntityStateChange(Map eventData) { | ||||
|     String entityId = eventData["entity_id"]; | ||||
|     _entitiesData[entityId].addAll(eventData["new_state"]); | ||||
|     eventBus.fire(new StateChangedEvent(eventData["entity_id"])); | ||||
|   } | ||||
|  | ||||
|   void _parseServices(Map data) { | ||||
|     Map result = {}; | ||||
|     debugPrint("Parsing ${data.length} Home Assistant service domains"); | ||||
| @@ -202,11 +231,10 @@ class HassioDataModel { | ||||
|     }); | ||||
|  | ||||
|     //Gethering information for UI | ||||
|  | ||||
|     debugPrint("Gethering views"); | ||||
|     uiGroups.forEach((viewId) { | ||||
|       var viewGroup = _entitiesData[viewId]; | ||||
|       Map viewGroupStructure = {}; | ||||
|       debugPrint("Gethering views"); | ||||
|       if (viewGroup != null) { | ||||
|         viewGroupStructure["standalone"] = []; | ||||
|         viewGroupStructure["groups"] = []; | ||||
|   | ||||
| @@ -7,10 +7,13 @@ import 'package:shared_preferences/shared_preferences.dart'; | ||||
| import 'package:web_socket_channel/io.dart'; | ||||
| import 'package:web_socket_channel/status.dart' as socketStatus; | ||||
| import 'package:progress_indicators/progress_indicators.dart'; | ||||
| import 'package:event_bus/event_bus.dart'; | ||||
|  | ||||
| part 'settings.dart'; | ||||
| part 'data_model.dart'; | ||||
|  | ||||
| EventBus eventBus = new EventBus(); | ||||
|  | ||||
| void main() => runApp(new HassClientApp()); | ||||
|  | ||||
| class HassClientApp extends StatelessWidget { | ||||
| @@ -71,6 +74,12 @@ class _MainPageState extends State<MainPage> { | ||||
|     String _hassioPassword = prefs.getString('hassio-password'); | ||||
|     _dataModel = HassioDataModel(_hassioAPIEndpoint, _hassioPassword); | ||||
|     await _refreshData(); | ||||
|     eventBus.on<StateChangedEvent>().listen((event) { | ||||
|       debugPrint("State change event for ${event.entityId}"); | ||||
|       setState(() { | ||||
|         _entitiesData = _dataModel.entities; | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   _refreshData() async { | ||||
|   | ||||
| @@ -71,6 +71,13 @@ packages: | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "0.1.2" | ||||
|   event_bus: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: event_bus | ||||
|       url: "https://pub.dartlang.org" | ||||
|     source: hosted | ||||
|     version: "1.0.1" | ||||
|   flutter: | ||||
|     dependency: "direct main" | ||||
|     description: flutter | ||||
|   | ||||
| @@ -17,6 +17,7 @@ dependencies: | ||||
|     sdk: flutter | ||||
|   shared_preferences: any | ||||
|   progress_indicators: ^0.1.2 | ||||
|   event_bus: ^1.0.1 | ||||
|  | ||||
|   # The following adds the Cupertino Icons font to your application. | ||||
|   # Use with the CupertinoIcons class for iOS style icons. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user