Files
GarminHomeAssistant/source/HomeAssistantSyncDelegate.mc
Philip Abbey 70f05e8912 Added missing code headers
And included vincentezw in headers for the code he touched.
2025-07-22 22:14:46 +01:00

127 lines
4.7 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 Home Assistant
//
class HomeAssistantSyncDelegate extends Communications.SyncDelegate {
private static var syncError as Lang.String or Null;
// Initialize an instance of this delegate
public function initialize() {
SyncDelegate.initialize();
}
//! Called by the system to determine if a sync is needed
public function isSyncNeeded() as Lang.Boolean {
return true;
}
//! Called by the system when starting a bulk sync.
public function onStartSync() as Void {
syncError = null;
if (WifiLteExecutionConfirmDelegate.mCommandData == null) {
syncError = 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 Hass with a given payload and URL, and calls haCallback
private function performRequest(url as Lang.String, data as Lang.Dictionary or Null) {
Communications.makeWebRequest(
url,
data, // May include {"entity_id": xxxx} for service calls
{
:method => Communications.HTTP_REQUEST_METHOD_POST,
:headers => {
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
"Authorization" => "Bearer " + Settings.getApiKey()
},
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON,
},
method(:haCallback)
);
}
//! Handle callback from request
public function haCallback(code as Lang.Number, data as Null or Lang.Dictionary) as Void {
Communications.notifySyncProgress(100);
if (code == 200) {
syncError = null;
if (WifiLteExecutionConfirmDelegate.mCommandData[:type].equals("entity")) {
var callbackMethod = WifiLteExecutionConfirmDelegate.mCommandData[:callback];
if (callbackMethod != null) {
var d = data as Lang.Array;
callbackMethod.invoke(d);
}
}
onStopSync();
return;
}
switch(code) {
case Communications.NETWORK_REQUEST_TIMED_OUT:
syncError = WatchUi.loadResource($.Rez.Strings.TimedOut) as Lang.String;
break;
case Communications.INVALID_HTTP_BODY_IN_NETWORK_RESPONSE:
syncError = WatchUi.loadResource($.Rez.Strings.NoJson) as Lang.String;
syncError = "";
default:
var codeMsg = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr) as Lang.String;
syncError = codeMsg + code;
break;
}
onStopSync();
}
//! Clean up
public function onStopSync() as Void {
if (WifiLteExecutionConfirmDelegate.mCommandData[:exit]) {
System.exit();
}
Communications.cancelAllRequests();
Communications.notifySyncComplete(syncError);
}
}