diff --git a/resources/settings/properties.xml b/resources/settings/properties.xml
index 7d88dff..c7009ea 100644
--- a/resources/settings/properties.xml
+++ b/resources/settings/properties.xml
@@ -13,31 +13,44 @@
-->
-
+
+
+
+
-
+
-
+
false
-
+
false
0
3
@@ -71,4 +84,4 @@
-->
15
-
+
\ No newline at end of file
diff --git a/resources/settings/settings.xml b/resources/settings/settings.xml
index 66912fc..15fd778 100644
--- a/resources/settings/settings.xml
+++ b/resources/settings/settings.xml
@@ -107,4 +107,10 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/source/BackgroundServiceDelegate.mc b/source/BackgroundServiceDelegate.mc
index e398065..d40bb42 100644
--- a/source/BackgroundServiceDelegate.mc
+++ b/source/BackgroundServiceDelegate.mc
@@ -51,17 +51,26 @@ class BackgroundServiceDelegate extends System.ServiceDelegate {
} else {
// Don't use Settings.* here as the object lasts < 30 secs and is recreated each time the background service is run
Communications.makeWebRequest(
- (Properties.getValue("api_url") as Lang.String) + "/events/garmin.battery_level",
+ (Properties.getValue("api_url") as Lang.String) + "/webhook/" + (Properties.getValue("webhook_id") as Lang.String),
{
- "level" => System.getSystemStats().battery,
- "is_charging" => System.getSystemStats().charging,
- "device_id" => System.getDeviceSettings().uniqueIdentifier
+ "type" => "update_sensor_states",
+ "data" => [
+ {
+ "state" => System.getSystemStats().battery,
+ "type" => "sensor",
+ "unique_id" => "battery_level"
+ },
+ {
+ "state" => System.getSystemStats().charging,
+ "type" => "binary_sensor",
+ "unique_id" => "battery_is_charging"
+ }
+ ]
},
{
:method => Communications.HTTP_REQUEST_METHOD_POST,
:headers => {
- "Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
- "Authorization" => "Bearer " + (Properties.getValue("api_key") as Lang.String)
+ "Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON
},
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
},
diff --git a/source/Settings.mc b/source/Settings.mc
index 407145f..942c4e3 100644
--- a/source/Settings.mc
+++ b/source/Settings.mc
@@ -25,6 +25,110 @@ using Toybox.System;
// Battery Level Reporting
using Toybox.Background;
using Toybox.Time;
+using Toybox.Communications;
+
+class WebhookManager {
+ function onReturnRequestWebhookId(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void {
+ // TODO: Handle errors
+ if (responseCode == 201) {
+ var id = data.get("webhook_id") as Lang.String or Null;
+ if (id != null) {
+ Settings.setWebhookId(id);
+ registerWebhookSensor({
+ "device_class" => "battery",
+ "name" => "Battery Level",
+ "state" => System.getSystemStats().battery,
+ "type" => "sensor",
+ "unique_id" => "battery_level",
+ "unit_of_measurement" => "%",
+ "state_class" => "measurement",
+ "entity_category" => "diagnostic",
+ "disabled" => false
+ });
+ registerWebhookSensor({
+ "device_class" => "battery_charging",
+ "name" => "Battery is Charging",
+ "state" => System.getSystemStats().charging,
+ "type" => "binary_sensor",
+ "unique_id" => "battery_is_charging",
+ "entity_category" => "diagnostic",
+ "disabled" => false
+ });
+ }
+ } else {
+ if (Globals.scDebug) {
+ System.println("Settings onReturnRequestWebhookId(): Error: " + responseCode);
+ }
+ }
+ }
+
+ function requestWebhookId() {
+ if (Globals.scDebug) {
+ System.println("Settings requestWebhookId(): Requesting webhook id");
+ }
+ Communications.makeWebRequest(
+ Settings.getApiUrl() + "/mobile_app/registrations",
+ {
+ "device_id" => System.getDeviceSettings().uniqueIdentifier,
+ "app_id" => "garmin_home_assistant",
+ "app_name" => "GarminHomeAssistant",
+ "app_version" => "",
+ "device_name" => "Garmin Watch",
+ "manufacturer" => "Garmin",
+ "model" => "",
+ "os_name" => "",
+ "os_version" => Lang.format("$1$.$2$", System.getDeviceSettings().firmwareVersion),
+ "supports_encryption" => false,
+ "app_data" => {}
+ },
+ {
+ :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(:onReturnRequestWebhookId)
+ );
+ }
+
+ function onReturnRegisterWebhookSensor(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void {
+ // TODO: Handle errors
+ if (responseCode == 201) {
+ if ((data.get("success") as Lang.Boolean or Null) == true) {
+ if (Globals.scDebug) {
+ System.println("Settings onReturnRegisterWebhookSensor(): Success");
+ }
+ }
+ } else {
+ if (Globals.scDebug) {
+ System.println("Settings onReturnRegisterWebhookSensor(): Error: " + responseCode);
+ }
+ }
+ }
+
+ function registerWebhookSensor(sensor as Lang.Object) {
+ if (Globals.scDebug) {
+ System.println("Settings registerWebhookSensor(): Registering webhook sensor: " + sensor.toString());
+ }
+ Communications.makeWebRequest(
+ Settings.getApiUrl() + "/webhook/" + Settings.getWebhookId(),
+ {
+ "type" => "register_sensor",
+ "data" => sensor
+ },
+ {
+ :method => Communications.HTTP_REQUEST_METHOD_POST,
+ :headers => {
+ "Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON
+ },
+ :responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
+ },
+ method(:onReturnRegisterWebhookSensor)
+ );
+ }
+}
(:glance, :background)
class Settings {
@@ -32,6 +136,7 @@ class Settings {
public static const MENU_STYLE_TEXT = 1;
private static var mApiKey as Lang.String = "";
+ private static var mWebhookId 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;
@@ -45,10 +150,14 @@ class Settings {
private static var mBatteryRefreshRate as Lang.Number = 15; // minutes
private static var mIsApp as Lang.Boolean = false;
+ // Must keep the object so it doesn't get garbage collected.
+ private static var mWebhookManager as WebhookManager or Null;
+
// Called on application start and then whenever the settings are changed.
static function update() {
mIsApp = getApp().getIsApp();
mApiKey = Properties.getValue("api_key");
+ mWebhookId = Properties.getValue("webhook_id");
mApiUrl = Properties.getValue("api_url");
mConfigUrl = Properties.getValue("config_url");
mCacheConfig = Properties.getValue("cache_config");
@@ -64,7 +173,12 @@ class Settings {
// Manage this inside the application or widget only (not a glance or background service process)
if (mIsApp) {
if (mIsBatteryLevelEnabled) {
- if ((System has :ServiceDelegate) and
+ if (getWebhookId().equals("")) {
+ mWebhookManager = new WebhookManager();
+ mWebhookManager.requestWebhookId();
+ }
+ if (!getWebhookId().equals("") and
+ (System has :ServiceDelegate) and
((Background.getTemporalEventRegisteredTime() == null) or
(Background.getTemporalEventRegisteredTime() != (mBatteryRefreshRate * 60)))) {
Background.registerForTemporalEvent(new Time.Duration(mBatteryRefreshRate * 60)); // Convert to seconds
@@ -90,6 +204,15 @@ class Settings {
return mApiKey;
}
+ static function getWebhookId() as Lang.String {
+ return mWebhookId;
+ }
+
+ static function setWebhookId(webhookId as Lang.String) {
+ mWebhookId = webhookId;
+ Properties.setValue("webhook_id", mWebhookId);
+ }
+
static function getApiUrl() as Lang.String {
return mApiUrl;
}
@@ -130,5 +253,4 @@ class Settings {
static function getIsWidgetStartNoTap() as Lang.Boolean {
return mIsWidgetStartNoTap;
}
-
}