From cacd9f856fb32bd41cb69318f46f8a887221d62f Mon Sep 17 00:00:00 2001 From: Philip Abbey Date: Wed, 20 Mar 2024 23:33:13 +0000 Subject: [PATCH] Initial solution --- README.md | 4 ++- resources/settings/properties.xml | 48 +++++++++++++++++++------------ resources/settings/settings.xml | 7 +++++ resources/strings/strings.xml | 1 + source/HomeAssistantApp.mc | 31 +++++++++++++------- source/Settings.mc | 13 +++++++++ 6 files changed, 74 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 28a8652..f539b53 100644 --- a/README.md +++ b/README.md @@ -240,7 +240,9 @@ You may choose to cache your menu definition on your device in order to reduce t The application uses vibration to confirm the action has been requested, as opposed to the 'toast' appears to show the action has been successfully executed. This is enabled by default but may be turned off if you do not desire this behaviour. -The application timeout prevents the app running on your watch when you have forgotten to close it. It prevents the refreshing of the menu statuses and therefore excessive wear on your battery level. There is a second timeout value for confirmation views. This is intended for use with more sensitive toggles so that the confirmation view is not left open and forgotten and then confirmed accidentally without you noticing. **We cannot advise you this is safe, be careful what you toggle with the watch application!** +The application timeout prevents the HomeAssistant App running on your watch when you have forgotten to close it. It prevents the refreshing of the menu statuses and therefore excessive wear on your battery level. For those users who prefer to keep the application open all the time for continuous use, they can reduce the battery wear by increasing the "poll delay". This inserts a user configurable number of milliseconds between each item's update check, hence reducing the API access activity. This also reduces the responsive of the statuses displayed when HA devices are switched externally, i.e. by another Home Assistant client, then the watch menu display will not update as quickly. Therefore if you only use the HomeAssistant App briefly now and then, keep this setting at the default 0 seconds. NB. There's a minimum of 50 ms in ConnectIQ timers, so anything less and the value here is forced to 0 ms which turns this feature off completely. + +There is a second timeout value for confirmation views. This is intended for use with more sensitive toggles so that the confirmation view is not left open and forgotten and then confirmed accidentally without you noticing. **We cannot advise you this is safe, be careful what you toggle with the watch application!** There is a toggle setting for "text alignment" that provides finer adjustment for right-to-left languages. Perhaps this could be made automatic based on device language? diff --git a/resources/settings/properties.xml b/resources/settings/properties.xml index 24561d2..fdb6637 100644 --- a/resources/settings/properties.xml +++ b/resources/settings/properties.xml @@ -22,37 +22,47 @@ - + false false true 0 + 0 + + 3 @@ -62,7 +72,8 @@ 1 false @@ -73,11 +84,10 @@ 15 diff --git a/resources/settings/settings.xml b/resources/settings/settings.xml index 85f5d09..3bccb0d 100644 --- a/resources/settings/settings.xml +++ b/resources/settings/settings.xml @@ -65,6 +65,13 @@ + + + + Should the application clear the existing cache next time it is started? Should the application provide feedback via vibrations? Timeout in seconds. Exit the application after this period of inactivity to save the device battery. + Additional poll delay (in milliseconds). Adds a delay between the status update of menu items. After this time (in seconds), a confirmation dialog for an action is automatically closed and the action is cancelled. Set to 0 to disable the timeout. Left (off) or Right (on) Menu Alignment. Left to right diff --git a/source/HomeAssistantApp.mc b/source/HomeAssistantApp.mc index bae504b..983df25 100644 --- a/source/HomeAssistantApp.mc +++ b/source/HomeAssistantApp.mc @@ -31,7 +31,8 @@ class HomeAssistantApp extends Application.AppBase { private var mMenuStatus as Lang.String or Null; private var mHaMenu as HomeAssistantView or Null; private var mQuitTimer as QuitTimer or Null; - private var mTimer as Timer.Timer or Null; + private var mGlanceTimer as Timer.Timer or Null; + private var mUpdateTimer as Timer.Timer or Null; // Array initialised by onReturnFetchMenuConfig() private var mItemsToUpdate as Lang.Array or Null; private var mNextItemToUpdate as Lang.Number = 0; // Index into the above array @@ -87,11 +88,11 @@ class HomeAssistantApp extends Application.AppBase { // Return the initial view of your application here function getInitialView() as Lang.Array? { - mIsApp = true; - mQuitTimer = new QuitTimer(); - // RezStrings.update(); - mApiStatus = WatchUi.loadResource($.Rez.Strings.Checking) as Lang.String; - mMenuStatus = WatchUi.loadResource($.Rez.Strings.Checking) as Lang.String; + mIsApp = true; + mQuitTimer = new QuitTimer(); + mUpdateTimer = new Timer.Timer(); + mApiStatus = WatchUi.loadResource($.Rez.Strings.Checking) as Lang.String; + mMenuStatus = WatchUi.loadResource($.Rez.Strings.Checking) as Lang.String; Settings.update(); if (Settings.getApiKey().length() == 0) { @@ -393,15 +394,24 @@ class HomeAssistantApp extends Application.AppBase { WatchUi.pushView(mHaMenu, new HomeAssistantViewDelegate(true), WatchUi.SLIDE_IMMEDIATE); } + function updateNextMenuItem() as Void { + var delay = Settings.getPollDelay(); + if (delay >= 50) { // Minimum 50 ms delay for Timers + mUpdateTimer.start(method(:updateNextMenuItemInt), delay, false); + } else { + updateNextMenuItemInt(); + } + } + // We need to spread out the API calls so as not to overload the results queue and cause Communications.BLE_QUEUE_FULL // (-101) error. This function is called by a timer every Globals.menuItemUpdateInterval ms. - function updateNextMenuItem() as Void { + function updateNextMenuItemInt() as Void { var itu = mItemsToUpdate as Lang.Array; if (itu != null) { itu[mNextItemToUpdate].getState(); mNextItemToUpdate = (mNextItemToUpdate + 1) % itu.size(); // } else { - // System.println("HomeAssistantApp updateNextMenuItem(): No menu items to update"); + // System.println("HomeAssistantApp updateNextMenuItemInt(): No menu items to update"); } } @@ -415,13 +425,14 @@ class HomeAssistantApp extends Application.AppBase { mMenuStatus = WatchUi.loadResource($.Rez.Strings.Checking) as Lang.String; updateStatus(); Settings.update(); - mTimer = new Timer.Timer(); - mTimer.start(method(:updateStatus), Globals.scApiBackoff, true); + mGlanceTimer = new Timer.Timer(); + mGlanceTimer.start(method(:updateStatus), Globals.scApiBackoff, true); return [new HomeAssistantGlanceView(self)]; } // Required for the Glance update timer. function updateStatus() as Void { + mGlanceTimer = null; fetchMenuConfig(); fetchApiStatus(); } diff --git a/source/Settings.mc b/source/Settings.mc index 7b616ce..b354fdd 100644 --- a/source/Settings.mc +++ b/source/Settings.mc @@ -36,6 +36,7 @@ class Settings { private static var mClearCache as Lang.Boolean = false; private static var mVibrate as Lang.Boolean = false; private static var mAppTimeout as Lang.Number = 0; // seconds + private static var mPollDelay as Lang.Number = 0; // milliseconds private static var mConfirmTimeout as Lang.Number = 3; // seconds private static var mMenuAlignment as Lang.Number = WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_LEFT; private static var mIsBatteryLevelEnabled as Lang.Boolean = false; @@ -56,11 +57,18 @@ class Settings { mClearCache = Properties.getValue("clear_cache"); mVibrate = Properties.getValue("enable_vibration"); mAppTimeout = Properties.getValue("app_timeout"); + mPollDelay = Properties.getValue("poll_delay"); mConfirmTimeout = Properties.getValue("confirm_timeout"); mMenuAlignment = Properties.getValue("menu_alignment"); mIsBatteryLevelEnabled = Properties.getValue("enable_battery_level"); mBatteryRefreshRate = Properties.getValue("battery_level_refresh_rate"); + // There's a minimum of 50 ms on Timer.Timers, so reset to 0 if too small. + if (mPollDelay < 50) { // milliseconds + mPollDelay = 0; + Properties.setValue("poll_delay", mPollDelay); + } + if (System has :ServiceDelegate) { mHasService = true; } @@ -138,6 +146,10 @@ class Settings { return mAppTimeout * 1000; // Convert to milliseconds } + static function getPollDelay() as Lang.Number { + return mPollDelay; + } + static function getConfirmTimeout() as Lang.Number { return mConfirmTimeout * 1000; // Convert to milliseconds } @@ -153,4 +165,5 @@ class Settings { Background.deleteTemporalEvent(); } } + }