mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2025-06-15 19:08:40 +00:00
Initial solution
This commit is contained in:
@ -24,6 +24,12 @@
|
||||
<!-- Best be a public URL in order to work away from your home LAN and have a trusted HTTPS certificate -->
|
||||
<property id="config_url" type="string"></property>
|
||||
|
||||
<!-- Decide if the menu configuration should be cached. -->
|
||||
<property id="cache_config" type="boolean">false</property>
|
||||
|
||||
<!-- Clear the menu configuration on next application start, and refetch, then set this back to false -->
|
||||
<property id="clear_cache" type="boolean">false</property>
|
||||
|
||||
<!--
|
||||
Application timeout in seconds, except 0 for no timeout (default). After this amount of elapsed time
|
||||
with no activity, exit the application.
|
||||
|
@ -37,6 +37,20 @@
|
||||
<settingConfig type="alphaNumeric" />
|
||||
</setting>
|
||||
|
||||
<setting
|
||||
propertyKey="@Properties.cache_config"
|
||||
title="@Strings.SettingsCacheConfig"
|
||||
>
|
||||
<settingConfig type="boolean" />
|
||||
</setting>
|
||||
|
||||
<setting
|
||||
propertyKey="@Properties.clear_cache"
|
||||
title="@Strings.SettingsClearCache"
|
||||
>
|
||||
<settingConfig type="boolean" />
|
||||
</setting>
|
||||
|
||||
<setting
|
||||
propertyKey="@Properties.app_timeout"
|
||||
title="@Strings.SettingsAppTimeout"
|
||||
|
@ -35,6 +35,7 @@
|
||||
<string id="Checking" scope="glance">Checking...</string>
|
||||
<string id="Unavailable" scope="glance">Unavailable</string>
|
||||
<string id="Unconfigured" scope="glance">Unconfigured</string>
|
||||
<string id="Cached" scope="glance">Cached</string>
|
||||
<string id="GlanceMenu" scope="glance">Menu</string>
|
||||
|
||||
<!-- For the settings GUI -->
|
||||
@ -43,6 +44,8 @@
|
||||
<string id="SettingsApiKeyPrompt">Long-Lived Access Token.</string>
|
||||
<string id="SettingsApiUrl">URL for HomeAssistant API.</string>
|
||||
<string id="SettingsConfigUrl">URL for menu configuration (JSON).</string>
|
||||
<string id="SettingsCacheConfig">Should the application cache the menu configuration?</string>
|
||||
<string id="SettingsClearCache">Should the application clear the existing cache next time it is started?</string>
|
||||
<string id="SettingsAppTimeout">Timeout in seconds. Exit the application after this period of inactivity to save the device battery.</string>
|
||||
<string id="SettingsConfirmTimeout">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.</string>
|
||||
<string id="SettingsMenuItemStyle">Menu item style.</string>
|
||||
|
@ -124,12 +124,16 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
}
|
||||
return ErrorView.create(RezStrings.getNoInternet() + ".");
|
||||
} else {
|
||||
fetchMenuConfig();
|
||||
var isCached = fetchMenuConfig();
|
||||
fetchApiStatus();
|
||||
if (WidgetApp.isWidget) {
|
||||
return [new RootView(self), new RootViewDelegate(self)] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||
} else {
|
||||
return [new WatchUi.View(), new WatchUi.BehaviorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||
if (isCached) {
|
||||
return [mHaMenu, new HomeAssistantViewDelegate(true)] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||
} else {
|
||||
return [new WatchUi.View(), new WatchUi.BehaviorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -193,21 +197,11 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
|
||||
case 200:
|
||||
mMenuStatus = RezStrings.getAvailable();
|
||||
if (Settings.getCacheConfig()) {
|
||||
Storage.setValue("menu", data as Lang.Dictionary);
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
mHaMenu = new HomeAssistantView(data, null);
|
||||
mQuitTimer.begin();
|
||||
if (Settings.getIsWidgetStartNoTap()) {
|
||||
// As soon as the menu has been fetched start show the menu of items.
|
||||
// This behaviour is inconsistent with the standard Garmin User Interface, but has been
|
||||
// requested by users so has been made the non-default option.
|
||||
pushHomeAssistantMenuView();
|
||||
}
|
||||
mItemsToUpdate = mHaMenu.getItemsToUpdate();
|
||||
// Start the continuous update process that continues for as long as the application is running.
|
||||
// The chain of functions from 'updateNextMenuItem()' calls 'updateNextMenuItem()' on completion.
|
||||
if (mItemsToUpdate.size() > 0) {
|
||||
updateNextMenuItem();
|
||||
}
|
||||
buildMenu(data);
|
||||
if (!WidgetApp.isWidget) {
|
||||
WatchUi.switchToView(mHaMenu, new HomeAssistantViewDelegate(false), WatchUi.SLIDE_IMMEDIATE);
|
||||
}
|
||||
@ -226,43 +220,77 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
WatchUi.requestUpdate();
|
||||
}
|
||||
|
||||
// Return true if the menu came from the cache, otherwise false. This is because fetching the menu when not in the cache is
|
||||
// asynchronous and affects how the views are managed.
|
||||
(:glance)
|
||||
function fetchMenuConfig() as Void {
|
||||
function fetchMenuConfig() as Lang.Boolean {
|
||||
if (Settings.getConfigUrl().equals("")) {
|
||||
mMenuStatus = RezStrings.getUnconfigured();
|
||||
WatchUi.requestUpdate();
|
||||
} else {
|
||||
if (! System.getDeviceSettings().phoneConnected) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem getState(): No Phone connection, skipping API call.");
|
||||
}
|
||||
if (mIsGlance) {
|
||||
WatchUi.requestUpdate();
|
||||
} else {
|
||||
ErrorView.show(RezStrings.getNoPhone() + ".");
|
||||
}
|
||||
mMenuStatus = RezStrings.getUnavailable();
|
||||
} else if (! System.getDeviceSettings().connectionAvailable) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem getState(): No Internet connection, skipping API call.");
|
||||
}
|
||||
if (mIsGlance) {
|
||||
WatchUi.requestUpdate();
|
||||
} else {
|
||||
ErrorView.show(RezStrings.getNoInternet() + ".");
|
||||
}
|
||||
mMenuStatus = RezStrings.getUnavailable();
|
||||
} else {
|
||||
Communications.makeWebRequest(
|
||||
Settings.getConfigUrl(),
|
||||
null,
|
||||
{
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
},
|
||||
method(:onReturnFetchMenuConfig)
|
||||
);
|
||||
var menu = Storage.getValue("menu") as Lang.Dictionary;
|
||||
if (menu != null and Settings.getClearCache()) {
|
||||
Storage.deleteValue("menu");
|
||||
menu = null;
|
||||
Settings.unsetClearCache();
|
||||
}
|
||||
if (menu == null) {
|
||||
if (! System.getDeviceSettings().phoneConnected) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem getState(): No Phone connection, skipping API call.");
|
||||
}
|
||||
if (mIsGlance) {
|
||||
WatchUi.requestUpdate();
|
||||
} else {
|
||||
ErrorView.show(RezStrings.getNoPhone() + ".");
|
||||
}
|
||||
mMenuStatus = RezStrings.getUnavailable();
|
||||
} else if (! System.getDeviceSettings().connectionAvailable) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem getState(): No Internet connection, skipping API call.");
|
||||
}
|
||||
if (mIsGlance) {
|
||||
WatchUi.requestUpdate();
|
||||
} else {
|
||||
ErrorView.show(RezStrings.getNoInternet() + ".");
|
||||
}
|
||||
mMenuStatus = RezStrings.getUnavailable();
|
||||
} else {
|
||||
Communications.makeWebRequest(
|
||||
Settings.getConfigUrl(),
|
||||
null,
|
||||
{
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
},
|
||||
method(:onReturnFetchMenuConfig)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
mMenuStatus = RezStrings.getCached();
|
||||
if (!mIsGlance) {
|
||||
buildMenu(menu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function buildMenu(menu as Lang.Dictionary) {
|
||||
mHaMenu = new HomeAssistantView(menu, null);
|
||||
mQuitTimer.begin();
|
||||
if (Settings.getIsWidgetStartNoTap()) {
|
||||
// As soon as the menu has been fetched start show the menu of items.
|
||||
// This behaviour is inconsistent with the standard Garmin User Interface, but has been
|
||||
// requested by users so has been made the non-default option.
|
||||
pushHomeAssistantMenuView();
|
||||
}
|
||||
mItemsToUpdate = mHaMenu.getItemsToUpdate();
|
||||
// Start the continuous update process that continues for as long as the application is running.
|
||||
// The chain of functions from 'updateNextMenuItem()' calls 'updateNextMenuItem()' on completion.
|
||||
if (mItemsToUpdate.size() > 0) {
|
||||
updateNextMenuItem();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,6 +102,8 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
var myTimer = new Timer.Timer();
|
||||
// Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer.
|
||||
myTimer.start(getApp().method(:updateNextMenuItem), Globals.scApiBackoff, false);
|
||||
// Revert status
|
||||
status = getApp().getApiStatus();
|
||||
break;
|
||||
|
||||
case 404:
|
||||
|
@ -26,8 +26,8 @@ using Toybox.WatchUi;
|
||||
|
||||
class HomeAssistantView extends WatchUi.Menu2 {
|
||||
// List of items that need to have their status updated periodically
|
||||
private var mListToggleItems = [];
|
||||
private var mListMenuItems = [];
|
||||
private var mListToggleItems = [];
|
||||
private var mListMenuItems = [];
|
||||
|
||||
function initialize(
|
||||
definition as Lang.Dictionary,
|
||||
|
@ -55,6 +55,8 @@ class RezStrings {
|
||||
(:glance)
|
||||
private static var strUnconfigured as Lang.String or Null;
|
||||
(:glance)
|
||||
private static var strCached as Lang.String or Null;
|
||||
(:glance)
|
||||
private static var strGlanceMenu as Lang.String or Null;
|
||||
private static var strLabelToggle as Lang.Dictionary or Null;
|
||||
|
||||
@ -71,6 +73,7 @@ class RezStrings {
|
||||
strChecking = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
strUnavailable = WatchUi.loadResource($.Rez.Strings.Unavailable);
|
||||
strUnconfigured = WatchUi.loadResource($.Rez.Strings.Unconfigured);
|
||||
strCached = WatchUi.loadResource($.Rez.Strings.Cached);
|
||||
strGlanceMenu = WatchUi.loadResource($.Rez.Strings.GlanceMenu);
|
||||
}
|
||||
|
||||
@ -97,6 +100,7 @@ class RezStrings {
|
||||
strChecking = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
strUnavailable = WatchUi.loadResource($.Rez.Strings.Unavailable);
|
||||
strUnconfigured = WatchUi.loadResource($.Rez.Strings.Unconfigured);
|
||||
strCached = WatchUi.loadResource($.Rez.Strings.Cached);
|
||||
strGlanceMenu = WatchUi.loadResource($.Rez.Strings.GlanceMenu);
|
||||
strLabelToggle = {
|
||||
:enabled => WatchUi.loadResource($.Rez.Strings.MenuItemOn) as Lang.String,
|
||||
@ -184,6 +188,10 @@ class RezStrings {
|
||||
return strUnconfigured;
|
||||
}
|
||||
|
||||
static function getCached() as Lang.String {
|
||||
return strCached;
|
||||
}
|
||||
|
||||
static function getGlanceMenu() as Lang.String {
|
||||
return strGlanceMenu;
|
||||
}
|
||||
|
@ -34,6 +34,8 @@ class Settings {
|
||||
private static var mApiKey as Lang.String = "";
|
||||
private static var mApiUrl as Lang.String = "";
|
||||
private static var mConfigUrl as Lang.String = "";
|
||||
private static var mCacheConfig as Lang.Boolean = false;
|
||||
private static var mClearCache as Lang.Boolean = false;
|
||||
private static var mAppTimeout as Lang.Number = 0; // seconds
|
||||
private static var mConfirmTimeout as Lang.Number = 3; // seconds
|
||||
private static var mMenuStyle as Lang.Number = MENU_STYLE_ICONS;
|
||||
@ -49,6 +51,8 @@ class Settings {
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
mApiUrl = Properties.getValue("api_url");
|
||||
mConfigUrl = Properties.getValue("config_url");
|
||||
mCacheConfig = Properties.getValue("cache_config");
|
||||
mClearCache = Properties.getValue("clear_cache");
|
||||
mAppTimeout = Properties.getValue("app_timeout");
|
||||
mConfirmTimeout = Properties.getValue("confirm_timeout");
|
||||
mMenuStyle = Properties.getValue("menu_theme");
|
||||
@ -99,7 +103,20 @@ class Settings {
|
||||
static function getConfigUrl() as Lang.String {
|
||||
return mConfigUrl;
|
||||
}
|
||||
|
||||
|
||||
static function getCacheConfig() as Lang.Boolean {
|
||||
return mCacheConfig;
|
||||
}
|
||||
|
||||
static function getClearCache() as Lang.Boolean {
|
||||
return mClearCache;
|
||||
}
|
||||
|
||||
static function unsetClearCache() {
|
||||
mClearCache = false;
|
||||
Properties.setValue("clear_cache", mClearCache);
|
||||
}
|
||||
|
||||
static function getAppTimeout() as Lang.Number {
|
||||
return mAppTimeout * 1000; // Convert to milliseconds
|
||||
}
|
||||
|
Reference in New Issue
Block a user