mirror of
https://github.com/house-of-abbey/GarminHomeAssistant.git
synced 2026-02-03 03:28:12 +00:00
Fix to prevent out of memory error in a glance
This commit also includes a minor code tidy for constants, to make their format consistent.
This commit is contained in:
@@ -27,6 +27,8 @@ using Toybox.Timer;
|
|||||||
//
|
//
|
||||||
(:glance, :background)
|
(:glance, :background)
|
||||||
class HomeAssistantApp extends Application.AppBase {
|
class HomeAssistantApp extends Application.AppBase {
|
||||||
|
static const scStorageKeyMenu as Lang.String = "menu";
|
||||||
|
|
||||||
private var mHasToast as Lang.Boolean = false;
|
private var mHasToast as Lang.Boolean = false;
|
||||||
private var mApiStatus as Lang.String?;
|
private var mApiStatus as Lang.String?;
|
||||||
private var mMenuStatus as Lang.String?;
|
private var mMenuStatus as Lang.String?;
|
||||||
@@ -207,7 +209,15 @@ class HomeAssistantApp extends Application.AppBase {
|
|||||||
mMenuStatus = WatchUi.loadResource($.Rez.Strings.Unavailable) as Lang.String;
|
mMenuStatus = WatchUi.loadResource($.Rez.Strings.Unavailable) as Lang.String;
|
||||||
} else {
|
} else {
|
||||||
if (Settings.getCacheConfig()) {
|
if (Settings.getCacheConfig()) {
|
||||||
Storage.setValue("menu", data as Lang.Dictionary);
|
// var stats = System.getSystemStats(); // stats.* values in bytes
|
||||||
|
// System.println("HomeAssistantApp onReturnFetchMenuConfig() Memory: total=" + stats.totalMemory + ", used=" + stats.usedMemory + ", free=" + stats.freeMemory);
|
||||||
|
if (mIsApp) {
|
||||||
|
// This call can crash a glance with "Error: Out Of Memory Error"
|
||||||
|
// https://forums.garmin.com/developer/connect-iq/i/bug-reports/storage-setvalue-should-handle-memory-limits-gracefully
|
||||||
|
// "Keys and values are limited to 8 KB each, and a total of 128 KB of storage is available."
|
||||||
|
// "Storage.setValue() fails with an uncatchable out-of-memory error."
|
||||||
|
Storage.setValue(scStorageKeyMenu, data as Lang.Dictionary);
|
||||||
|
}
|
||||||
mMenuStatus = WatchUi.loadResource($.Rez.Strings.Cached) as Lang.String;
|
mMenuStatus = WatchUi.loadResource($.Rez.Strings.Cached) as Lang.String;
|
||||||
} else {
|
} else {
|
||||||
mMenuStatus = WatchUi.loadResource($.Rez.Strings.Available) as Lang.String;
|
mMenuStatus = WatchUi.loadResource($.Rez.Strings.Available) as Lang.String;
|
||||||
@@ -246,7 +256,7 @@ class HomeAssistantApp extends Application.AppBase {
|
|||||||
if (Settings.getClearCache() || !Settings.getCacheConfig()) {
|
if (Settings.getClearCache() || !Settings.getCacheConfig()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (Storage.getValue("menu") as Lang.Dictionary) != null;
|
return (Storage.getValue(scStorageKeyMenu) as Lang.Dictionary) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Fetch the menu configuration over HTTPS, which might be locally cached.
|
//! Fetch the menu configuration over HTTPS, which might be locally cached.
|
||||||
@@ -260,10 +270,10 @@ class HomeAssistantApp extends Application.AppBase {
|
|||||||
mMenuStatus = WatchUi.loadResource($.Rez.Strings.Unconfigured) as Lang.String;
|
mMenuStatus = WatchUi.loadResource($.Rez.Strings.Unconfigured) as Lang.String;
|
||||||
WatchUi.requestUpdate();
|
WatchUi.requestUpdate();
|
||||||
} else {
|
} else {
|
||||||
var menu = Storage.getValue("menu") as Lang.Dictionary;
|
var menu = Storage.getValue(scStorageKeyMenu) as Lang.Dictionary;
|
||||||
if (menu != null and (Settings.getClearCache() || !Settings.getCacheConfig())) {
|
if (menu != null and (Settings.getClearCache() || !Settings.getCacheConfig())) {
|
||||||
// System.println("HomeAssistantApp fetchMenuConfig(): Clearing cached menu on user request.");
|
// System.println("HomeAssistantApp fetchMenuConfig(): Clearing cached menu on user request.");
|
||||||
Storage.deleteValue("menu");
|
Storage.deleteValue(scStorageKeyMenu);
|
||||||
menu = null;
|
menu = null;
|
||||||
Settings.unsetClearCache();
|
Settings.unsetClearCache();
|
||||||
}
|
}
|
||||||
@@ -524,10 +534,10 @@ class HomeAssistantApp extends Application.AppBase {
|
|||||||
case 200:
|
case 200:
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
// 'menu' will be null if caching has just been enabled, but not yet cached locally.
|
// 'menu' will be null if caching has just been enabled, but not yet cached locally.
|
||||||
var menu = Storage.getValue("menu") as Lang.Dictionary;
|
var menu = Storage.getValue(scStorageKeyMenu) as Lang.Dictionary;
|
||||||
if (menu == null || !structuralEquals(data, menu)) {
|
if (menu == null || !structuralEquals(data, menu)) {
|
||||||
// System.println("HomeAssistantApp onReturnCheckMenuConfig() New menu found.");
|
// System.println("HomeAssistantApp onReturnCheckMenuConfig() New menu found.");
|
||||||
Storage.setValue("menu", data as Lang.Dictionary);
|
Storage.setValue(scStorageKeyMenu, data as Lang.Dictionary);
|
||||||
if (menu != null) {
|
if (menu != null) {
|
||||||
// Notify the the user we have just got a newer menu file
|
// Notify the the user we have just got a newer menu file
|
||||||
var toast = WatchUi.loadResource($.Rez.Strings.MenuUpdated) as Lang.String;
|
var toast = WatchUi.loadResource($.Rez.Strings.MenuUpdated) as Lang.String;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class PinDigit extends WatchUi.Selectable {
|
|||||||
//
|
//
|
||||||
function initialize(digit as Lang.Number, stepX as Lang.Number, stepY as Lang.Number) {
|
function initialize(digit as Lang.Number, stepX as Lang.Number, stepY as Lang.Number) {
|
||||||
var marginX = stepX * 0.05; // 5% margin on all sides
|
var marginX = stepX * 0.05; // 5% margin on all sides
|
||||||
var marginY = stepY * 0.05;
|
var marginY = stepY * 0.05;
|
||||||
var x = (digit == 0) ? stepX : stepX * ((digit+2) % 3); // layout '0' in 2nd col, others ltr in 3 columns
|
var x = (digit == 0) ? stepX : stepX * ((digit+2) % 3); // layout '0' in 2nd col, others ltr in 3 columns
|
||||||
x += marginX + HomeAssistantPinConfirmationView.MARGIN_X;
|
x += marginX + HomeAssistantPinConfirmationView.MARGIN_X;
|
||||||
var y = (digit == 0) ? stepY * 4 : (digit <= 3) ? stepY : (digit <=6) ? stepY * 2 : stepY * 3; // layout '0' in bottom row (5), others top to bottom in 3 rows (2-4) (row 1 is reserved for masked pin)
|
var y = (digit == 0) ? stepY * 4 : (digit <= 3) ? stepY : (digit <=6) ? stepY * 2 : stepY * 3; // layout '0' in bottom row (5), others top to bottom in 3 rows (2-4) (row 1 is reserved for masked pin)
|
||||||
@@ -216,7 +216,7 @@ class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
|||||||
mFailures = new PinFailures();
|
mFailures = new PinFailures();
|
||||||
if (mFailures.isLocked()) {
|
if (mFailures.isLocked()) {
|
||||||
var msg = WatchUi.loadResource($.Rez.Strings.PinInputLocked) + " " +
|
var msg = WatchUi.loadResource($.Rez.Strings.PinInputLocked) + " " +
|
||||||
mFailures.getLockedUntilSeconds() + " " +
|
mFailures.getLockedUntilSeconds() + " " +
|
||||||
WatchUi.loadResource($.Rez.Strings.Seconds);
|
WatchUi.loadResource($.Rez.Strings.Seconds);
|
||||||
WatchUi.showToast(msg, {});
|
WatchUi.showToast(msg, {});
|
||||||
}
|
}
|
||||||
@@ -298,7 +298,7 @@ class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
|||||||
if (mTimer != null) {
|
if (mTimer != null) {
|
||||||
mTimer.stop();
|
mTimer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
WatchUi.popView(WatchUi.SLIDE_RIGHT);
|
WatchUi.popView(WatchUi.SLIDE_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,7 +310,7 @@ class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
|||||||
if (Attention has :vibrate && Settings.getVibrate()) {
|
if (Attention has :vibrate && Settings.getVibrate()) {
|
||||||
Attention.vibrate([
|
Attention.vibrate([
|
||||||
new Attention.VibeProfile(100, 100),
|
new Attention.VibeProfile(100, 100),
|
||||||
new Attention.VibeProfile( 0, 200),
|
new Attention.VibeProfile( 0, 200),
|
||||||
new Attention.VibeProfile( 75, 100),
|
new Attention.VibeProfile( 75, 100),
|
||||||
new Attention.VibeProfile( 0, 200),
|
new Attention.VibeProfile( 0, 200),
|
||||||
new Attention.VibeProfile( 50, 100),
|
new Attention.VibeProfile( 50, 100),
|
||||||
@@ -337,10 +337,10 @@ class HomeAssistantPinConfirmationDelegate extends WatchUi.BehaviorDelegate {
|
|||||||
//! Manage PIN entry failures to try and prevent brute force exhaustion by inserting delays in retries.
|
//! Manage PIN entry failures to try and prevent brute force exhaustion by inserting delays in retries.
|
||||||
//
|
//
|
||||||
class PinFailures {
|
class PinFailures {
|
||||||
|
|
||||||
const STORAGE_KEY_FAILURES as Lang.String = "pin_failures";
|
static const scStorageKeyFailures as Lang.String = "pin_failures";
|
||||||
const STORAGE_KEY_LOCKED as Lang.String = "pin_locked";
|
static const scStorageKeyLocked as Lang.String = "pin_locked";
|
||||||
|
|
||||||
private var mFailures as Lang.Array<Lang.Number>;
|
private var mFailures as Lang.Array<Lang.Number>;
|
||||||
private var mLockedUntil as Lang.Number?;
|
private var mLockedUntil as Lang.Number?;
|
||||||
|
|
||||||
@@ -348,9 +348,9 @@ class PinFailures {
|
|||||||
//
|
//
|
||||||
function initialize() {
|
function initialize() {
|
||||||
// System.println("PinFailures initialize() Initializing PIN failures from storage");
|
// System.println("PinFailures initialize() Initializing PIN failures from storage");
|
||||||
var failures = Application.Storage.getValue(PinFailures.STORAGE_KEY_FAILURES);
|
var failures = Application.Storage.getValue(scStorageKeyFailures);
|
||||||
mFailures = (failures == null) ? [] : failures;
|
mFailures = (failures == null) ? [] : failures;
|
||||||
mLockedUntil = Application.Storage.getValue(PinFailures.STORAGE_KEY_LOCKED);
|
mLockedUntil = Application.Storage.getValue(scStorageKeyLocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Record a PIN entry failure. If too many have occurred lock the application.
|
//! Record a PIN entry failure. If too many have occurred lock the application.
|
||||||
@@ -368,11 +368,11 @@ class PinFailures {
|
|||||||
} else {
|
} else {
|
||||||
mFailures = [];
|
mFailures = [];
|
||||||
mLockedUntil = Time.now().add(new Time.Duration(Globals.scPinLockTimeMinutes * Time.Gregorian.SECONDS_PER_MINUTE)).value();
|
mLockedUntil = Time.now().add(new Time.Duration(Globals.scPinLockTimeMinutes * Time.Gregorian.SECONDS_PER_MINUTE)).value();
|
||||||
Application.Storage.setValue(STORAGE_KEY_LOCKED, mLockedUntil);
|
Application.Storage.setValue(scStorageKeyLocked, mLockedUntil);
|
||||||
// System.println("PinFailures addFailure() Locked until " + mLockedUntil);
|
// System.println("PinFailures addFailure() Locked until " + mLockedUntil);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Application.Storage.setValue(STORAGE_KEY_FAILURES, mFailures);
|
Application.Storage.setValue(scStorageKeyFailures, mFailures);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Clear the record of previous PIN entry failures, e.g. because the correct PIN has now been entered
|
//! Clear the record of previous PIN entry failures, e.g. because the correct PIN has now been entered
|
||||||
@@ -382,8 +382,8 @@ class PinFailures {
|
|||||||
// System.println("PinFailures reset() Resetting failures");
|
// System.println("PinFailures reset() Resetting failures");
|
||||||
mFailures = [];
|
mFailures = [];
|
||||||
mLockedUntil = null;
|
mLockedUntil = null;
|
||||||
Application.Storage.deleteValue(STORAGE_KEY_FAILURES);
|
Application.Storage.deleteValue(scStorageKeyFailures);
|
||||||
Application.Storage.deleteValue(STORAGE_KEY_LOCKED);
|
Application.Storage.deleteValue(scStorageKeyLocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Retrieve the remaining time the application must be locked out for.
|
//! Retrieve the remaining time the application must be locked out for.
|
||||||
@@ -399,12 +399,12 @@ class PinFailures {
|
|||||||
//
|
//
|
||||||
function isLocked() as Lang.Boolean {
|
function isLocked() as Lang.Boolean {
|
||||||
if (mLockedUntil == null) {
|
if (mLockedUntil == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var isLocked = new Time.Moment(Time.now().value()).lessThan(new Time.Moment(mLockedUntil));
|
var isLocked = new Time.Moment(Time.now().value()).lessThan(new Time.Moment(mLockedUntil));
|
||||||
if (!isLocked) {
|
if (!isLocked) {
|
||||||
mLockedUntil = null;
|
mLockedUntil = null;
|
||||||
Application.Storage.deleteValue(STORAGE_KEY_LOCKED);
|
Application.Storage.deleteValue(scStorageKeyLocked);
|
||||||
}
|
}
|
||||||
return isLocked;
|
return isLocked;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ using Toybox.Time;
|
|||||||
//
|
//
|
||||||
(:glance, :background)
|
(:glance, :background)
|
||||||
class Settings {
|
class Settings {
|
||||||
|
static const scStorageKeySensorsEn as Lang.String = "sensors_enabled";
|
||||||
|
|
||||||
private static var mApiKey as Lang.String? = "";
|
private static var mApiKey as Lang.String? = "";
|
||||||
private static var mWebhookId as Lang.String? = "";
|
private static var mWebhookId as Lang.String? = "";
|
||||||
private static var mApiUrl as Lang.String? = "";
|
private static var mApiUrl as Lang.String? = "";
|
||||||
@@ -115,9 +117,9 @@ class Settings {
|
|||||||
} else {
|
} else {
|
||||||
// System.println("Settings update(): Doing just sensor creation.");
|
// System.println("Settings update(): Doing just sensor creation.");
|
||||||
// We already have a Webhook ID, so just enable or disable the sensor in Home Assistant.
|
// We already have a Webhook ID, so just enable or disable the sensor in Home Assistant.
|
||||||
// Storage.getValue("sensors_enabled") returns true, false, or null
|
// Storage.getValue(scStorageKeySensorsEn) returns true, false, or null
|
||||||
if (mIsSensorsEnabled != Storage.getValue("sensors_enabled")) {
|
if (mIsSensorsEnabled != Storage.getValue(scStorageKeySensorsEn)) {
|
||||||
Storage.setValue("sensors_enabled", mIsSensorsEnabled);
|
Storage.setValue(scStorageKeySensorsEn, mIsSensorsEnabled);
|
||||||
mWebhookManager.registerWebhookSensors();
|
mWebhookManager.registerWebhookSensors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user