diff --git a/apps/widbaroalarm/ChangeLog b/apps/widbaroalarm/ChangeLog index ec66c5568..c12cc0d65 100644 --- a/apps/widbaroalarm/ChangeLog +++ b/apps/widbaroalarm/ChangeLog @@ -1 +1,2 @@ 0.01: Initial version +0.02: Do not warn multiple times for the same exceedance diff --git a/apps/widbaroalarm/README.md b/apps/widbaroalarm/README.md index b92a51050..fdc239170 100644 --- a/apps/widbaroalarm/README.md +++ b/apps/widbaroalarm/README.md @@ -2,10 +2,8 @@ Get a notification when the pressure reaches defined thresholds. -![Screenshot](screenshot.png) ## Settings - * Interval: check interval of sensor data in minutes. 0 to disable automatic check. * Low alarm: Toggle low alarm * Low threshold: Warn when pressure drops below this value diff --git a/apps/widbaroalarm/metadata.json b/apps/widbaroalarm/metadata.json index 0976df531..82aaab65a 100644 --- a/apps/widbaroalarm/metadata.json +++ b/apps/widbaroalarm/metadata.json @@ -2,7 +2,7 @@ "id": "widbaroalarm", "name": "Barometer alarm widget", "shortName": "Barometer alarm", - "version": "0.01", + "version": "0.02", "description": "A widget that can alarm on when the pressure reaches defined thresholds.", "icon": "widget.png", "type": "widget", diff --git a/apps/widbaroalarm/settings.js b/apps/widbaroalarm/settings.js index 1455072e4..bea6319d1 100644 --- a/apps/widbaroalarm/settings.js +++ b/apps/widbaroalarm/settings.js @@ -36,7 +36,7 @@ value: settings.min, min: 600, max: 1000, - step: 10, + step: 5, onchange: x => save("min", x), }, "High alarm": { @@ -48,9 +48,9 @@ }, "High threshold": { value: settings.max, - min: 1000, + min: 700, max: 1100, - step: 10, + step: 5, onchange: x => save("max", x), }, "Drop alarm": { diff --git a/apps/widbaroalarm/widget.js b/apps/widbaroalarm/widget.js index 7279a963a..a78f0a05c 100644 --- a/apps/widbaroalarm/widget.js +++ b/apps/widbaroalarm/widget.js @@ -1,185 +1,235 @@ (function() { - let medianPressure; - let threeHourAvrPressure; - let currentPressures = []; + let medianPressure; + let threeHourAvrPressure; + let currentPressures = []; - const LOG_FILE = "widbaroalarm.log.json"; - const SETTINGS_FILE = "widbaroalarm.json"; - const storage = require('Storage'); - let settings = Object.assign( + const LOG_FILE = "widbaroalarm.log.json"; + const SETTINGS_FILE = "widbaroalarm.json"; + const storage = require('Storage'); + + let settings; + + function loadSettings() { + settings = Object.assign( storage.readJSON("widbaroalarm.default.json", true) || {}, storage.readJSON(SETTINGS_FILE, true) || {} ); + } - function setting(key) { - return settings[key]; + loadSettings(); + + + function setting(key) { + return settings[key]; + } + + function saveSetting(key, value) { + settings[key] = value; + storage.write(SETTINGS_FILE, settings); + } + + const interval = setting("interval"); + + let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours + + function showAlarm(body, title) { + if (body == undefined) return; + + require("notify").show({ + title: title || "Pressure", + body: body, + icon: require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA")) + }); + + if (setting("buzz") && + !(storage.readJSON('setting.json', 1) || {}).quiet) { + Bangle.buzz(); } - const interval = setting("interval"); + } - let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours - function showAlarm(body, title) { - if (body == undefined) return; + function didWeAlreadyWarn(key) { + return setting(key) == undefined || setting(key) > 0; + } - require("notify").show({ - title: title || "Pressure", - body: body, - icon: require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA")) - }); - - if (setting("buzz") && - !(storage.readJSON('setting.json', 1) || {}).quiet) { - Bangle.buzz(); - } - } + function checkForAlarms(pressure) { + if (pressure == undefined || pressure <= 0) return; let alreadyWarned = false; - function checkForAlarms(pressure) { - if (pressure == undefined || pressure <= 0) return; + const ts = Math.round(Date.now() / 1000); // seconds + const d = { + "ts": ts, + "p": pressure + }; - const ts = Math.round(Date.now() / 1000); // seconds - const d = { - "ts": ts, - "p": pressure - }; - - // delete entries older than 3h - for (let i = 0; i < history3.length; i++) { - if (history3[i]["ts"] < ts - (3 * 60 * 60)) { - history3.shift(); - } - } - // delete oldest entries until we have max 50 - while (history3.length > 50) { + // delete entries older than 3h + for (let i = 0; i < history3.length; i++) { + if (history3[i]["ts"] < ts - (3 * 60 * 60)) { history3.shift(); } + } + // delete oldest entries until we have max 50 + while (history3.length > 50) { + history3.shift(); + } - history3.push(d); - // write data to storage - storage.writeJSON(LOG_FILE, history3); - - if (setting("lowalarm") && pressure <= setting("min")) { - showAlarm("Pressure low: " + Math.round(pressure) + " hPa"); - alreadyWarned = true; + if (setting("lowalarm")) { + // Is below the alarm threshold? + if (pressure <= setting("min")) { + if (!didWeAlreadyWarn("lastLowWarningTs")) { + showAlarm("Pressure low: " + Math.round(pressure) + " hPa"); + saveSetting("lastLowWarningTs", ts); + alreadyWarned = true; + } + } else { + saveSetting("lastLowWarningTs", 0); } - if (setting("highalarm") && pressure >= setting("max")) { - showAlarm("Pressure high: " + Math.round(pressure) + " hPa"); - alreadyWarned = true; + } else { + saveSetting("lastLowWarningTs", 0); + } + + if (setting("highalarm")) { + // Is above the alarm threshold? + if (pressure >= setting("max")) { + if (!didWeAlreadyWarn("lastHighWarningTs")) { + showAlarm("Pressure high: " + Math.round(pressure) + " hPa"); + saveSetting("lastHighWarningTs", ts); + alreadyWarned = true; + } + } else { + saveSetting("lastHighWarningTs", 0); } + } else { + saveSetting("lastHighWarningTs", 0); + } - if (!alreadyWarned) { - // 3h change detection - const drop3halarm = setting("drop3halarm"); - const raise3halarm = setting("raise3halarm"); - if (drop3halarm > 0 || raise3halarm > 0) { - // we need at least 30min of data for reliable detection - if (history3[0]["ts"] > ts - (30 * 60)) { - return; - } + if (!alreadyWarned) { + // 3h change detection + const drop3halarm = setting("drop3halarm"); + const raise3halarm = setting("raise3halarm"); + if (drop3halarm > 0 || raise3halarm > 0) { + // we need at least 30min of data for reliable detection + if (history3[0]["ts"] > ts - (30 * 60)) { + return; + } - // Get oldest entry: - const oldestPressure = history3[0]["p"]; - if (oldestPressure != undefined && oldestPressure > 0) { - const diff = oldestPressure - pressure; + // Get oldest entry: + const oldestPressure = history3[0]["p"]; + if (oldestPressure != undefined && oldestPressure > 0) { + const diff = oldestPressure - pressure; - // drop alarm - if (drop3halarm > 0 && oldestPressure > pressure) { - if (Math.abs(diff) > drop3halarm) { - showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + - Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure drop"); + // drop alarm + if (drop3halarm > 0 && oldestPressure > pressure && !didWeAlreadyWarn("lastHighWarningTs")) { + if (Math.abs(diff) > drop3halarm) { + showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure drop"); + saveSetting("lastDropWarningTs", ts); + } else { + saveSetting("lastDropWarningTs", ts); } + } else { + saveSetting("lastDropWarningTs", ts); } // raise alarm - if (raise3halarm > 0 && oldestPressure < pressure) { + if (raise3halarm > 0 && oldestPressure < pressure && !didWeAlreadyWarn("lastRaiseWarningTs")) { if (Math.abs(diff) > raise3halarm) { showAlarm((Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h from " + Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "Pressure raise"); + saveSetting("lastRaiseWarningTs", ts); + } else { + saveSetting("lastRaiseWarningTs", ts); + } + } else { + saveSetting("lastRaiseWarningTs", ts); } } } } + + history3.push(d); + // write data to storage + storage.writeJSON(LOG_FILE, history3); + + // calculate 3h average for widget + let sum = 0; + for (let i = 0; i < history3.length; i++) { + sum += history3[i]["p"]; + } + threeHourAvrPressure = sum / history3.length; } - // calculate 3h average for widget - let sum = 0; - for (let i = 0; i < history3.length; i++) { - sum += history3[i]["p"]; - } - threeHourAvrPressure = sum / history3.length; -} - -function baroHandler(data) { - if (data) { - const pressure = Math.round(data.pressure); - if (pressure == undefined || pressure <= 0) return; - currentPressures.push(pressure); - } -} - -/* - turn on barometer power - take 5 measurements - sort the results - take the middle one (median) - turn off barometer power -*/ -function check() { - Bangle.setBarometerPower(true, "widbaroalarm"); - setTimeout(function() { - currentPressures = []; - - Bangle.getPressure().then(baroHandler); - Bangle.getPressure().then(baroHandler); - Bangle.getPressure().then(baroHandler); - Bangle.getPressure().then(baroHandler); - Bangle.getPressure().then(baroHandler); - - setTimeout(function() { - Bangle.setBarometerPower(false, "widbaroalarm"); - - currentPressures.sort(); - - // take median value - medianPressure = currentPressures[3]; - checkForAlarms(medianPressure); - }, 1000); - }, 500); -} - -function reload() { - check(); -} - -function draw() { - g.reset(); - if (setting("show") && medianPressure != undefined) { - g.setFont("6x8", 1).setFontAlign(1, 0); - g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6); - if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { - g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); + function baroHandler(data) { + if (data) { + const pressure = Math.round(data.pressure); + if (pressure == undefined || pressure <= 0) return; + currentPressures.push(pressure); } } -} -if (global.WIDGETS != undefined && typeof WIDGETS === "object") { - WIDGETS["baroalarm"] = { - width: setting("show") ? 24 : 0, - reload: reload, - area: "tr", - draw: draw - }; -} + /* + turn on barometer power + take 5 measurements + sort the results + take the middle one (median) + turn off barometer power + */ + function check() { + Bangle.setBarometerPower(true, "widbaroalarm"); + setTimeout(function() { + currentPressures = []; -// Let's delay the first check a bit -setTimeout(function() { -check(); -if (interval > 0) { - setInterval(check, interval * 60000); -} -}, 5000); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + Bangle.getPressure().then(baroHandler); + + setTimeout(function() { + Bangle.setBarometerPower(false, "widbaroalarm"); + + currentPressures.sort(); + + // take median value + medianPressure = currentPressures[3]; + checkForAlarms(medianPressure); + }, 1000); + }, 500); + } + + function reload() { + check(); + } + + function draw() { + g.reset(); + if (setting("show") && medianPressure != undefined) { + g.setFont("6x8", 1).setFontAlign(1, 0); + g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6); + if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) { + g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10); + } + } + } + + if (global.WIDGETS != undefined && typeof WIDGETS === "object") { + WIDGETS["baroalarm"] = { + width: setting("show") ? 24 : 0, + reload: reload, + area: "tr", + draw: draw + }; + } + + // Let's delay the first check a bit + setTimeout(function() { + check(); + if (interval > 0) { + setInterval(check, interval * 60000); + } + }, 1000); })();