Do not crash on zero items to update
Report unreachable URLs
Verify API URL does not have a trailing slash '/'
Increased HTTP response diagnosis
This commit is contained in:
Philip Abbey
2023-11-12 16:24:56 +00:00
parent 765d7f7f50
commit d540fb576a
40 changed files with 251 additions and 46 deletions

View File

@ -26,23 +26,29 @@ using Toybox.Timer;
class HomeAssistantApp extends Application.AppBase {
hidden var mHaMenu;
hidden var strNoApiKey as Lang.String;
hidden var strNoApiUrl as Lang.String;
hidden var strNoConfigUrl as Lang.String;
hidden var strNoInternet as Lang.String;
hidden var strNoMenu as Lang.String;
hidden var strApiFlood as Lang.String;
hidden var strNoApiKey as Lang.String;
hidden var strNoApiUrl as Lang.String;
hidden var strNoConfigUrl as Lang.String;
hidden var strNoInternet as Lang.String;
hidden var strNoMenu as Lang.String;
hidden var strApiFlood as Lang.String;
hidden var strConfigUrlNotFound as Lang.String;
hidden var strUnhandledHttpErr as Lang.String;
hidden var strTrailingSlashErr as Lang.String;
hidden var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig()
hidden var mNextItemToUpdate = 0; // Index into the above array
function initialize() {
AppBase.initialize();
strNoApiKey = WatchUi.loadResource($.Rez.Strings.NoAPIKey);
strNoApiUrl = WatchUi.loadResource($.Rez.Strings.NoApiUrl);
strNoConfigUrl = WatchUi.loadResource($.Rez.Strings.NoConfigUrl);
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
strNoMenu = WatchUi.loadResource($.Rez.Strings.NoMenu);
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
strNoApiKey = WatchUi.loadResource($.Rez.Strings.NoAPIKey);
strNoApiUrl = WatchUi.loadResource($.Rez.Strings.NoApiUrl);
strNoConfigUrl = WatchUi.loadResource($.Rez.Strings.NoConfigUrl);
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
strNoMenu = WatchUi.loadResource($.Rez.Strings.NoMenu);
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
strConfigUrlNotFound = WatchUi.loadResource($.Rez.Strings.ConfigUrlNotFound);
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
strTrailingSlashErr = WatchUi.loadResource($.Rez.Strings.TrailingSlashErr);
}
// onStart() is called on application start up
@ -54,19 +60,26 @@ class HomeAssistantApp extends Application.AppBase {
// Return the initial view of your application here
function getInitialView() as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>? {
var api_url = Properties.getValue("api_url") as Lang.String;
if ((Properties.getValue("api_key") as Lang.String).length() == 0) {
if (Globals.scDebug) {
System.println("HomeAssistantMenuItem Note - execScript(): No API key in the application settings.");
System.println("HomeAssistantMenuItem execScript(): No API key in the application settings.");
}
return [new ErrorView(strNoApiKey + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
} else if ((Properties.getValue("api_url") as Lang.String).length() == 0) {
} else if (api_url.length() == 0) {
if (Globals.scDebug) {
System.println("HomeAssistantMenuItem Note - execScript(): No API URL in the application settings.");
System.println("HomeAssistantMenuItem execScript(): No API URL in the application settings.");
}
return [new ErrorView(strNoApiUrl + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
} else if (api_url.substring(-1, api_url.length()).equals("/")) {
if (Globals.scDebug) {
System.println("HomeAssistantMenuItem execScript(): API URL must not have a trailing slash '/'.");
}
return [new ErrorView(strTrailingSlashErr + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
} else if ((Properties.getValue("config_url") as Lang.String).length() == 0) {
if (Globals.scDebug) {
System.println("HomeAssistantMenuItem Note - execScript(): No configuration URL in the application settings.");
System.println("HomeAssistantMenuItem execScript(): No configuration URL in the application settings.");
}
return [new ErrorView(strNoConfigUrl + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
} else if (System.getDeviceSettings().phoneConnected && System.getDeviceSettings().connectionAvailable) {
@ -74,7 +87,7 @@ class HomeAssistantApp extends Application.AppBase {
return [new WatchUi.View(), new WatchUi.BehaviorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
} else {
if (Globals.scDebug) {
System.println("HomeAssistantApp Note - fetchMenuConfig(): No Internet connection, skipping API call.");
System.println("HomeAssistantApp fetchMenuConfig(): No Internet connection, skipping API call.");
}
return [new ErrorView(strNoInternet + "."), new ErrorDelegate()] as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>;
}
@ -96,23 +109,30 @@ class HomeAssistantApp extends Application.AppBase {
// Avoid pushing multiple ErrorViews
WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP);
}
} else if (responseCode == 404) {
if (Globals.scDebug) {
System.println("HomeAssistantApp onReturnFetchMenuConfig() Response Code: 404, page not found. Check Configuration URL setting.");
}
WatchUi.pushView(new ErrorView(strConfigUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP);
} else if (responseCode == 200) {
mHaMenu = new HomeAssistantView(data, null);
WatchUi.switchToView(mHaMenu, new HomeAssistantViewDelegate(), WatchUi.SLIDE_IMMEDIATE);
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.
updateNextMenuItem();
} else if (responseCode == -300) {
if (mItemsToUpdate.size() > 0) {
updateNextMenuItem();
}
} else if (responseCode == Communications.NETWORK_REQUEST_TIMED_OUT) {
if (Globals.scDebug) {
System.println("HomeAssistantApp Note - onReturnFetchMenuConfig(): Network request timeout.");
System.println("HomeAssistantApp onReturnFetchMenuConfig(): Network request timeout.");
}
WatchUi.pushView(new ErrorView(strNoMenu + ". " + strNoInternet + "?"), new ErrorDelegate(), WatchUi.SLIDE_UP);
} else {
if (Globals.scDebug) {
System.println("HomeAssistantApp Note - onReturnFetchMenuConfig(): Configuration not found or potential validation issue.");
System.println("HomeAssistantApp onReturnFetchMenuConfig(): Unhandled HTTP response code = " + responseCode);
}
WatchUi.pushView(new ErrorView(strNoMenu + " code=" + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP);
WatchUi.pushView(new ErrorView(strUnhandledHttpErr + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP);
}
}

View File

@ -24,10 +24,12 @@ using Toybox.Graphics;
using Toybox.Application.Properties;
class HomeAssistantMenuItem extends WatchUi.MenuItem {
hidden var mApiKey = Properties.getValue("api_key");
hidden var strNoInternet as Lang.String;
hidden var strApiFlood as Lang.String;
hidden var mService as Lang.String;
hidden var mApiKey as Lang.String;
hidden var strNoInternet as Lang.String;
hidden var strApiFlood as Lang.String;
hidden var strApiUrlNotFound as Lang.String;
hidden var strUnhandledHttpErr as Lang.String;
hidden var mService as Lang.String;
function initialize(
label as Lang.String or Lang.Symbol,
@ -39,8 +41,11 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem {
:icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol
} or Null
) {
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound);
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
mApiKey = Properties.getValue("api_key");
mService = service;
WatchUi.MenuItem.initialize(
label,
@ -66,12 +71,17 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem {
// Avoid pushing multiple ErrorViews
WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP);
}
} else if (responseCode == 404) {
if (Globals.scDebug) {
System.println("HomeAssistantMenuItem onReturnExecScript() Response Code: 404, page not found. Check API URL setting.");
}
WatchUi.pushView(new ErrorView(strApiUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP);
} else if (responseCode == 200) {
var d = data as Lang.Array;
for(var i = 0; i < d.size(); i++) {
if ((d[i].get("entity_id") as Lang.String).equals(mIdentifier)) {
if (Globals.scDebug) {
System.println("HomeAssistantMenuItem Note - onReturnExecScript(): Correct script executed.");
System.println("HomeAssistantMenuItem onReturnExecScript(): Correct script executed.");
}
if (WatchUi has :showToast) {
WatchUi.showToast(
@ -97,6 +107,11 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem {
}
}
}
} else {
if (Globals.scDebug) {
System.println("HomeAssistantMenuItem onReturnExecScript(): Unhandled HTTP response code = " + responseCode);
}
WatchUi.pushView(new ErrorView(strUnhandledHttpErr + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP);
}
}
@ -142,7 +157,7 @@ class HomeAssistantMenuItem extends WatchUi.MenuItem {
}
} else {
if (Globals.scDebug) {
System.println("HomeAssistantMenuItem Note - execScript(): No Internet connection, skipping API call.");
System.println("HomeAssistantMenuItem execScript(): No Internet connection, skipping API call.");
}
WatchUi.pushView(new ErrorView(strNoInternet + "."), new ErrorDelegate(), WatchUi.SLIDE_UP);
}

View File

@ -24,9 +24,11 @@ using Toybox.Graphics;
using Toybox.Application.Properties;
class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
hidden var mApiKey = Properties.getValue("api_key");
hidden var strNoInternet as Lang.String;
hidden var strApiFlood as Lang.String;
hidden var mApiKey as Lang.String;
hidden var strNoInternet as Lang.String;
hidden var strApiFlood as Lang.String;
hidden var strApiUrlNotFound as Lang.String;
hidden var strUnhandledHttpErr as Lang.String;
function initialize(
label as Lang.String or Lang.Symbol,
@ -41,10 +43,12 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
:icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol
} or Null
) {
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound);
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
mApiKey = Properties.getValue("api_key");
WatchUi.ToggleMenuItem.initialize(label, subLabel, identifier, enabled, options);
mApiKey = Properties.getValue("api_key");
}
private function setUiToggle(state as Null or Lang.String) as Void {
@ -75,6 +79,17 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
// Avoid pushing multiple ErrorViews
WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP);
}
// Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer.
getApp().updateNextMenuItem();
} else if (responseCode == 404) {
if (Globals.scDebug) {
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Code: 404, page not found. Check API URL setting.");
}
var cw = WatchUi.getCurrentView();
if (!(cw[0] instanceof ErrorView)) {
// Avoid pushing multiple ErrorViews
WatchUi.pushView(new ErrorView(strApiUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP);
}
} else if (responseCode == 200) {
var state = data.get("state") as Lang.String;
if (Globals.scDebug) {
@ -84,9 +99,14 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
setLabel((data.get("attributes") as Lang.Dictionary).get("friendly_name") as Lang.String);
}
setUiToggle(state);
// Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer.
getApp().updateNextMenuItem();
} else {
if (Globals.scDebug) {
System.println("HomeAssistantToggleMenuItem onReturnGetState(): Unhandled HTTP response code = " + responseCode);
}
WatchUi.pushView(new ErrorView(strUnhandledHttpErr + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP);
}
// Now this feels very "closely coupled" to the application, but it is the most reliable method instead of using a timer.
getApp().updateNextMenuItem();
}
function getState() as Void {
@ -110,7 +130,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
);
} else {
if (Globals.scDebug) {
System.println("HomeAssistantToggleMenuItem Note - getState(): No Internet connection, skipping API call.");
System.println("HomeAssistantToggleMenuItem getState(): No Internet connection, skipping API call.");
}
WatchUi.pushView(new ErrorView(strNoInternet + "."), new ErrorDelegate(), WatchUi.SLIDE_UP);
}
@ -127,10 +147,15 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
if (Globals.scDebug) {
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: BLE_QUEUE_FULL, API calls too rapid.");
}
WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP);
} else if (responseCode == 404) {
if (Globals.scDebug) {
System.println("HomeAssistantToggleMenuItem onReturnSetState() Response Code: 404, page not found. Check API URL setting.");
}
var cw = WatchUi.getCurrentView();
if (!(cw[0] instanceof ErrorView)) {
// Avoid pushing multiple ErrorViews
WatchUi.pushView(new ErrorView(strApiFlood), new ErrorDelegate(), WatchUi.SLIDE_UP);
WatchUi.pushView(new ErrorView(strApiUrlNotFound), new ErrorDelegate(), WatchUi.SLIDE_UP);
}
} else if (responseCode == 200) {
var state;
@ -144,6 +169,11 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
setUiToggle(state);
}
}
} else {
if (Globals.scDebug) {
System.println("HomeAssistantToggleMenuItem onReturnSetState(): Unhandled HTTP response code = " + responseCode);
}
WatchUi.pushView(new ErrorView(strUnhandledHttpErr + responseCode ), new ErrorDelegate(), WatchUi.SLIDE_UP);
}
}
@ -180,7 +210,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
);
} else {
if (Globals.scDebug) {
System.println("HomeAssistantToggleMenuItem Note - setState(): No Internet connection, skipping API call.");
System.println("HomeAssistantToggleMenuItem setState(): No Internet connection, skipping API call.");
}
WatchUi.pushView(new ErrorView(strNoInternet + "."), new ErrorDelegate(), WatchUi.SLIDE_UP);
}