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