Compare commits

...

4 Commits
0.2.3 ... 0.2.4

Author SHA1 Message Date
e0d35d07dc Version 0.2.4 2018-10-03 14:37:54 +03:00
285447a5b7 Resolves #114 Error going back from settings 2018-10-03 14:36:23 +03:00
ed3e4ba272 COnnection closing improvements 2018-10-03 10:35:40 +03:00
908563063a Fix input_boolean control 2018-10-03 09:50:14 +03:00
5 changed files with 138 additions and 65 deletions

View File

@ -106,7 +106,7 @@ class EntityWidget extends StatefulWidget {
_EntityWidgetState createState() { _EntityWidgetState createState() {
switch (entity.domain) { switch (entity.domain) {
case "automation": case "automation":
case "input_boolean ": case "input_boolean":
case "switch": case "switch":
case "light": { case "light": {
return _SwitchEntityWidgetState(); return _SwitchEntityWidgetState();

View File

@ -25,9 +25,11 @@ class HomeAssistant {
Timer _connectionTimer; Timer _connectionTimer;
Timer _fetchTimer; Timer _fetchTimer;
StreamSubscription _socketSubscription;
int messageExpirationTime = 50; //seconds int messageExpirationTime = 50; //seconds
Duration fetchTimeout = Duration(seconds: 30); Duration fetchTimeout = Duration(seconds: 45);
Duration connectTimeout = Duration(seconds: 10); Duration connectTimeout = Duration(seconds: 15);
String get locationName => _instanceConfig["location_name"] ?? ""; String get locationName => _instanceConfig["location_name"] ?? "";
int get viewsCount => _entities.viewList.length ?? 0; int get viewsCount => _entities.viewList.length ?? 0;
@ -35,15 +37,18 @@ class HomeAssistant {
EntityCollection get entities => _entities; EntityCollection get entities => _entities;
HomeAssistant(String url, String password, String authType) { HomeAssistant() {
_hassioAPIEndpoint = url;
_hassioPassword = password;
_hassioAuthType = authType;
_entities = EntityCollection(); _entities = EntityCollection();
_uiBuilder = UIBuilder(); _uiBuilder = UIBuilder();
_messageQueue = SendMessageQueue(messageExpirationTime); _messageQueue = SendMessageQueue(messageExpirationTime);
} }
void updateConnectionSettings(String url, String password, String authType) {
_hassioAPIEndpoint = url;
_hassioPassword = password;
_hassioAuthType = authType;
}
Future fetch() { Future fetch() {
if ((_fetchCompleter != null) && (!_fetchCompleter.isCompleted)) { if ((_fetchCompleter != null) && (!_fetchCompleter.isCompleted)) {
TheLogger.log("Warning","Previous fetch is not complited"); TheLogger.log("Warning","Previous fetch is not complited");
@ -51,6 +56,7 @@ class HomeAssistant {
_fetchCompleter = new Completer(); _fetchCompleter = new Completer();
_fetchTimer = Timer(fetchTimeout, () { _fetchTimer = Timer(fetchTimeout, () {
closeConnection(); closeConnection();
TheLogger.log("Error", "Data fetching timeout");
_finishFetching({"errorCode" : 9,"errorMessage": "Couldn't get data from server"}); _finishFetching({"errorCode" : 9,"errorMessage": "Couldn't get data from server"});
}); });
_connection().then((r) { _connection().then((r) {
@ -63,10 +69,15 @@ class HomeAssistant {
} }
closeConnection() { closeConnection() {
if (_hassioChannel?.closeCode == null) { if (_socketSubscription != null) {
_hassioChannel?.sink?.close(); _socketSubscription.cancel();
}
if (_hassioChannel != null) {
if (_hassioChannel.closeCode == null) {
_hassioChannel.sink?.close();
}
_hassioChannel = null;
} }
_hassioChannel = null;
} }
Future _connection() { Future _connection() {
@ -74,10 +85,12 @@ class HomeAssistant {
TheLogger.log("Debug","Previous connection is not complited"); TheLogger.log("Debug","Previous connection is not complited");
} else { } else {
if ((_hassioChannel == null) || (_hassioChannel.sink == null) || (_hassioChannel.closeCode != null)) { if ((_hassioChannel == null) || (_hassioChannel.sink == null) || (_hassioChannel.closeCode != null)) {
closeConnection();
TheLogger.log("Debug", "Socket connecting..."); TheLogger.log("Debug", "Socket connecting...");
_connectionCompleter = new Completer(); _connectionCompleter = new Completer();
_connectionTimer = Timer(connectTimeout, () { _connectionTimer = Timer(connectTimeout, () {
closeConnection(); closeConnection();
TheLogger.log("Error", "Socket connection timeout");
_finishConnecting({"errorCode" : 1,"errorMessage": "Couldn't connect to Home Assistant. Looks like a network issues"}); _finishConnecting({"errorCode" : 1,"errorMessage": "Couldn't connect to Home Assistant. Looks like a network issues"});
}); });
_hassioChannel = IOWebSocketChannel.connect( _hassioChannel = IOWebSocketChannel.connect(
@ -85,7 +98,8 @@ class HomeAssistant {
_hassioChannel.stream.handleError((e) { _hassioChannel.stream.handleError((e) {
TheLogger.log("Error", "Unhandled socket error: ${e.toString()}"); TheLogger.log("Error", "Unhandled socket error: ${e.toString()}");
}); });
_hassioChannel.stream.listen((message) => if (_socketSubscription != null) _socketSubscription.cancel();
_socketSubscription = _hassioChannel.stream.listen((message) =>
_handleMessage(_connectionCompleter, message)); _handleMessage(_connectionCompleter, message));
_hassioChannel.sink.done.whenComplete(() { _hassioChannel.sink.done.whenComplete(() {
TheLogger.log("Debug","Socket sink finished. Assuming it is closed."); TheLogger.log("Debug","Socket sink finished. Assuming it is closed.");

View File

@ -34,7 +34,7 @@ part 'badge_class.dart';
EventBus eventBus = new EventBus(); EventBus eventBus = new EventBus();
const String appName = "HA Client"; const String appName = "HA Client";
const appVersion = "0.2.3"; const appVersion = "0.2.4";
String homeAssistantWebHost; String homeAssistantWebHost;
@ -88,6 +88,9 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
HomeAssistant _homeAssistant; HomeAssistant _homeAssistant;
EntityCollection _entities; EntityCollection _entities;
//Map _instanceConfig; //Map _instanceConfig;
String _apiEndpoint;
String _apiPassword;
String _authType;
int _uiViewsCount = 0; int _uiViewsCount = 0;
String _instanceHost; String _instanceHost;
int _errorCodeToBeShown = 0; int _errorCodeToBeShown = 0;
@ -107,14 +110,35 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
_homeAssistant = HomeAssistant();
_settingsSubscription = eventBus.on<SettingsChangedEvent>().listen((event) { _settingsSubscription = eventBus.on<SettingsChangedEvent>().listen((event) {
TheLogger.log("Debug","Settings change event: reconnect=${event.reconnect}"); TheLogger.log("Debug","Settings change event: reconnect=${event.reconnect}");
setState(() { if (event.reconnect) {
_errorCodeToBeShown = 0; _homeAssistant.closeConnection();
}); _initConnection().then((b){
_initConnection(); setState(() {
_homeAssistant.updateConnectionSettings(_apiEndpoint, _apiPassword, _authType);
_errorCodeToBeShown = 10;
_lastErrorMessage = "Connection settings was changed.";
});
}, onError: (_) {
setState(() {
_lastErrorMessage = _;
_errorCodeToBeShown = 5;
});
});
}
});
_initConnection().then((_){
_createConnection();
}, onError: (_) {
setState(() {
_lastErrorMessage = _;
_errorCodeToBeShown = 5;
});
}); });
_initConnection();
} }
@override @override
@ -130,62 +154,62 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
String domain = prefs.getString('hassio-domain'); String domain = prefs.getString('hassio-domain');
String port = prefs.getString('hassio-port'); String port = prefs.getString('hassio-port');
_instanceHost = "$domain:$port"; _instanceHost = "$domain:$port";
String apiEndpoint = "${prefs.getString('hassio-protocol')}://$domain:$port/api/websocket"; _apiEndpoint = "${prefs.getString('hassio-protocol')}://$domain:$port/api/websocket";
homeAssistantWebHost = "${prefs.getString('hassio-res-protocol')}://$domain:$port"; homeAssistantWebHost = "${prefs.getString('hassio-res-protocol')}://$domain:$port";
String apiPassword = prefs.getString('hassio-password'); _apiPassword = prefs.getString('hassio-password');
String authType = prefs.getString('hassio-auth-type'); _authType = prefs.getString('hassio-auth-type');
if ((domain == null) || (port == null) || (apiPassword == null) || if ((domain == null) || (port == null) || (_apiPassword == null) ||
(domain.length == 0) || (port.length == 0) || (apiPassword.length == 0)) { (domain.length == 0) || (port.length == 0) || (_apiPassword.length == 0)) {
setState(() { throw("Check connection settings");
_errorCodeToBeShown = 5;
});
} else {
if (_homeAssistant != null) _homeAssistant.closeConnection();
_createConnection(apiEndpoint, apiPassword, authType);
} }
} }
_createConnection(String apiEndpoint, String apiPassword, String authType) { _createConnection() {
_homeAssistant = HomeAssistant(apiEndpoint, apiPassword, authType);
_refreshData(); _refreshData();
if (_stateSubscription != null) _stateSubscription.cancel(); if (_stateSubscription == null) {
_stateSubscription = eventBus.on<StateChangedEvent>().listen((event) { _stateSubscription = eventBus.on<StateChangedEvent>().listen((event) {
setState(() { setState(() {
if (event.localChange) { if (event.localChange) {
_entities _entities
.get(event.entityId) .get(event.entityId)
.state = event.newState; .state = event.newState;
} }
});
}); });
}); }
if (_serviceCallSubscription != null) _serviceCallSubscription.cancel(); if (_serviceCallSubscription == null) {
_serviceCallSubscription = eventBus.on<ServiceCallEvent>().listen((event) { _serviceCallSubscription =
_callService(event.domain, event.service, event.entityId, event.additionalParams); eventBus.on<ServiceCallEvent>().listen((event) {
}); _callService(event.domain, event.service, event.entityId,
event.additionalParams);
});
}
if (_showEntityPageSubscription != null) _showEntityPageSubscription.cancel(); if (_showEntityPageSubscription == null) {
_showEntityPageSubscription = eventBus.on<ShowEntityPageEvent>().listen((event) { _showEntityPageSubscription =
_showEntityPage(event.entity); eventBus.on<ShowEntityPageEvent>().listen((event) {
}); _showEntityPage(event.entity);
});
}
} }
_refreshData() async { _refreshData() async {
_homeAssistant.updateConnectionSettings(_apiEndpoint, _apiPassword, _authType);
setState(() { setState(() {
_isLoading = true; _isLoading = true;
}); });
_errorCodeToBeShown = 0; _errorCodeToBeShown = 0;
if (_homeAssistant != null) { _lastErrorMessage = "";
await _homeAssistant.fetch().then((result) { await _homeAssistant.fetch().then((result) {
setState(() { setState(() {
//_instanceConfig = _homeAssistant.instanceConfig; //_instanceConfig = _homeAssistant.instanceConfig;
_entities = _homeAssistant.entities; _entities = _homeAssistant.entities;
_uiViewsCount = _homeAssistant.viewsCount; _uiViewsCount = _homeAssistant.viewsCount;
_isLoading = false; _isLoading = false;
});
}).catchError((e) {
_setErrorState(e);
}); });
} }).catchError((e) {
_setErrorState(e);
});
} }
_setErrorState(e) { _setErrorState(e) {
@ -483,6 +507,25 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
HAUtils.launchURL("https://github.com/estevez-dev/ha_client_pub/issues/new"); HAUtils.launchURL("https://github.com/estevez-dev/ha_client_pub/issues/new");
}, },
), ),
Container(
height: 30.0,
decoration: new BoxDecoration(
border: new Border(
top: BorderSide(
width: 2.0,
color: Colors.black26,
)
),
)
),
new ListTile(
leading: Icon(MaterialDesignIcons.createIconDataFromIconName("mdi:coffee")),
title: Text("By me a coffee"),
onTap: () {
Navigator.of(context).pop();
HAUtils.launchURL("https://www.buymeacoffee.com/estevez");
},
),
new AboutListTile( new AboutListTile(
applicationName: appName, applicationName: appName,
applicationVersion: appVersion, applicationVersion: appVersion,
@ -499,6 +542,8 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
SnackBarAction action; SnackBarAction action;
switch (_errorCodeToBeShown) { switch (_errorCodeToBeShown) {
case 9: case 9:
case 11:
case 7:
case 1: { case 1: {
action = SnackBarAction( action = SnackBarAction(
label: "Retry", label: "Retry",
@ -533,9 +578,9 @@ class _MainPageState extends State<MainPage> with WidgetsBindingObserver {
break; break;
} }
case 7: { case 10: {
action = SnackBarAction( action = SnackBarAction(
label: "Retry", label: "Refresh",
onPressed: () { onPressed: () {
_scaffoldKey?.currentState?.hideCurrentSnackBar(); _scaffoldKey?.currentState?.hideCurrentSnackBar();
_refreshData(); _refreshData();

View File

@ -15,6 +15,7 @@ class _ConnectionSettingsPageState extends State<ConnectionSettingsPage> {
String _hassioPassword = ""; String _hassioPassword = "";
String _socketProtocol = "wss"; String _socketProtocol = "wss";
String _authType = "access_token"; String _authType = "access_token";
bool _connectionSettingsChanged = false;
@override @override
void initState() { void initState() {
@ -45,6 +46,7 @@ class _ConnectionSettingsPageState extends State<ConnectionSettingsPage> {
prefs.setString("hassio-protocol", _socketProtocol); prefs.setString("hassio-protocol", _socketProtocol);
prefs.setString("hassio-res-protocol", _socketProtocol == "wss" ? "https" : "http"); prefs.setString("hassio-res-protocol", _socketProtocol == "wss" ? "https" : "http");
prefs.setString("hassio-auth-type", _authType); prefs.setString("hassio-auth-type", _authType);
_connectionSettingsChanged = true;
} }
@override @override
@ -52,12 +54,24 @@ class _ConnectionSettingsPageState extends State<ConnectionSettingsPage> {
return new Scaffold( return new Scaffold(
appBar: new AppBar( appBar: new AppBar(
leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: (){ leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: (){
_saveSettings().then((r){ Navigator.pop(context);
Navigator.pop(context);
});
eventBus.fire(SettingsChangedEvent(true));
}), }),
title: new Text(widget.title), title: new Text(widget.title),
actions: <Widget>[
IconButton(
icon: Icon(Icons.check),
onPressed:(){
if (_connectionSettingsChanged) {
_saveSettings().then((r){
Navigator.pop(context);
eventBus.fire(SettingsChangedEvent(_connectionSettingsChanged));
});
} else {
Navigator.pop(context);
}
}
)
],
), ),
body: ListView( body: ListView(
padding: const EdgeInsets.all(20.0), padding: const EdgeInsets.all(20.0),

View File

@ -1,7 +1,7 @@
name: hass_client name: hass_client
description: Home Assistant Android Client description: Home Assistant Android Client
version: 0.2.3+25 version: 0.2.4+26
environment: environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0" sdk: ">=2.0.0-dev.68.0 <3.0.0"