mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2025-08-02 09:58:39 +00:00
Added Watch Battery transmission
Added a background service to send the watch battery level to Home Assistant. Changed the Glance View as requested by a user. Updated to new HA icon using SVG in stead of PNG.
This commit is contained in:
73
source/BackgroundServiceDelegate.mc
Normal file
73
source/BackgroundServiceDelegate.mc
Normal file
@ -0,0 +1,73 @@
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// 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 & Someone0nEarth, 31 October 2023
|
||||
//
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// The background service delegate currently just reports the Garmin watch's battery
|
||||
// level.
|
||||
//
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
using Toybox.Lang;
|
||||
using Toybox.Application.Properties;
|
||||
using Toybox.Background;
|
||||
using Toybox.System;
|
||||
|
||||
(:background)
|
||||
class BackgroundServiceDelegate extends System.ServiceDelegate {
|
||||
|
||||
function initialize() {
|
||||
ServiceDelegate.initialize();
|
||||
}
|
||||
|
||||
function onReturnBatteryUpdate(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void {
|
||||
if (Globals.scDebug) {
|
||||
System.println("BackgroundServiceDelegate onReturnBatteryUpdate() Response Code: " + responseCode);
|
||||
System.println("BackgroundServiceDelegate onReturnBatteryUpdate() Response Data: " + data);
|
||||
}
|
||||
Background.exit(null);
|
||||
}
|
||||
|
||||
function onTemporalEvent() as Void {
|
||||
if (! System.getDeviceSettings().phoneConnected) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("BackgroundServiceDelegate onTemporalEvent(): No Phone connection, skipping API call.");
|
||||
}
|
||||
} else if (! System.getDeviceSettings().connectionAvailable) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("BackgroundServiceDelegate onTemporalEvent(): No Internet connection, skipping API call.");
|
||||
}
|
||||
} 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",
|
||||
{
|
||||
"level" => System.getSystemStats().battery,
|
||||
"is_charging" => System.getSystemStats().charging,
|
||||
"device_id" => System.getDeviceSettings().uniqueIdentifier
|
||||
},
|
||||
{
|
||||
:method => Communications.HTTP_REQUEST_METHOD_POST,
|
||||
:headers => {
|
||||
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
|
||||
"Authorization" => "Bearer " + (Properties.getValue("api_key") as Lang.String)
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
},
|
||||
method(:onReturnBatteryUpdate)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
27
source/ClientId.mc.unpopulated
Normal file
27
source/ClientId.mc.unpopulated
Normal file
@ -0,0 +1,27 @@
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// J D Abbey & P A Abbey, 28 December 2022
|
||||
//
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// ClientId is somewhere to store personal credentials that should not be shared in
|
||||
// a separate file that is locally customised to the source code and not commited
|
||||
// back to GitHub.
|
||||
//
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
(:glance)
|
||||
class ClientId {
|
||||
static const webLogUrl = "https://...";
|
||||
static const webLogClearUrl = "https://..._clear.php";
|
||||
}
|
@ -20,6 +20,7 @@
|
||||
|
||||
using Toybox.Lang;
|
||||
|
||||
(:glance)
|
||||
class Globals {
|
||||
// Enable printing of messages to the debug console (don't make this a Property
|
||||
// as the messages can't be read from a watch!)
|
||||
|
@ -21,40 +21,39 @@
|
||||
using Toybox.Application;
|
||||
using Toybox.Lang;
|
||||
using Toybox.WatchUi;
|
||||
using Toybox.System;
|
||||
using Toybox.Application.Properties;
|
||||
using Toybox.Timer;
|
||||
|
||||
(:background)
|
||||
class HomeAssistantApp extends Application.AppBase {
|
||||
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 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 strAvailable = WatchUi.loadResource($.Rez.Strings.Available);
|
||||
private var strUnavailable = WatchUi.loadResource($.Rez.Strings.Unavailable);
|
||||
private var strUnconfigured = WatchUi.loadResource($.Rez.Strings.Unconfigured);
|
||||
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 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 strAvailable as Lang.String or Null;
|
||||
private var strUnavailable as Lang.String or Null;
|
||||
private var strUnconfigured as Lang.String or Null;
|
||||
|
||||
private var mApiKey as Lang.String or Null; // The compiler can't tell these are updated by
|
||||
private var mApiUrl as Lang.String or Null; // initialize(), hence the "or Null".
|
||||
private var mConfigUrl as Lang.String or Null; //
|
||||
private var mApiStatus as Lang.String = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
private var mMenuStatus as Lang.String = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
private var mApiStatus as Lang.String or Null;
|
||||
private var mMenuStatus as Lang.String or Null;
|
||||
private var mHaMenu as HomeAssistantView or Null;
|
||||
private var mQuitTimer as QuitTimer or Null;
|
||||
private var mTimer as Timer.Timer or Null;
|
||||
private var mItemsToUpdate; // Array initialised by onReturnFetchMenuConfig()
|
||||
private var mNextItemToUpdate = 0; // Index into the above array
|
||||
private var mItemsToUpdate as Lang.Array<HomeAssistantToggleMenuItem> or Null; // Array initialised by onReturnFetchMenuConfig()
|
||||
private var mNextItemToUpdate as Lang.Number = 0; // Index into the above array
|
||||
private var mIsGlance as Lang.Boolean = false;
|
||||
private var mIsApp as Lang.Boolean = false; // Or Widget
|
||||
|
||||
function initialize() {
|
||||
AppBase.initialize();
|
||||
onSettingsChanged();
|
||||
// ATTENTION when adding stuff into this block:
|
||||
// Because of the >>GlanceView<<, it should contain only
|
||||
// code, which is used as well for the glance:
|
||||
@ -100,8 +99,18 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
// with "(:glance)".
|
||||
}
|
||||
|
||||
// These are required for the Application/Widget and the Glance view, but not for the background service.
|
||||
function initResources() {
|
||||
strAvailable = WatchUi.loadResource($.Rez.Strings.Available);
|
||||
strUnavailable = WatchUi.loadResource($.Rez.Strings.Unavailable);
|
||||
strUnconfigured = WatchUi.loadResource($.Rez.Strings.Unconfigured);
|
||||
mApiStatus = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
mMenuStatus = WatchUi.loadResource($.Rez.Strings.Checking);
|
||||
}
|
||||
|
||||
// Return the initial view of your application here
|
||||
function getInitialView() as Lang.Array<WatchUi.Views or WatchUi.InputDelegates>? {
|
||||
mIsApp = true;
|
||||
strNoApiKey = WatchUi.loadResource($.Rez.Strings.NoAPIKey);
|
||||
strNoApiUrl = WatchUi.loadResource($.Rez.Strings.NoApiUrl);
|
||||
strNoConfigUrl = WatchUi.loadResource($.Rez.Strings.NoConfigUrl);
|
||||
@ -113,24 +122,25 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
strNoJson = WatchUi.loadResource($.Rez.Strings.NoJson);
|
||||
strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
|
||||
strTrailingSlashErr = WatchUi.loadResource($.Rez.Strings.TrailingSlashErr);
|
||||
initResources();
|
||||
mQuitTimer = new QuitTimer();
|
||||
|
||||
if (mApiKey.length() == 0) {
|
||||
if (Settings.get().getApiKey().length() == 0) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp getInitialView(): No API key in the application settings.");
|
||||
System.println("HomeAssistantApp getInitialView(): No API key in the application Settings.get().");
|
||||
}
|
||||
return ErrorView.create(strNoApiKey + ".");
|
||||
} else if (mApiUrl.length() == 0) {
|
||||
} else if (Settings.get().getApiUrl().length() == 0) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp getInitialView(): No API URL in the application settings.");
|
||||
System.println("HomeAssistantApp getInitialView(): No API URL in the application Settings.get().");
|
||||
}
|
||||
return ErrorView.create(strNoApiUrl + ".");
|
||||
} else if (mApiUrl.substring(-1, mApiUrl.length()).equals("/")) {
|
||||
} else if (Settings.get().getApiUrl().substring(-1, Settings.get().getApiUrl().length()).equals("/")) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp getInitialView(): API URL must not have a trailing slash '/'.");
|
||||
}
|
||||
return ErrorView.create(strTrailingSlashErr + ".");
|
||||
} else if (mConfigUrl.length() == 0) {
|
||||
} else if (Settings.get().getConfigUrl().length() == 0) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp getInitialView(): No configuration URL in the application settings.");
|
||||
}
|
||||
@ -218,7 +228,7 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
if (!mIsGlance) {
|
||||
mHaMenu = new HomeAssistantView(data, null);
|
||||
mQuitTimer.begin();
|
||||
if (Properties.getValue("widget_start_no_tap")) {
|
||||
if (Settings.get().get().getIsWidgetStartNoTap()) {
|
||||
// As soon as the menu has been fetched start show the menu of items.
|
||||
// This behaviour is inconsistent with the standard Garmin User Interface, but has been
|
||||
// requested by users so has been made the non-default option.
|
||||
@ -250,14 +260,10 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
|
||||
(:glance)
|
||||
function fetchMenuConfig() as Void {
|
||||
if (mConfigUrl.equals("")) {
|
||||
if (Settings.get().getConfigUrl().equals("")) {
|
||||
mMenuStatus = strUnconfigured;
|
||||
WatchUi.requestUpdate();
|
||||
} else {
|
||||
var options = {
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
};
|
||||
if (! System.getDeviceSettings().phoneConnected) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem getState(): No Phone connection, skipping API call.");
|
||||
@ -280,9 +286,12 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
mMenuStatus = strUnavailable;
|
||||
} else {
|
||||
Communications.makeWebRequest(
|
||||
mConfigUrl,
|
||||
Settings.get().getConfigUrl(),
|
||||
null,
|
||||
options,
|
||||
{
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
},
|
||||
method(:onReturnFetchMenuConfig)
|
||||
);
|
||||
}
|
||||
@ -373,17 +382,10 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
|
||||
(:glance)
|
||||
function fetchApiStatus() as Void {
|
||||
if (mApiUrl.equals("")) {
|
||||
if (Settings.get().getApiUrl().equals("")) {
|
||||
mApiStatus = strUnconfigured;
|
||||
WatchUi.requestUpdate();
|
||||
} else {
|
||||
var options = {
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:headers => {
|
||||
"Authorization" => "Bearer " + mApiKey
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
};
|
||||
if (! System.getDeviceSettings().phoneConnected) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem getState(): No Phone connection, skipping API call.");
|
||||
@ -406,9 +408,15 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
}
|
||||
} else {
|
||||
Communications.makeWebRequest(
|
||||
mApiUrl + "/",
|
||||
Settings.get().getApiUrl() + "/",
|
||||
null,
|
||||
options,
|
||||
{
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:headers => {
|
||||
"Authorization" => "Bearer " + Settings.get().getApiKey()
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
},
|
||||
method(:onReturnFetchApiStatus)
|
||||
);
|
||||
}
|
||||
@ -437,8 +445,8 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
WatchUi.pushView(mHaMenu, new HomeAssistantViewDelegate(true), WatchUi.SLIDE_IMMEDIATE);
|
||||
}
|
||||
|
||||
// We need to spread out the API calls so as not to overload the results queue and cause Communications.BLE_QUEUE_FULL (-101) error.
|
||||
// This function is called by a timer every Globals.menuItemUpdateInterval ms.
|
||||
// We need to spread out the API calls so as not to overload the results queue and cause Communications.BLE_QUEUE_FULL
|
||||
// (-101) error. This function is called by a timer every Globals.menuItemUpdateInterval ms.
|
||||
function updateNextMenuItem() as Void {
|
||||
var itu = mItemsToUpdate as Lang.Array<HomeAssistantToggleMenuItem>;
|
||||
if (itu == null) {
|
||||
@ -458,9 +466,9 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
return mQuitTimer;
|
||||
}
|
||||
|
||||
(:glance)
|
||||
function getGlanceView() as Lang.Array<WatchUi.GlanceView or WatchUi.GlanceViewDelegate> or Null {
|
||||
mIsGlance = true;
|
||||
initResources();
|
||||
updateGlance();
|
||||
mTimer = new Timer.Timer();
|
||||
mTimer.start(method(:updateGlance), Globals.scApiBackoff, true);
|
||||
@ -476,12 +484,25 @@ class HomeAssistantApp extends Application.AppBase {
|
||||
// Replace this functionality with a more central settings class as proposed in
|
||||
// https://github.com/house-of-abbey/GarminHomeAssistant/pull/17.
|
||||
function onSettingsChanged() as Void {
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
mApiUrl = Properties.getValue("api_url");
|
||||
mConfigUrl = Properties.getValue("config_url");
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantApp onSettingsChanged()");
|
||||
}
|
||||
Settings.get().update();
|
||||
}
|
||||
|
||||
// Called each time the Registered Temporal Event is to be invoked. So the object is created each time on request and
|
||||
// then destroyed on completion (to save resources).
|
||||
function getServiceDelegate() as Lang.Array<System.ServiceDelegate> {
|
||||
return [new BackgroundServiceDelegate()];
|
||||
}
|
||||
|
||||
function getIsApp() as Lang.Boolean {
|
||||
return mIsApp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
(:glance, :background)
|
||||
function getApp() as HomeAssistantApp {
|
||||
return Application.getApp() as HomeAssistantApp;
|
||||
}
|
||||
|
@ -40,10 +40,10 @@ class HomeAssistantConfirmationDelegate extends WatchUi.ConfirmationDelegate {
|
||||
function initialize(callback as Method() as Void) {
|
||||
WatchUi.ConfirmationDelegate.initialize();
|
||||
mConfirmMethod = callback;
|
||||
var timeoutSeconds = Properties.getValue("confirm_timeout") as Lang.Number;
|
||||
if (timeoutSeconds > 0) {
|
||||
var timeout = Settings.get().getConfirmTimeout(); // ms
|
||||
if (timeout > 0) {
|
||||
mTimer = new Timer.Timer();
|
||||
mTimer.start(method(:onTimeout), timeoutSeconds * 1000, true);
|
||||
mTimer.start(method(:onTimeout), timeout, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,7 @@ using Toybox.Graphics;
|
||||
|
||||
(:glance)
|
||||
class HomeAssistantGlanceView extends WatchUi.GlanceView {
|
||||
private static const scLeftMargin = 20; // in pixels
|
||||
private static const scLeftIndent = 10; // Left Indent "_text:" in pixels
|
||||
private static const scLeftMargin = 5; // in pixels
|
||||
private static const scMidSep = 10; // Middle Separator "text:_text" in pixels
|
||||
private var mApp as HomeAssistantApp;
|
||||
private var mTitle as WatchUi.Text or Null;
|
||||
@ -58,8 +57,8 @@ class HomeAssistantGlanceView extends WatchUi.GlanceView {
|
||||
:text => "API:",
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin + scLeftIndent + tw,
|
||||
:justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin,
|
||||
:locY => 3 * h / 6
|
||||
});
|
||||
mApiStatus = new WatchUi.Text({
|
||||
@ -67,15 +66,15 @@ class HomeAssistantGlanceView extends WatchUi.GlanceView {
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin + scLeftIndent + scMidSep + tw,
|
||||
:locX => scLeftMargin + scMidSep + tw,
|
||||
:locY => 3 * h / 6
|
||||
});
|
||||
mMenuText = new WatchUi.Text({
|
||||
:text => strGlanceMenu + ":",
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_RIGHT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin + scLeftIndent + tw,
|
||||
:justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin,
|
||||
:locY => 5 * h / 6
|
||||
});
|
||||
mMenuStatus = new WatchUi.Text({
|
||||
@ -83,7 +82,7 @@ class HomeAssistantGlanceView extends WatchUi.GlanceView {
|
||||
:color => Graphics.COLOR_WHITE,
|
||||
:font => Graphics.FONT_XTINY,
|
||||
:justification => Graphics.TEXT_JUSTIFY_LEFT | Graphics.TEXT_JUSTIFY_VCENTER,
|
||||
:locX => scLeftMargin + scLeftIndent + scMidSep + tw,
|
||||
:locX => scLeftMargin + scMidSep + tw,
|
||||
:locY => 5 * h / 6
|
||||
});
|
||||
}
|
||||
@ -95,7 +94,7 @@ class HomeAssistantGlanceView extends WatchUi.GlanceView {
|
||||
}
|
||||
dc.setColor(
|
||||
Graphics.COLOR_WHITE,
|
||||
Graphics.COLOR_BLUE
|
||||
Graphics.COLOR_TRANSPARENT
|
||||
);
|
||||
dc.clear();
|
||||
mTitle.draw(dc);
|
||||
|
@ -23,13 +23,12 @@ using Toybox.Lang;
|
||||
using Toybox.WatchUi;
|
||||
|
||||
class HomeAssistantMenuItemFactory {
|
||||
private var mMenuItemOptions as Lang.Dictionary;
|
||||
private var mLabelToggle as Lang.Dictionary;
|
||||
private var strMenuItemTap as Lang.String;
|
||||
private var bRepresentTypesWithLabels as Lang.Boolean;
|
||||
private var mTapTypeIcon as WatchUi.Bitmap;
|
||||
private var mGroupTypeIcon as WatchUi.Bitmap;
|
||||
private var mHomeAssistantService as HomeAssistantService;
|
||||
private var mMenuItemOptions as Lang.Dictionary;
|
||||
private var mLabelToggle as Lang.Dictionary;
|
||||
private var strMenuItemTap as Lang.String;
|
||||
private var mTapTypeIcon as WatchUi.Bitmap;
|
||||
private var mGroupTypeIcon as WatchUi.Bitmap;
|
||||
private var mHomeAssistantService as HomeAssistantService;
|
||||
|
||||
private static var instance;
|
||||
|
||||
@ -38,18 +37,10 @@ class HomeAssistantMenuItemFactory {
|
||||
:enabled => WatchUi.loadResource($.Rez.Strings.MenuItemOn) as Lang.String,
|
||||
:disabled => WatchUi.loadResource($.Rez.Strings.MenuItemOff) as Lang.String
|
||||
};
|
||||
bRepresentTypesWithLabels = Application.Properties.getValue("types_representation") as Lang.Boolean;
|
||||
|
||||
var menuItemAlignment = Application.Properties.getValue("menu_alignment") as Lang.Boolean;
|
||||
if(menuItemAlignment){
|
||||
mMenuItemOptions = {
|
||||
:alignment => WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_RIGHT
|
||||
};
|
||||
} else {
|
||||
mMenuItemOptions = {
|
||||
:alignment => WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_LEFT
|
||||
};
|
||||
}
|
||||
mMenuItemOptions = {
|
||||
:alignment => Settings.get().getMenuAlignment()
|
||||
};
|
||||
|
||||
strMenuItemTap = WatchUi.loadResource($.Rez.Strings.MenuItemTap);
|
||||
mTapTypeIcon = new WatchUi.Bitmap({
|
||||
@ -74,15 +65,9 @@ class HomeAssistantMenuItemFactory {
|
||||
}
|
||||
|
||||
function toggle(label as Lang.String or Lang.Symbol, identifier as Lang.Object or Null) as WatchUi.MenuItem {
|
||||
var subLabel = null;
|
||||
|
||||
if (bRepresentTypesWithLabels == true){
|
||||
subLabel=mLabelToggle;
|
||||
}
|
||||
|
||||
return new HomeAssistantToggleMenuItem(
|
||||
label,
|
||||
subLabel,
|
||||
Settings.get().getMenuStyle() == Settings.MENU_STYLE_TEXT ? mLabelToggle : null,
|
||||
identifier,
|
||||
false,
|
||||
mMenuItemOptions
|
||||
@ -95,7 +80,7 @@ class HomeAssistantMenuItemFactory {
|
||||
service as Lang.String or Null,
|
||||
confirm as Lang.Boolean
|
||||
) as WatchUi.MenuItem {
|
||||
if (bRepresentTypesWithLabels) {
|
||||
if (Settings.get().getMenuStyle() == Settings.MENU_STYLE_TEXT) {
|
||||
return new HomeAssistantMenuItem(
|
||||
label,
|
||||
strMenuItemTap,
|
||||
@ -120,7 +105,7 @@ class HomeAssistantMenuItemFactory {
|
||||
}
|
||||
|
||||
function group(definition as Lang.Dictionary) as WatchUi.MenuItem {
|
||||
if (bRepresentTypesWithLabels) {
|
||||
if (Settings.get().getMenuStyle() == Settings.MENU_STYLE_TEXT) {
|
||||
return new HomeAssistantViewMenuItem(definition);
|
||||
} else {
|
||||
return new HomeAssistantViewIconMenuItem(definition, mGroupTypeIcon, mMenuItemOptions);
|
||||
|
@ -27,17 +27,11 @@ class HomeAssistantService {
|
||||
private var strNoPhone = WatchUi.loadResource($.Rez.Strings.NoPhone);
|
||||
private var strNoInternet = WatchUi.loadResource($.Rez.Strings.NoInternet);
|
||||
private var strNoResponse = WatchUi.loadResource($.Rez.Strings.NoResponse);
|
||||
private var strNoJson = WatchUi.loadResource($.Rez.Strings.NoJson);
|
||||
private var strNoJson = WatchUi.loadResource($.Rez.Strings.NoJson);
|
||||
private var strApiFlood = WatchUi.loadResource($.Rez.Strings.ApiFlood);
|
||||
private var strApiUrlNotFound = WatchUi.loadResource($.Rez.Strings.ApiUrlNotFound);
|
||||
private var strUnhandledHttpErr = WatchUi.loadResource($.Rez.Strings.UnhandledHttpErr);
|
||||
|
||||
private var mApiKey as Lang.String;
|
||||
|
||||
function initialize() {
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
}
|
||||
|
||||
// Callback function after completing the POST request to call a service.
|
||||
//
|
||||
function onReturnCall(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String, context as Lang.Object) as Void {
|
||||
@ -123,15 +117,6 @@ class HomeAssistantService {
|
||||
}
|
||||
|
||||
function call(identifier as Lang.String, service as Lang.String) as Void {
|
||||
var options = {
|
||||
:method => Communications.HTTP_REQUEST_METHOD_POST,
|
||||
:headers => {
|
||||
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
|
||||
"Authorization" => "Bearer " + mApiKey
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON,
|
||||
:context => identifier
|
||||
};
|
||||
if (! System.getDeviceSettings().phoneConnected) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService call(): No Phone connection, skipping API call.");
|
||||
@ -144,7 +129,7 @@ class HomeAssistantService {
|
||||
ErrorView.show(strNoInternet + ".");
|
||||
} else {
|
||||
// Can't use null for substring() parameters due to API version level.
|
||||
var url = (Properties.getValue("api_url") as Lang.String) + "/services/" + service.substring(0, service.find(".")) + "/" + service.substring(service.find(".")+1, service.length());
|
||||
var url = Settings.get().getApiUrl() + "/services/" + service.substring(0, service.find(".")) + "/" + service.substring(service.find(".")+1, service.length());
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantService call() URL=" + url);
|
||||
System.println("HomeAssistantService call() service=" + service);
|
||||
@ -154,7 +139,15 @@ class HomeAssistantService {
|
||||
{
|
||||
"entity_id" => identifier
|
||||
},
|
||||
options,
|
||||
{
|
||||
:method => Communications.HTTP_REQUEST_METHOD_POST,
|
||||
:headers => {
|
||||
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
|
||||
"Authorization" => "Bearer " + Settings.get().getApiKey()
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON,
|
||||
:context => identifier
|
||||
},
|
||||
method(:onReturnCall)
|
||||
);
|
||||
if (Attention has :vibrate) {
|
||||
|
@ -35,8 +35,6 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
private var strUnavailable = WatchUi.loadResource($.Rez.Strings.Unavailable);
|
||||
private var strAvailable = WatchUi.loadResource($.Rez.Strings.Available);
|
||||
|
||||
private var mApiKey as Lang.String;
|
||||
|
||||
function initialize(
|
||||
label as Lang.String or Lang.Symbol,
|
||||
subLabel as Lang.String or Lang.Symbol or {
|
||||
@ -50,7 +48,6 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
:icon as Graphics.BitmapType or WatchUi.Drawable or Lang.Symbol
|
||||
} or Null
|
||||
) {
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
WatchUi.ToggleMenuItem.initialize(label, subLabel, identifier, enabled, options);
|
||||
}
|
||||
|
||||
@ -76,7 +73,7 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
System.println("HomeAssistantToggleMenuItem onReturnGetState() Response Data: " + data);
|
||||
}
|
||||
|
||||
var status = strUnavailable;
|
||||
var status = strUnavailable;
|
||||
switch (responseCode) {
|
||||
case Communications.BLE_HOST_TIMEOUT:
|
||||
case Communications.BLE_CONNECTION_UNAVAILABLE:
|
||||
@ -168,13 +165,6 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
}
|
||||
|
||||
function getState() as Void {
|
||||
var options = {
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:headers => {
|
||||
"Authorization" => "Bearer " + mApiKey
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
};
|
||||
if (! System.getDeviceSettings().phoneConnected) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem getState(): No Phone connection, skipping API call.");
|
||||
@ -188,14 +178,20 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
ErrorView.show(strNoInternet + ".");
|
||||
getApp().setApiStatus(strUnavailable);
|
||||
} else {
|
||||
var url = Properties.getValue("api_url") + "/states/" + mIdentifier;
|
||||
var url = Settings.get().getApiUrl() + "/states/" + mIdentifier;
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem getState() URL=" + url);
|
||||
}
|
||||
Communications.makeWebRequest(
|
||||
url,
|
||||
null,
|
||||
options,
|
||||
{
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:headers => {
|
||||
"Authorization" => "Bearer " + Settings.get().getApiKey()
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
},
|
||||
method(:onReturnGetState)
|
||||
);
|
||||
}
|
||||
@ -272,14 +268,6 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
}
|
||||
|
||||
function setState(s as Lang.Boolean) as Void {
|
||||
var options = {
|
||||
:method => Communications.HTTP_REQUEST_METHOD_POST,
|
||||
:headers => {
|
||||
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
|
||||
"Authorization" => "Bearer " + mApiKey
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
};
|
||||
if (! System.getDeviceSettings().phoneConnected) {
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem getState(): No Phone connection, skipping API call.");
|
||||
@ -297,12 +285,12 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
} else {
|
||||
// Updated SDK and got a new error
|
||||
// ERROR: venu: Cannot find symbol ':substring' on type 'PolyType<Null or $.Toybox.Lang.Object>'.
|
||||
var id = mIdentifier as Lang.String;
|
||||
var url;
|
||||
var id = mIdentifier as Lang.String;
|
||||
var url = Settings.get().getApiKey() + "/services/";
|
||||
if (s) {
|
||||
url = Properties.getValue("api_url") + "/services/" + id.substring(0, id.find(".")) + "/turn_on";
|
||||
url = url + id.substring(0, id.find(".")) + "/turn_on";
|
||||
} else {
|
||||
url = Properties.getValue("api_url") + "/services/" + id.substring(0, id.find(".")) + "/turn_off";
|
||||
url = url + id.substring(0, id.find(".")) + "/turn_off";
|
||||
}
|
||||
if (Globals.scDebug) {
|
||||
System.println("HomeAssistantToggleMenuItem setState() URL=" + url);
|
||||
@ -313,7 +301,14 @@ class HomeAssistantToggleMenuItem extends WatchUi.ToggleMenuItem {
|
||||
{
|
||||
"entity_id" => mIdentifier
|
||||
},
|
||||
options,
|
||||
{
|
||||
:method => Communications.HTTP_REQUEST_METHOD_POST,
|
||||
:headers => {
|
||||
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_JSON,
|
||||
"Authorization" => "Bearer " + Settings.get().getApiKey()
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_JSON
|
||||
},
|
||||
method(:onReturnSetState)
|
||||
);
|
||||
}
|
||||
|
@ -24,12 +24,9 @@ using Toybox.Application.Properties;
|
||||
using Toybox.WatchUi;
|
||||
|
||||
class QuitTimer extends Timer.Timer {
|
||||
private var api_timeout;
|
||||
|
||||
|
||||
function initialize() {
|
||||
Timer.Timer.initialize();
|
||||
// Timer needs delay in milliseconds.
|
||||
api_timeout = (Properties.getValue("app_timeout") as Lang.Number) * 1000;
|
||||
}
|
||||
|
||||
function exitApp() as Void {
|
||||
@ -41,6 +38,7 @@ class QuitTimer extends Timer.Timer {
|
||||
}
|
||||
|
||||
function begin() {
|
||||
var api_timeout = Settings.get().getAppTimeout(); // ms
|
||||
if (api_timeout > 0) {
|
||||
start(method(:exitApp), api_timeout, false);
|
||||
}
|
||||
|
136
source/Settings.mc
Normal file
136
source/Settings.mc
Normal file
@ -0,0 +1,136 @@
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// 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, SomeoneOnEarth, 23 November 2023
|
||||
//
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Home Assistant settings.
|
||||
//
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
||||
using Toybox.Lang;
|
||||
using Toybox.Application.Properties;
|
||||
using Toybox.WatchUi;
|
||||
using Toybox.System;
|
||||
// Battery Level Reporting
|
||||
using Toybox.Background;
|
||||
using Toybox.Time;
|
||||
|
||||
(:glance, :background)
|
||||
class Settings {
|
||||
private static var instance;
|
||||
|
||||
public static const MENU_STYLE_ICONS = 0;
|
||||
public static const MENU_STYLE_TEXT = 1;
|
||||
|
||||
private var mApiKey as Lang.String = "";
|
||||
private var mApiUrl as Lang.String = "";
|
||||
private var mConfigUrl as Lang.String = "";
|
||||
private var mAppTimeout as Lang.Number = 0; // seconds
|
||||
private var mConfirmTimeout as Lang.Number = 3; // seconds
|
||||
private var mMenuStyle as Lang.Number = MENU_STYLE_ICONS;
|
||||
private var mMenuAlignment as Lang.Number = WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_LEFT;
|
||||
private var mIsWidgetStartNoTap as Lang.Boolean = false;
|
||||
private var mIsBatteryLevelEnabled as Lang.Boolean = false;
|
||||
private var mBatteryRefreshRate as Lang.Number = 15; // minutes
|
||||
private var mIsApp as Lang.Boolean = false;
|
||||
|
||||
private function initialize() {
|
||||
mIsApp = getApp().getIsApp();
|
||||
update();
|
||||
}
|
||||
|
||||
// Called on application start and then whenever the settings are changed.
|
||||
function update() {
|
||||
mApiKey = Properties.getValue("api_key");
|
||||
mApiUrl = Properties.getValue("api_url");
|
||||
mConfigUrl = Properties.getValue("config_url");
|
||||
mAppTimeout = Properties.getValue("app_timeout");
|
||||
mConfirmTimeout = Properties.getValue("confirm_timeout");
|
||||
mMenuStyle = Properties.getValue("menu_theme");
|
||||
mMenuAlignment = Properties.getValue("menu_alignment");
|
||||
mIsWidgetStartNoTap = Properties.getValue("widget_start_no_tap");
|
||||
mIsBatteryLevelEnabled = Properties.getValue("enable_battery_level");
|
||||
mBatteryRefreshRate = Properties.getValue("battery_level_refresh_rate");
|
||||
|
||||
// Manage this inside the application or widget only (not a glance or background service process)
|
||||
if (mIsApp) {
|
||||
if (mIsBatteryLevelEnabled) {
|
||||
if ((System has :ServiceDelegate) and
|
||||
((Background.getTemporalEventRegisteredTime() == null) or
|
||||
(Background.getTemporalEventRegisteredTime() != (mBatteryRefreshRate * 60)))) {
|
||||
Background.registerForTemporalEvent(new Time.Duration(mBatteryRefreshRate * 60)); // Convert to seconds
|
||||
}
|
||||
} else {
|
||||
// Explicitly disable the background event which persists when the application closes.
|
||||
if ((System has :ServiceDelegate) and (Background.getTemporalEventRegisteredTime() != null)) {
|
||||
Background.deleteTemporalEvent();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Explicitly disable the background events for glances and ironically any use by the background service. However
|
||||
// that has been avoided more recently by not using this object in BackgroundServiceDelegate.
|
||||
if ((System has :ServiceDelegate) and (Background.getTemporalEventRegisteredTime() != null)) {
|
||||
Background.deleteTemporalEvent();
|
||||
}
|
||||
}
|
||||
if (Globals.scDebug) {
|
||||
System.println("Settings update(): getTemporalEventRegisteredTime() = " + Background.getTemporalEventRegisteredTime());
|
||||
if (Background.getTemporalEventRegisteredTime() != null) {
|
||||
System.println("Settings update(): getTemporalEventRegisteredTime().value() = " + Background.getTemporalEventRegisteredTime().value().format("%d") + " seconds");
|
||||
} else {
|
||||
System.println("Settings update(): getTemporalEventRegisteredTime() = null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function get() as Settings {
|
||||
if (instance == null) {
|
||||
instance = new Settings();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
function getApiKey() as Lang.String {
|
||||
return mApiKey;
|
||||
}
|
||||
|
||||
function getApiUrl() as Lang.String {
|
||||
return mApiUrl;
|
||||
}
|
||||
|
||||
function getConfigUrl() as Lang.String {
|
||||
return mConfigUrl;
|
||||
}
|
||||
|
||||
function getAppTimeout() as Lang.Number {
|
||||
return mAppTimeout * 1000; // Convert to milliseconds
|
||||
}
|
||||
|
||||
function getConfirmTimeout() as Lang.Number {
|
||||
return mConfirmTimeout * 1000; // Convert to milliseconds
|
||||
}
|
||||
|
||||
function getMenuStyle() as Lang.Number {
|
||||
return mMenuStyle; // Either MENU_STYLE_ICONS or MENU_STYLE_TEXT
|
||||
}
|
||||
|
||||
function getMenuAlignment() as Lang.Number {
|
||||
return mMenuAlignment; // Either WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_RIGHT or WatchUi.MenuItem.MENU_ITEM_LABEL_ALIGN_LEFT
|
||||
}
|
||||
|
||||
function getIsWidgetStartNoTap() as Lang.Boolean {
|
||||
return mIsWidgetStartNoTap;
|
||||
}
|
||||
|
||||
}
|
179
source/WebLog.mc
Normal file
179
source/WebLog.mc
Normal file
@ -0,0 +1,179 @@
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// J D Abbey & P A Abbey, 28 December 2022
|
||||
//
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// WebLog provides a logging and hence debugging aid for when the application is
|
||||
// deployed to the watch. This is only used for development and use of it must not
|
||||
// persist into a deployed version. It uses a string buffer to group log entries into
|
||||
// larger submissions in order to prevent overflow of the blue tooth stack.
|
||||
//
|
||||
//-----------------------------------------------------------------------------------
|
||||
//
|
||||
// Usage:
|
||||
// wl = new WebLog();
|
||||
// wl.clear();
|
||||
// wl.println("Debug Message");
|
||||
// wl.flush();
|
||||
//
|
||||
// https://domain.name/path/log.php
|
||||
//
|
||||
// <?php
|
||||
// $myfile = fopen("log", "a");
|
||||
// $queries = array();
|
||||
// parse_str($_SERVER['QUERY_STRING'], $queries);
|
||||
// fwrite($myfile, $queries['log']);
|
||||
// print "Success";
|
||||
// ?>
|
||||
//
|
||||
// Logs published to: https://domain.name/path/log
|
||||
//
|
||||
// https://domain.name/path/log_clear.php
|
||||
//
|
||||
// <?php
|
||||
// $myfile = fopen("log", "w");
|
||||
// fwrite($myfile, "");
|
||||
// print "Success";
|
||||
// ?>
|
||||
|
||||
using Toybox.Communications;
|
||||
using Toybox.Lang;
|
||||
using Toybox.System;
|
||||
|
||||
(:glance, :background)
|
||||
class WebLog {
|
||||
private var callsbuffer = 4 as Lang.Number;
|
||||
private var numCalls = 0 as Lang.Number;
|
||||
private var buffer = "" as Lang.String;
|
||||
|
||||
// Set the number of calls to print() before sending the buffer to the online
|
||||
// logger.
|
||||
//
|
||||
function setCallsBuffer(l as Lang.Number) {
|
||||
callsbuffer = l;
|
||||
}
|
||||
|
||||
// Get the number of calls to print() before sending the buffer to the online
|
||||
// logger.
|
||||
//
|
||||
function getCallsBuffer() as Lang.Number {
|
||||
return callsbuffer;
|
||||
}
|
||||
|
||||
// Create a debug log over the Internet to keep track of the watch's runtime
|
||||
// execution.
|
||||
//
|
||||
function print(str as Lang.String) {
|
||||
var myTime = System.getClockTime();
|
||||
buffer += myTime.hour.format("%02d") + ":" + myTime.min.format("%02d") + ":" + myTime.sec.format("%02d") + " " + str;
|
||||
numCalls++;
|
||||
if (Globals.scDebug) {
|
||||
System.println("WebLog print() str = " + str);
|
||||
}
|
||||
if (numCalls >= callsbuffer) {
|
||||
doPrint();
|
||||
}
|
||||
}
|
||||
|
||||
// Create a debug log over the Internet to keep track of the watch's runtime
|
||||
// execution. Add a new line character to the end.
|
||||
//
|
||||
function println(str as Lang.String) {
|
||||
print(str + "\n");
|
||||
}
|
||||
|
||||
// Flush the current buffer to the online logger even if it has not reach the
|
||||
// submission level set by 'callsbuffer'.
|
||||
//
|
||||
function flush() {
|
||||
if (Globals.scDebug) {
|
||||
System.println("WebLog flush()");
|
||||
}
|
||||
if (numCalls > 0) {
|
||||
doPrint();
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the submission to the online logger.
|
||||
//
|
||||
function doPrint() {
|
||||
if (Globals.scDebug) {
|
||||
System.println("WebLog doPrint()");
|
||||
System.println(buffer);
|
||||
}
|
||||
Communications.makeWebRequest(
|
||||
ClientId.webLogUrl,
|
||||
{
|
||||
"log" => buffer
|
||||
},
|
||||
{
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:headers => {
|
||||
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_URL_ENCODED
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_TEXT_PLAIN
|
||||
},
|
||||
method(:onLog)
|
||||
);
|
||||
numCalls = 0;
|
||||
buffer = "";
|
||||
}
|
||||
|
||||
// Clear the debug log over the Internet to start a new track of the watch's runtime
|
||||
// execution.
|
||||
//
|
||||
function clear() {
|
||||
if (Globals.scDebug) {
|
||||
System.println("WebLog clear()");
|
||||
}
|
||||
Communications.makeWebRequest(
|
||||
ClientId.webLogClearUrl,
|
||||
{},
|
||||
{
|
||||
:method => Communications.HTTP_REQUEST_METHOD_GET,
|
||||
:headers => {
|
||||
"Content-Type" => Communications.REQUEST_CONTENT_TYPE_URL_ENCODED
|
||||
},
|
||||
:responseType => Communications.HTTP_RESPONSE_CONTENT_TYPE_TEXT_PLAIN
|
||||
},
|
||||
method(:onClear)
|
||||
);
|
||||
numCalls = 0;
|
||||
buffer = "";
|
||||
}
|
||||
|
||||
// Callback function to print the outcome of a doPrint() method.
|
||||
//
|
||||
function onLog(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void {
|
||||
if (Globals.scDebug) {
|
||||
if (responseCode != 200) {
|
||||
System.println("WebLog onLog() Failed");
|
||||
System.println("WebLog onLog() Response Code: " + responseCode);
|
||||
System.println("WebLog onLog() Response Data: " + data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Callback function to print the outcome of a clear() method.
|
||||
//
|
||||
function onClear(responseCode as Lang.Number, data as Null or Lang.Dictionary or Lang.String) as Void {
|
||||
if (Globals.scDebug) {
|
||||
if (responseCode != 200) {
|
||||
System.println("WebLog onClear() Failed");
|
||||
System.println("WebLog onClear() Response Code: " + responseCode);
|
||||
System.println("WebLog onClear() Response Data: " + data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user