mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2025-09-15 13:31:31 +00:00
1. Fixed a bug where templates failed to display in toggle menu items (at least on some devices). 2. Fixed a bug where a menu item requesting to exit on completion appeared to indicate failure when using Wi-Fi or LTE. The fix uses a delay in exiting the application modelled as sufficient for a Venu 2 device, so this might need tweaking for other devices.
146 lines
5.4 KiB
MonkeyC
146 lines
5.4 KiB
MonkeyC
//-----------------------------------------------------------------------------------
|
|
//
|
|
// Distributed under MIT Licence
|
|
// See https://github.com/house-of-abbey/GarminHomeAssistant/blob/main/LICENSE.
|
|
//
|
|
//-----------------------------------------------------------------------------------
|
|
//
|
|
// GarminHomeAssistant is a Garmin IQ application written in Monkey C and routinely
|
|
// tested on a Venu 2 device. The source code is provided at:
|
|
// https://github.com/house-of-abbey/GarminHomeAssistant.
|
|
//
|
|
// P A Abbey & J D Abbey & vincentezw, 22 July 2025
|
|
//
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
using Toybox.Communications;
|
|
using Toybox.Lang;
|
|
|
|
//! SyncDelegate to execute single command via POST request to the Home Assistant
|
|
//! server.
|
|
//
|
|
class HomeAssistantSyncDelegate extends Communications.SyncDelegate {
|
|
//! Retain the last synchronisation error.
|
|
private static var mSyncError as Lang.String?;
|
|
|
|
//! Class Constructor
|
|
//
|
|
public function initialize() {
|
|
SyncDelegate.initialize();
|
|
}
|
|
|
|
//! Called by the system to determine if a synchronisation is needed
|
|
//
|
|
public function isSyncNeeded() as Lang.Boolean {
|
|
return true;
|
|
}
|
|
|
|
//! Called by the system when starting a bulk synchronisation.
|
|
//
|
|
public function onStartSync() as Void {
|
|
mSyncError = null;
|
|
if (WifiLteExecutionConfirmDelegate.mCommandData == null) {
|
|
mSyncError = WatchUi.loadResource($.Rez.Strings.WifiLteExecutionDataError) as Lang.String;
|
|
onStopSync();
|
|
return;
|
|
}
|
|
|
|
var type = WifiLteExecutionConfirmDelegate.mCommandData[:type];
|
|
var data = WifiLteExecutionConfirmDelegate.mCommandData[:data];
|
|
var url;
|
|
|
|
switch (type) {
|
|
case "service":
|
|
var service = WifiLteExecutionConfirmDelegate.mCommandData[:service];
|
|
url = Settings.getApiUrl() + "/services/" + service.substring(0, service.find(".")) + "/" + service.substring(service.find(".")+1, service.length());
|
|
var entity_id = "";
|
|
if (data != null) {
|
|
entity_id = data.get("entity_id");
|
|
if (entity_id == null) {
|
|
entity_id = "";
|
|
}
|
|
}
|
|
performRequest(url, data);
|
|
break;
|
|
case "entity":
|
|
url = WifiLteExecutionConfirmDelegate.mCommandData[:url];
|
|
performRequest(url, data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//! Performs a POST request to the Home Assistant server with a given payload and URL, and calls
|
|
//! haCallback.
|
|
//!
|
|
//! @param url URL for the API call.
|
|
//! @param data Data to be supplied to the API call.
|
|
//
|
|
private function performRequest(url as Lang.String, data as Lang.Dictionary?) {
|
|
Communications.makeWebRequest(
|
|
url,
|
|
data, // May include {"entity_id": xxxx} for service calls
|
|
{
|
|
:method => Communications.HTTP_REQUEST_METHOD_POST,
|
|
:headers => Settings.augmentHttpHeaders({
|
|
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
|
|
"Authorization" => "Bearer " + Settings.getApiKey()
|
|
}),
|
|
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON,
|
|
},
|
|
method(:haCallback)
|
|
);
|
|
}
|
|
|
|
//! Handle callback from request
|
|
//!
|
|
//! @param responseCode Response code.
|
|
//! @param data Response data.
|
|
//
|
|
public function haCallback(code as Lang.Number, data as Lang.Dictionary?) as Void {
|
|
Communications.notifySyncProgress(100);
|
|
switch(code) {
|
|
case Communications.NETWORK_REQUEST_TIMED_OUT:
|
|
mSyncError = WatchUi.loadResource($.Rez.Strings.TimedOut);
|
|
break;
|
|
case Communications.NETWORK_RESPONSE_OUT_OF_MEMORY:
|
|
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
|
|
mSyncError = WatchUi.loadResource($.Rez.Strings.PotentialError);
|
|
break;
|
|
case 404:
|
|
mSyncError = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound);
|
|
break;
|
|
case 200:
|
|
mSyncError = null;
|
|
if (WifiLteExecutionConfirmDelegate.mCommandData[:type].equals("entity")) {
|
|
var callbackMethod = WifiLteExecutionConfirmDelegate.mCommandData[:callback];
|
|
if (callbackMethod != null) {
|
|
callbackMethod.invoke(data as Lang.Array);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
mSyncError = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr) + code;
|
|
break;
|
|
}
|
|
onStopSync();
|
|
}
|
|
|
|
//! Clean up
|
|
//
|
|
public function onStopSync() as Void {
|
|
Communications.notifySyncComplete(mSyncError);
|
|
Communications.cancelAllRequests();
|
|
// Need to delay the exit here or the transfer shows as failed (and it might not be).
|
|
if (WifiLteExecutionConfirmDelegate.mCommandData[:exit]) {
|
|
var myTimer = new Timer.Timer();
|
|
myTimer.start(method(:exit), Globals.wifiQuitDelayMs, false);
|
|
}
|
|
}
|
|
|
|
//! Required for `method(:exit)` to be able to find a method at all.
|
|
//
|
|
public function exit() as Void {
|
|
System.exit();
|
|
}
|
|
}
|