mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2025-06-17 20:08:33 +00:00
New glance and widget views
Added ability to test if we're a widget or a watch-app. Added troubleshooting documentation.
This commit is contained in:
@ -24,31 +24,38 @@ using Toybox.WatchUi;
|
||||
using Toybox.Application.Properties;
|
||||
|
||||
class HomeAssistantApp extends Application.AppBase {
|
||||
private var mHaMenu as HomeAssistantView or Null;
|
||||
private var mQuitTimer as QuitTimer or Null;
|
||||
private var strNoApiKey as Lang.String or Null;
|
||||
private var strNoApiUrl as Lang.String or Null;
|
||||
private var strNoConfigUrl as Lang.String or Null;
|
||||
private var strNoPhone as Lang.String or Null;
|
||||
private var strNoInternet as Lang.String or Null;
|
||||
private var strNoResponse as Lang.String or Null;
|
||||
private var strNoMenu as Lang.String or Null;
|
||||
private var strApiFlood as Lang.String or Null;
|
||||
private var strConfigUrlNotFound as Lang.String or Null;
|
||||
private var strNoJson as Lang.String or Null;
|
||||
private var strUnhandledHttpErr as Lang.String or Null;
|
||||
private var strTrailingSlashErr as Lang.String or Null;
|
||||
private var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig()
|
||||
private var mNextItemToUpdate = 0; // Index into the above array
|
||||
private var strAvailable = WatchUi.loadResource($.Rez.Strings.Available);
|
||||
private var strUnavailable = WatchUi.loadResource($.Rez.Strings.Unavailable);
|
||||
|
||||
private var mApiKey as Lang.String;
|
||||
private var mApiStatus as Lang.String = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
private var mMenuStatus as Lang.String = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
private var mHaMenu as HomeAssistantView or Null;
|
||||
private var mQuitTimer as QuitTimer or Null;
|
||||
private var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig()
|
||||
private var mNextItemToUpdate = 0; // Index into the above array
|
||||
private var mIsGlance as Lang.Boolean = false;
|
||||
|
||||
function initialize() {
|
||||
AppBase.initialize();
|
||||
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
// ATTENTION when adding stuff into this block:
|
||||
// Because of the >>GlanceView<<, it should contain only
|
||||
// code, which is used as well for the glance:
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/glances/
|
||||
//
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// "Resource Scopes":
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/resources/
|
||||
//
|
||||
@ -58,12 +65,13 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
|
||||
// onStart() is called on application start up
|
||||
function onStart(state as Lang.Dictionary?) as Void {
|
||||
AppBase.onStart(state);
|
||||
// ATTENTION when adding stuff into this block:
|
||||
// Because of the >>GlanceView<<, it should contain only
|
||||
// code, which is used as well for the glance:
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/glances/
|
||||
//
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// "Resource Scopes":
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/resources/
|
||||
//
|
||||
@ -73,12 +81,13 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
|
||||
// onStop() is called when your application is exiting
|
||||
function onStop(state as Lang.Dictionary?) as Void {
|
||||
AppBase.onStop(state);
|
||||
// ATTENTION when adding stuff into this block:
|
||||
// Because of the >>GlanceView<<, it should contain only
|
||||
// code, which is used as well for the glance:
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/glances/
|
||||
//
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// Also dealing with resources "Rez" needs attention, too. See
|
||||
// "Resource Scopes":
|
||||
// - https://developer.garmin.com/connect-iq/core-topics/resources/
|
||||
//
|
||||
@ -88,16 +97,15 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
|
||||
// Return the initial view of your application here
|
||||
function getInitialView() as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>? {
|
||||
|
||||
strNoApiKey = WatchUi.loadResource($.Rez.Strings.NoAPIKey);
|
||||
strNoApiUrl = WatchUi.loadResource($.Rez.Strings.NoApiUrl);
|
||||
strNoConfigUrl = WatchUi.loadResource($.Rez.Strings.NoConfigUrl);
|
||||
strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone);
|
||||
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||
strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse);
|
||||
strNoMenu = WatchUi.loadResource($.Rez.Strings.NoMenu);
|
||||
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
|
||||
strConfigUrlNotFound = WatchUi.loadResource($.Rez.Strings.ConfigUrlNotFound);
|
||||
strNoJson = WatchUi.loadResource($.Rez.Strings.NoJson);
|
||||
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
|
||||
strTrailingSlashErr = WatchUi.loadResource($.Rez.Strings.TrailingSlashErr);
|
||||
mQuitTimer = new QuitTimer();
|
||||
@ -136,61 +144,102 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
return ErrorView.create(strNoInternet + ".");
|
||||
} else {
|
||||
fetchMenuConfig();
|
||||
return [new RootView(self), new RootViewDelegate(self)] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
|
||||
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>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Callback function after completing the GET request to fetch the configuration menu.
|
||||
//
|
||||
(:glance)
|
||||
function onReturnFetchMenuConfig(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: " + responseCode);
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Data: " + data);
|
||||
}
|
||||
if (responseCode == Communications.BLE_HOST_TIMEOUT || responseCode == Communications.BLE_CONNECTION_UNAVAILABLE) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||
}
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
} else if (responseCode == Communications.BLE_QUEUE_FULL) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
// Don't need to worry about multiple ErrorViews here as the fetch does not happen a second time.
|
||||
ErrorView.show(strApiFlood);
|
||||
} else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
ErrorView.show(strNoResponse);
|
||||
} else if (responseCode == 404) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: 404, page not found. Check Configuration URL setting.");
|
||||
}
|
||||
ErrorView.show(strConfigUrlNotFound);
|
||||
} else if (responseCode == 200) {
|
||||
mHaMenu = new HomeAssistantView(data, null);
|
||||
mQuitTimer.begin();
|
||||
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();
|
||||
}
|
||||
} else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig(): Network request timeout.");
|
||||
}
|
||||
ErrorView.show(strNoMenu + ". " + strNoInternet + "?");
|
||||
} else {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig(): Unhandled HTTP response code = " + responseCode);
|
||||
}
|
||||
ErrorView.show(strUnhandledHttpErr + responseCode );
|
||||
|
||||
mMenuStatus = strUnavailable;
|
||||
switch (responseCode) {
|
||||
case Communications.BLE_HOST_TIMEOUT:
|
||||
case Communications.BLE_CONNECTION_UNAVAILABLE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.BLE_QUEUE_FULL:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strApiFlood);
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.NETWORK_REQUEST_TIMED_OUT:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoResponse);
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoJson);
|
||||
}
|
||||
break;
|
||||
|
||||
case 404:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: 404, page not found. Check Configuration URL setting.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strConfigUrlNotFound);
|
||||
}
|
||||
break;
|
||||
|
||||
case 200:
|
||||
mMenuStatus = strAvailable;
|
||||
if (!mIsGlance) {
|
||||
mHaMenu = new HomeAssistantView(data, null);
|
||||
mQuitTimer.begin();
|
||||
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();
|
||||
}
|
||||
if (!WidgetApp.isWidget) {
|
||||
WatchUi.switchToView(mHaMenu, new HomeAssistantViewDelegate(false), WatchUi.SLIDE_IMMEDIATE);
|
||||
}
|
||||
}
|
||||
WatchUi.requestUpdate();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchMenuConfig(): Unhandled HTTP response code = " + responseCode);
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strUnhandledHttpErr + responseCode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(:glance)
|
||||
function fetchMenuConfig() as Void {
|
||||
var options = {
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
@ -204,11 +253,120 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
);
|
||||
}
|
||||
|
||||
function homeAssistantMenuIsLoaded() as Lang.Boolean{
|
||||
return mHaMenu!=null;
|
||||
// Callback function after completing the GET request to fetch the API status.
|
||||
//
|
||||
(:glance)
|
||||
function onReturnFetchApiStatus(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: " + responseCode);
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Data: " + data);
|
||||
}
|
||||
|
||||
mApiStatus = strUnavailable;
|
||||
switch (responseCode) {
|
||||
case Communications.BLE_HOST_TIMEOUT:
|
||||
case Communications.BLE_CONNECTION_UNAVAILABLE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: BLE_HOST_TIMEOUT or BLE_CONNECTION_UNAVAILABLE, Bluetooth connection severed.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoPhone + ".");
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.BLE_QUEUE_FULL:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strApiFlood);
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.NETWORK_REQUEST_TIMED_OUT:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: NETWORK_REQUEST_TIMED_OUT, check Internet connection.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoResponse);
|
||||
}
|
||||
break;
|
||||
|
||||
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: INVALID_HTTP_BODY_IN_NETWORK_RESPONSE, check JSON is returned.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strNoJson);
|
||||
}
|
||||
break;
|
||||
|
||||
case 404:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus() Response Code: 404, page not found. Check Configuration URL setting.");
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strConfigUrlNotFound);
|
||||
}
|
||||
break;
|
||||
|
||||
case 200:
|
||||
var msg = null;
|
||||
if (data != null) {
|
||||
msg = data.get("message");
|
||||
}
|
||||
if (msg.equals("API running.")) {
|
||||
mApiStatus = strAvailable;
|
||||
} else {
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show("API " + mApiStatus + ".");
|
||||
}
|
||||
}
|
||||
WatchUi.requestUpdate();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onReturnFetchApiStatus(): Unhandled HTTP response code = " + responseCode);
|
||||
}
|
||||
if (!mIsGlance) {
|
||||
ErrorView.show(strUnhandledHttpErr + responseCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pushHomeAssistantMenuView() as Void{
|
||||
(:glance)
|
||||
function fetchApiStatus() as Void {
|
||||
var options = {
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:headers => {
|
||||
"Authorization" => "Bearer " + mApiKey
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
};
|
||||
Communications.makeWebRequest(
|
||||
Properties.getValue("api_url") + "/",
|
||||
null,
|
||||
options,
|
||||
method(:onReturnFetchApiStatus)
|
||||
);
|
||||
}
|
||||
|
||||
(:glance)
|
||||
function getApiStatus() as Lang.String {
|
||||
return mApiStatus;
|
||||
}
|
||||
|
||||
(:glance)
|
||||
function getMenuStatus() as Lang.String {
|
||||
return mMenuStatus;
|
||||
}
|
||||
|
||||
function isHomeAssistantMenuLoaded() as Lang.Boolean {
|
||||
return mHaMenu != null;
|
||||
}
|
||||
|
||||
function pushHomeAssistantMenuView() as Void {
|
||||
WatchUi.pushView(mHaMenu, new HomeAssistantViewDelegate(true), WatchUi.SLIDE_IMMEDIATE);
|
||||
}
|
||||
|
||||
@ -220,13 +378,16 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
mNextItemToUpdate = (mNextItemToUpdate + 1) % itu.size();
|
||||
}
|
||||
|
||||
function getQuitTimer() as QuitTimer{
|
||||
function getQuitTimer() as QuitTimer {
|
||||
return mQuitTimer;
|
||||
}
|
||||
|
||||
(:glance)
|
||||
function getGlanceView() {
|
||||
return [new HomeAssistantGlanceView()];
|
||||
mIsGlance = true;
|
||||
fetchMenuConfig();
|
||||
fetchApiStatus();
|
||||
return [new HomeAssistantGlanceView(self)];
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user