diff --git a/lib/data_model.dart b/lib/data_model.dart index ca166d0..c46505f 100644 --- a/lib/data_model.dart +++ b/lib/data_model.dart @@ -46,7 +46,7 @@ class HassioDataModel { Future fetch() { if ((_fetchCompleter != null) && (!_fetchCompleter.isCompleted)) { - debugPrint("Previous fetch is not complited"); + TheLogger.log("Warning","Previous fetch is not complited"); } else { //TODO: Fetch timeout timer. Should be removed after #21 fix _fetchingTimer = Timer(Duration(seconds: 15), () { @@ -73,10 +73,10 @@ class HassioDataModel { Future _reConnectSocket() { var _connectionCompleter = new Completer(); if ((_hassioChannel == null) || (_hassioChannel.closeCode != null)) { - debugPrint("Socket connecting..."); + TheLogger.log("Debug","Socket connecting..."); _hassioChannel = IOWebSocketChannel.connect(_hassioAPIEndpoint); _hassioChannel.stream.handleError((e) { - debugPrint("Unhandled socket error: ${e.toString()}"); + TheLogger.log("Error","Unhandled socket error: ${e.toString()}"); }); _hassioChannel.stream.listen((message) => _handleMessage(_connectionCompleter, message)); @@ -113,7 +113,7 @@ class HassioDataModel { _handleMessage(Completer connectionCompleter, String message) { var data = json.decode(message); - debugPrint("[Received]Message type: ${data['type']}"); + TheLogger.log("Debug","[Received] => Message type: ${data['type']}"); if (data["type"] == "auth_required") { _sendMessageRaw('{"type": "auth","$_hassioAuthType": "$_hassioPassword"}'); } else if (data["type"] == "auth_ok") { @@ -129,22 +129,18 @@ class HassioDataModel { } else if (data["id"] == _servicesMessageId) { _parseServices(data); } else if (data["id"] == _currentMessageId) { - debugPrint("Request id:$_currentMessageId was successful"); - } else { - debugPrint("Skipped message due to messageId:"); - debugPrint(message); + TheLogger.log("Debug","Request id:$_currentMessageId was successful"); } } 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"]}"); + TheLogger.log("Warning","Unhandled event type: ${data["event"]["event_type"]}"); } else { - debugPrint("Event is null"); + TheLogger.log("Error","Event is null: $message"); } } else { - debugPrint("Unknown message type"); - debugPrint(message); + TheLogger.log("Warning","Unknown message type: $message"); } } @@ -185,20 +181,29 @@ class HassioDataModel { _currentMessageId += 1; } - _sendMessageRaw(message) { - debugPrint("[Sent]$message"); + _sendMessageRaw(String message) { + if (message.indexOf('"type": "auth"') > 0) { + TheLogger.log("Debug", "[Sending] ==> auth request"); + } else { + TheLogger.log("Debug", "[Sending] ==> $message"); + } _hassioChannel.sink.add(message); } void _handleEntityStateChange(Map eventData) { - var parsedEntityData = _parseEntity(eventData["new_state"]); - String entityId = parsedEntityData["entity_id"]; - if (_entitiesData[entityId] == null) { - _entitiesData[entityId] = parsedEntityData; + TheLogger.log("Debug", "Parsing new state for ${eventData['entity_id']}"); + if (eventData["new_state"] == null) { + TheLogger.log("Error", "No new_state found"); } else { - _entitiesData[entityId].addAll(parsedEntityData); + var parsedEntityData = _parseEntity(eventData["new_state"]); + String entityId = parsedEntityData["entity_id"]; + if (_entitiesData[entityId] == null) { + _entitiesData[entityId] = parsedEntityData; + } else { + _entitiesData[entityId].addAll(parsedEntityData); + } + eventBus.fire(new StateChangedEvent(eventData["entity_id"])); } - eventBus.fire(new StateChangedEvent(eventData["entity_id"])); } void _parseConfig(Map data) { @@ -218,7 +223,7 @@ class HassioDataModel { try { Map data = response["result"]; Map result = {}; - debugPrint("Parsing ${data.length} Home Assistant service domains"); + TheLogger.log("Debug","Parsing ${data.length} Home Assistant service domains"); data.forEach((domain, services) { result[domain] = Map.from(services); services.forEach((serviceName, serviceData) { @@ -231,7 +236,7 @@ class HassioDataModel { _servicesCompleter.complete(); } catch (e) { //TODO hadle it properly - debugPrint("Error parsing services"); + TheLogger.log("Error","Error parsing services. But they are not used :-)"); _servicesCompleter.complete(); } } @@ -244,7 +249,7 @@ class HassioDataModel { return; } List data = response["result"]; - debugPrint("Parsing ${data.length} Home Assistant entities"); + TheLogger.log("Debug","Parsing ${data.length} Home Assistant entities"); List uiGroups = []; data.forEach((entity) { try { @@ -258,13 +263,12 @@ class HassioDataModel { } _entitiesData[entity["entity_id"]] = composedEntity; } catch (error) { - debugPrint("Error parsing entity: ${entity['entity_id']}"); - debugPrint("$error"); + TheLogger.log("Error","Error parsing entity: ${entity['entity_id']}"); } }); //Gethering information for UI - debugPrint("Gethering views"); + TheLogger.log("Debug","Gethering views"); int viewCounter = 0; uiGroups.forEach((viewId) { //Each view try { @@ -320,7 +324,7 @@ class HassioDataModel { } _uiStructure[viewId.split(".")[1]] = viewGroupStructure; } catch (error) { - debugPrint("Error parsing view: $viewId"); + TheLogger.log("Error","Error parsing view: $viewId"); } }); _statesCompleter.complete(); diff --git a/lib/logPage.dart b/lib/logPage.dart new file mode 100644 index 0000000..9bf7fd2 --- /dev/null +++ b/lib/logPage.dart @@ -0,0 +1,49 @@ +part of 'main.dart'; + +class LogViewPage extends StatefulWidget { + LogViewPage({Key key, this.title}) : super(key: key); + + final String title; + + @override + _LogViewPageState createState() => new _LogViewPageState(); +} + +class _LogViewPageState extends State { + String _hassioDomain = ""; + String _hassioPort = "8123"; + String _hassioPassword = ""; + String _socketProtocol = "wss"; + String _authType = "access_token"; + + @override + void initState() { + super.initState(); + _loadLog(); + } + + _loadLog() async { + // + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: (){ + Navigator.pop(context); + }), + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: new Text(widget.title), + ), + body: TextField( + maxLines: null, + + controller: TextEditingController( + text: TheLogger.getLog() + ), + ) + ); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 0ec374a..057636e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,8 +9,9 @@ import 'package:event_bus/event_bus.dart'; import 'package:flutter/widgets.dart'; import 'package:cached_network_image/cached_network_image.dart'; -part 'settings.dart'; +part 'settingsPage.dart'; part 'data_model.dart'; +part 'logPage.dart'; EventBus eventBus = new EventBus(); const String appName = "HA Client"; @@ -18,6 +19,36 @@ const appVersion = "0.1.0-alpha"; String homeAssistantWebHost; +class TheLogger { + + static List _log = []; + + static String getLog() { + String res = ''; + _log.forEach((line) { + res += "$line\n\n"; + }); + return res; + } + + static bool get isInDebugMode { + bool inDebugMode = false; + + assert(inDebugMode = true); + + return inDebugMode; + } + + static void log(String level, String message) { + debugPrint('$message'); + _log.add("[$level] : $message"); + if (_log.length > 50) { + _log.removeAt(0); + } + } + +} + void main() => runApp(new HassClientApp()); class HassClientApp extends StatelessWidget { @@ -32,7 +63,8 @@ class HassClientApp extends StatelessWidget { initialRoute: "/", routes: { "/": (context) => MainPage(title: 'Hass Client'), - "/connection-settings": (context) => ConnectionSettingsPage(title: "Connection Settings") + "/connection-settings": (context) => ConnectionSettingsPage(title: "Connection Settings"), + "/log-view": (context) => LogViewPage(title: "Log") }, ); } @@ -76,7 +108,7 @@ class _MainPageState extends State with WidgetsBindingObserver { super.initState(); WidgetsBinding.instance.addObserver(this); _settingsSubscription = eventBus.on().listen((event) { - debugPrint("Settings change event: reconnect=${event.reconnect}"); + TheLogger.log("Debug","Settings change event: reconnect=${event.reconnect}"); setState(() { _errorCodeToBeShown = 0; }); @@ -87,7 +119,7 @@ class _MainPageState extends State with WidgetsBindingObserver { @override void didChangeAppLifecycleState(AppLifecycleState state) { - debugPrint("$state"); + TheLogger.log("Debug","$state"); if (state == AppLifecycleState.resumed) { _refreshData(); } @@ -118,7 +150,6 @@ class _MainPageState extends State with WidgetsBindingObserver { _refreshData(); if (_stateSubscription != null) _stateSubscription.cancel(); _stateSubscription = eventBus.on().listen((event) { - debugPrint("State change event for ${event.entityId}"); setState(() { _entitiesData = _dataModel.entities; }); @@ -212,11 +243,9 @@ class _MainPageState extends State with WidgetsBindingObserver { List result = []; ids.forEach((entityId) { var data = _entitiesData[entityId]; - if (data == null) { - debugPrint("Hiding unknown entity from badges: $entityId"); - } else { + if (data != null) { result.add( - _buildSingleBadge(data) + _buildSingleBadge(data) ); } }); @@ -363,9 +392,7 @@ class _MainPageState extends State with WidgetsBindingObserver { List entities = []; ids.forEach((id) { var data = _entitiesData[id]; - if (data == null) { - debugPrint("Hiding unknown entity from card: $id"); - } else { + if (data != null) { entities.add(new ListTile( leading: MaterialDesignIcons.createIconFromEntityData(data, 28.0, _stateIconColors[data["state"]] ?? Colors.blueGrey), //subtitle: Text("${data['entity_id']}"), @@ -487,6 +514,13 @@ class _MainPageState extends State with WidgetsBindingObserver { Navigator.pushNamed(context, '/connection-settings'); }, ), + new ListTile( + leading: Icon(Icons.insert_drive_file), + title: Text("Log"), + onTap: () { + Navigator.pushNamed(context, '/log-view'); + }, + ), new AboutListTile( applicationName: appName, applicationVersion: appVersion, diff --git a/lib/settings.dart b/lib/settingsPage.dart similarity index 100% rename from lib/settings.dart rename to lib/settingsPage.dart