[#19] Implement Home Assistant state events listener
This commit is contained in:
parent
1b7a081ae5
commit
bf6559c990
@ -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