Show difference of last measurement to pressure average of the the last three hours and an arrow indicating the trend in the widget
parent
574736f3ff
commit
2dce374a18
|
|
@ -3,3 +3,4 @@
|
||||||
0.03: Fix crash
|
0.03: Fix crash
|
||||||
0.04: Use Prompt with dismiss and pause
|
0.04: Use Prompt with dismiss and pause
|
||||||
Improve barometer value median calculation
|
Improve barometer value median calculation
|
||||||
|
0.05: Show difference of last measurement to pressure average of the the last three hours and an arrow indicating the trend in the widget
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ Get a notification when the pressure reaches defined thresholds.
|
||||||
* Pause delay: Same as Dismiss delay but longer (useful for meetings and such). From 30 to 240 min
|
* Pause delay: Same as Dismiss delay but longer (useful for meetings and such). From 30 to 240 min
|
||||||
|
|
||||||
## Widget
|
## Widget
|
||||||
The widget shows two rows: pressure value of last measurement and pressure average of the the last three hours.
|
The widget shows two rows:
|
||||||
|
1. pressure value of last measurement
|
||||||
|
2. difference of last measurement to pressure average of the the last three hours and an arrow indicating the trend
|
||||||
|
|
||||||
## Creator
|
## Creator
|
||||||
Marco ([myxor](https://github.com/myxor))
|
Marco ([myxor](https://github.com/myxor))
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
"tags": "tool,barometer",
|
"tags": "tool,barometer",
|
||||||
"supports": ["BANGLEJS2"],
|
"supports": ["BANGLEJS2"],
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
|
"screenshots": [{"url":"screenshot-dark.png"}],
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"widbaroalarm.wid.js","url":"widget.js"},
|
{"name":"widbaroalarm.wid.js","url":"widget.js"},
|
||||||
{"name":"widbaroalarm.settings.js","url":"settings.js"},
|
{"name":"widbaroalarm.settings.js","url":"settings.js"},
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
|
|
@ -1,268 +1,290 @@
|
||||||
(function() {
|
(function() {
|
||||||
let medianPressure;
|
let medianPressure;
|
||||||
let threeHourAvrPressure;
|
let threeHourAvrPressure;
|
||||||
let currentPressures = [];
|
let currentPressures = [];
|
||||||
let stop = false; // semaphore
|
let stop = false; // semaphore
|
||||||
|
|
||||||
const LOG_FILE = "widbaroalarm.log.json";
|
const LOG_FILE = "widbaroalarm.log.json";
|
||||||
const SETTINGS_FILE = "widbaroalarm.json";
|
const SETTINGS_FILE = "widbaroalarm.json";
|
||||||
const storage = require('Storage');
|
const storage = require('Storage');
|
||||||
|
|
||||||
let settings;
|
let settings;
|
||||||
|
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
settings = Object.assign(
|
settings =
|
||||||
storage.readJSON("widbaroalarm.default.json", true) || {},
|
Object.assign(storage.readJSON("widbaroalarm.default.json", true) || {},
|
||||||
storage.readJSON(SETTINGS_FILE, true) || {}
|
storage.readJSON(SETTINGS_FILE, true) || {});
|
||||||
);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
|
function setting(key) { return settings[key]; }
|
||||||
|
|
||||||
function setting(key) {
|
function saveSetting(key, value) {
|
||||||
return settings[key];
|
settings[key] = value;
|
||||||
}
|
storage.write(SETTINGS_FILE, settings);
|
||||||
|
}
|
||||||
|
|
||||||
function saveSetting(key, value) {
|
const interval = setting("interval");
|
||||||
settings[key] = value;
|
|
||||||
storage.write(SETTINGS_FILE, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
const interval = setting("interval");
|
let history3 =
|
||||||
|
storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours
|
||||||
|
|
||||||
let history3 = storage.readJSON(LOG_FILE, true) || []; // history of recent 3 hours
|
function showAlarm(body, key) {
|
||||||
|
if (body == undefined)
|
||||||
|
return;
|
||||||
|
stop = true;
|
||||||
|
|
||||||
function showAlarm(body, key) {
|
E.showPrompt(body, {
|
||||||
if (body == undefined) return;
|
title : "Pressure alarm",
|
||||||
stop = true;
|
buttons : {"Ok" : 1, "Dismiss" : 2, "Pause" : 3}
|
||||||
|
}).then(function(v) {
|
||||||
E.showPrompt(body, {
|
|
||||||
title: "Pressure alarm",
|
|
||||||
buttons: {
|
|
||||||
"Ok": 1,
|
|
||||||
"Dismiss": 2,
|
|
||||||
"Pause": 3
|
|
||||||
}
|
|
||||||
}).then(function(v) {
|
|
||||||
const tsNow = Math.round(Date.now() / 1000); // seconds
|
|
||||||
|
|
||||||
if (v == 1) {
|
|
||||||
saveSetting(key, tsNow);
|
|
||||||
}
|
|
||||||
if (v == 2) {
|
|
||||||
// save timestamp of the future so that we do not warn again for the same event until then
|
|
||||||
saveSetting(key, tsNow + 60 * setting('dismissDelayMin'));
|
|
||||||
}
|
|
||||||
if (v == 3) {
|
|
||||||
// save timestamp of the future so that we do not warn again for the same event until then
|
|
||||||
saveSetting(key, tsNow + 60 * setting('pauseDelayMin'));
|
|
||||||
}
|
|
||||||
stop = false;
|
|
||||||
load();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (setting("buzz") &&
|
|
||||||
!(storage.readJSON('setting.json', 1) || {}).quiet) {
|
|
||||||
Bangle.buzz();
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
stop = false;
|
|
||||||
load();
|
|
||||||
}, 20000);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function doWeNeedToWarn(key) {
|
|
||||||
const tsNow = Math.round(Date.now() / 1000); // seconds
|
const tsNow = Math.round(Date.now() / 1000); // seconds
|
||||||
return setting(key) == 0 || setting(key) < tsNow;
|
|
||||||
|
if (v == 1) {
|
||||||
|
saveSetting(key, tsNow);
|
||||||
|
}
|
||||||
|
if (v == 2) {
|
||||||
|
// save timestamp of the future so that we do not warn again for the same
|
||||||
|
// event until then
|
||||||
|
saveSetting(key, tsNow + 60 * setting('dismissDelayMin'));
|
||||||
|
}
|
||||||
|
if (v == 3) {
|
||||||
|
// save timestamp of the future so that we do not warn again for the same
|
||||||
|
// event until then
|
||||||
|
saveSetting(key, tsNow + 60 * setting('pauseDelayMin'));
|
||||||
|
}
|
||||||
|
stop = false;
|
||||||
|
load();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (setting("buzz") && !(storage.readJSON('setting.json', 1) || {}).quiet) {
|
||||||
|
Bangle.buzz();
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkForAlarms(pressure) {
|
setTimeout(function() {
|
||||||
if (pressure == undefined || pressure <= 0) return;
|
stop = false;
|
||||||
|
load();
|
||||||
|
}, 20000);
|
||||||
|
}
|
||||||
|
|
||||||
let alreadyWarned = false;
|
function doWeNeedToWarn(key) {
|
||||||
|
const tsNow = Math.round(Date.now() / 1000); // seconds
|
||||||
|
return setting(key) == 0 || setting(key) < tsNow;
|
||||||
|
}
|
||||||
|
|
||||||
const ts = Math.round(Date.now() / 1000); // seconds
|
function checkForAlarms(pressure) {
|
||||||
const d = {
|
if (pressure == undefined || pressure <= 0)
|
||||||
"ts": ts,
|
return;
|
||||||
"p": pressure
|
|
||||||
};
|
|
||||||
|
|
||||||
// delete entries older than 3h
|
let alreadyWarned = false;
|
||||||
for (let i = 0; i < history3.length; i++) {
|
|
||||||
if (history3[i]["ts"] < ts - (3 * 60 * 60)) {
|
const ts = Math.round(Date.now() / 1000); // seconds
|
||||||
history3.shift();
|
const d = {"ts" : ts, "p" : pressure};
|
||||||
}
|
|
||||||
}
|
// delete entries older than 3h
|
||||||
// delete oldest entries until we have max 50
|
for (let i = 0; i < history3.length; i++) {
|
||||||
while (history3.length > 50) {
|
if (history3[i]["ts"] < ts - (3 * 60 * 60)) {
|
||||||
history3.shift();
|
history3.shift();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// delete oldest entries until we have max 50
|
||||||
|
while (history3.length > 50) {
|
||||||
|
history3.shift();
|
||||||
|
}
|
||||||
|
|
||||||
if (setting("lowalarm")) {
|
if (setting("lowalarm")) {
|
||||||
// Is below the alarm threshold?
|
// Is below the alarm threshold?
|
||||||
if (pressure <= setting("min")) {
|
if (pressure <= setting("min")) {
|
||||||
if (!doWeNeedToWarn("lastLowWarningTs")) {
|
if (!doWeNeedToWarn("lastLowWarningTs")) {
|
||||||
showAlarm("Pressure low: " + Math.round(pressure) + " hPa", "lastLowWarningTs");
|
showAlarm("Pressure low: " + Math.round(pressure) + " hPa",
|
||||||
alreadyWarned = true;
|
"lastLowWarningTs");
|
||||||
}
|
alreadyWarned = true;
|
||||||
} else {
|
|
||||||
saveSetting("lastLowWarningTs", 0);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
saveSetting("lastLowWarningTs", 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (setting("highalarm")) {
|
if (setting("highalarm")) {
|
||||||
// Is above the alarm threshold?
|
// Is above the alarm threshold?
|
||||||
if (pressure >= setting("max")) {
|
if (pressure >= setting("max")) {
|
||||||
if (doWeNeedToWarn("lastHighWarningTs")) {
|
if (doWeNeedToWarn("lastHighWarningTs")) {
|
||||||
showAlarm("Pressure high: " + Math.round(pressure) + " hPa", "lastHighWarningTs");
|
showAlarm("Pressure high: " + Math.round(pressure) + " hPa",
|
||||||
alreadyWarned = true;
|
"lastHighWarningTs");
|
||||||
}
|
alreadyWarned = true;
|
||||||
} else {
|
|
||||||
saveSetting("lastHighWarningTs", 0);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
saveSetting("lastHighWarningTs", 0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (history3.length > 0 && !alreadyWarned) {
|
if (history3.length > 0 && !alreadyWarned) {
|
||||||
// 3h change detection
|
// 3h change detection
|
||||||
const drop3halarm = setting("drop3halarm");
|
const drop3halarm = setting("drop3halarm");
|
||||||
const raise3halarm = setting("raise3halarm");
|
const raise3halarm = setting("raise3halarm");
|
||||||
if (drop3halarm > 0 || raise3halarm > 0) {
|
if (drop3halarm > 0 || raise3halarm > 0) {
|
||||||
// we need at least 30min of data for reliable detection
|
// we need at least 30min of data for reliable detection
|
||||||
const diffDateAge = Math.abs(history3[0]["ts"] - ts);
|
const diffDateAge = Math.abs(history3[0]["ts"] - ts);
|
||||||
if (diffDateAge < 10 * 60) { // todo change to 1800
|
if (diffDateAge < 10 * 60) { // todo change to 1800
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get oldest entry:
|
// Get oldest entry:
|
||||||
const oldestPressure = history3[0]["p"];
|
const oldestPressure = history3[0]["p"];
|
||||||
if (oldestPressure != undefined && oldestPressure > 0) {
|
if (oldestPressure != undefined && oldestPressure > 0) {
|
||||||
const diffPressure = Math.abs(oldestPressure - pressure);
|
const diffPressure = Math.abs(oldestPressure - pressure);
|
||||||
|
|
||||||
// drop alarm
|
// drop alarm
|
||||||
if (drop3halarm > 0 && oldestPressure > pressure) {
|
if (drop3halarm > 0 && oldestPressure > pressure) {
|
||||||
if (diffPressure > drop3halarm) {
|
if (diffPressure > drop3halarm) {
|
||||||
if (doWeNeedToWarn("lastDropWarningTs")) {
|
if (doWeNeedToWarn("lastDropWarningTs")) {
|
||||||
showAlarm((Math.round(diffPressure * 10) / 10) + " hPa/3h from " +
|
showAlarm((Math.round(diffPressure * 10) / 10) + " hPa/3h from " +
|
||||||
Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "lastDropWarningTs");
|
Math.round(oldestPressure) + " to " +
|
||||||
}
|
Math.round(pressure) + " hPa",
|
||||||
} else {
|
"lastDropWarningTs");
|
||||||
saveSetting("lastDropWarningTs", 0);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
saveSetting("lastDropWarningTs", 0);
|
saveSetting("lastDropWarningTs", 0);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
saveSetting("lastDropWarningTs", 0);
|
||||||
|
}
|
||||||
|
|
||||||
// raise alarm
|
// raise alarm
|
||||||
if (raise3halarm > 0 && oldestPressure < pressure) {
|
if (raise3halarm > 0 && oldestPressure < pressure) {
|
||||||
if (diffPressure > raise3halarm) {
|
if (diffPressure > raise3halarm) {
|
||||||
if (doWeNeedToWarn("lastRaiseWarningTs")) {
|
if (doWeNeedToWarn("lastRaiseWarningTs")) {
|
||||||
showAlarm((Math.round(diffPressure * 10) / 10) + " hPa/3h from " +
|
showAlarm((Math.round(diffPressure * 10) / 10) + " hPa/3h from " +
|
||||||
Math.round(oldestPressure) + " to " + Math.round(pressure) + " hPa", "lastRaiseWarningTs");
|
Math.round(oldestPressure) + " to " +
|
||||||
}
|
Math.round(pressure) + " hPa",
|
||||||
} else {
|
"lastRaiseWarningTs");
|
||||||
saveSetting("lastRaiseWarningTs", 0);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
saveSetting("lastRaiseWarningTs", 0);
|
saveSetting("lastRaiseWarningTs", 0);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
saveSetting("lastRaiseWarningTs", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
history3.push(d);
|
history3.push(d);
|
||||||
// write data to storage
|
// write data to storage
|
||||||
storage.writeJSON(LOG_FILE, history3);
|
storage.writeJSON(LOG_FILE, history3);
|
||||||
|
|
||||||
// calculate 3h average for widget
|
calculcate3hAveragePressure();
|
||||||
if (history3.length > 0) {
|
}
|
||||||
let sum = 0;
|
|
||||||
for (let i = 0; i < history3.length; i++) {
|
function calculcate3hAveragePressure() {
|
||||||
sum += history3[i]["p"];
|
if (history3 != undefined && history3.length > 0) {
|
||||||
}
|
let sum = 0;
|
||||||
threeHourAvrPressure = sum / history3.length;
|
for (let i = 0; i < history3.length; i++) {
|
||||||
} else {
|
sum += history3[i]["p"];
|
||||||
threeHourAvrPressure = undefined;
|
|
||||||
}
|
}
|
||||||
|
threeHourAvrPressure = sum / history3.length;
|
||||||
|
} else {
|
||||||
|
threeHourAvrPressure = undefined;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
turn on barometer power
|
||||||
|
take multiple measurements
|
||||||
|
sort the results
|
||||||
|
take the middle one (median)
|
||||||
|
turn off barometer power
|
||||||
|
*/
|
||||||
|
function check() {
|
||||||
|
if (stop)
|
||||||
|
return;
|
||||||
|
const MEDIANLENGTH = 20;
|
||||||
|
Bangle.setBarometerPower(true, "widbaroalarm");
|
||||||
|
Bangle.on('pressure', function(e) {
|
||||||
|
while (currentPressures.length > MEDIANLENGTH)
|
||||||
|
currentPressures.pop();
|
||||||
|
currentPressures.unshift(e.pressure);
|
||||||
|
median = currentPressures.slice().sort();
|
||||||
|
|
||||||
/*
|
if (median.length > 10) {
|
||||||
turn on barometer power
|
var mid = median.length >> 1;
|
||||||
take multiple measurements
|
medianPressure = Math.round(E.sum(median.slice(mid - 4, mid + 5)) / 9);
|
||||||
sort the results
|
if (medianPressure > 0) {
|
||||||
take the middle one (median)
|
turnOff();
|
||||||
turn off barometer power
|
checkForAlarms(medianPressure);
|
||||||
*/
|
|
||||||
function check() {
|
|
||||||
if (stop) return;
|
|
||||||
const MEDIANLENGTH = 20;
|
|
||||||
Bangle.setBarometerPower(true, "widbaroalarm");
|
|
||||||
Bangle.on('pressure', function(e) {
|
|
||||||
while (currentPressures.length > MEDIANLENGTH) currentPressures.pop();
|
|
||||||
currentPressures.unshift(e.pressure);
|
|
||||||
median = currentPressures.slice().sort();
|
|
||||||
|
|
||||||
if (median.length > 10) {
|
|
||||||
var mid = median.length >> 1;
|
|
||||||
medianPressure = Math.round(E.sum(median.slice(mid - 4, mid + 5)) / 9);
|
|
||||||
if (medianPressure > 0) {
|
|
||||||
turnOff();
|
|
||||||
checkForAlarms(medianPressure);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
setTimeout(function() {
|
|
||||||
turnOff();
|
|
||||||
}, 10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function turnOff() {
|
|
||||||
if (Bangle.isBarometerOn())
|
|
||||||
Bangle.setBarometerPower(false, "widbaroalarm");
|
|
||||||
}
|
|
||||||
|
|
||||||
function reload() {
|
|
||||||
check();
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw() {
|
|
||||||
if (global.WIDGETS != undefined && typeof global.WIDGETS === "object") {
|
|
||||||
global.WIDGETS["baroalarm"] = {
|
|
||||||
width: setting("show") ? 24 : 0,
|
|
||||||
reload: reload,
|
|
||||||
area: "tr",
|
|
||||||
draw: draw
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
g.reset();
|
});
|
||||||
if (setting("show")) {
|
|
||||||
|
setTimeout(function() { turnOff(); }, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function turnOff() {
|
||||||
|
if (Bangle.isBarometerOn())
|
||||||
|
Bangle.setBarometerPower(false, "widbaroalarm");
|
||||||
|
}
|
||||||
|
|
||||||
|
function reload() { check(); }
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
if (global.WIDGETS != undefined && typeof global.WIDGETS === "object") {
|
||||||
|
global.WIDGETS["baroalarm"] = {
|
||||||
|
width : setting("show") ? 24 : 0,
|
||||||
|
reload : reload,
|
||||||
|
area : "tr",
|
||||||
|
draw : draw
|
||||||
|
};
|
||||||
|
}
|
||||||
|
g.reset();
|
||||||
|
if (setting("show")) {
|
||||||
|
g.setFont("6x8", 1).setFontAlign(1, 0);
|
||||||
|
const x = this.x, y = this.y;
|
||||||
|
if (medianPressure == undefined) {
|
||||||
|
|
||||||
|
// trigger a new check
|
||||||
|
check();
|
||||||
|
|
||||||
|
// lets load last value from log (if available)
|
||||||
|
if (history3.length > 0) {
|
||||||
|
medianPressure = history3[history3.length - 1]["p"];
|
||||||
|
}
|
||||||
|
|
||||||
|
g.drawString("...", x + 24, y + 6);
|
||||||
g.setFont("6x8", 1).setFontAlign(1, 0);
|
g.setFont("6x8", 1).setFontAlign(1, 0);
|
||||||
if (medianPressure == undefined) {
|
g.drawString(Math.round(medianPressure), x + 24, y + 6);
|
||||||
check();
|
} else {
|
||||||
const x = this.x,
|
g.drawString(Math.round(medianPressure), x + 24, y + 6);
|
||||||
y = this.y;
|
}
|
||||||
g.drawString("...", x + 24, y + 6);
|
|
||||||
setTimeout(function() {
|
|
||||||
g.setFont("6x8", 1).setFontAlign(1, 0);
|
|
||||||
g.drawString(Math.round(medianPressure), x + 24, y + 6);
|
|
||||||
}, 10000);
|
|
||||||
} else {
|
|
||||||
g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (threeHourAvrPressure != undefined && threeHourAvrPressure > 0) {
|
if (threeHourAvrPressure == undefined) {
|
||||||
g.drawString(Math.round(threeHourAvrPressure), this.x + 24, this.y + 6 + 10);
|
calculcate3hAveragePressure();
|
||||||
|
}
|
||||||
|
if (threeHourAvrPressure != undefined) {
|
||||||
|
if (medianPressure != undefined) {
|
||||||
|
let icon;
|
||||||
|
|
||||||
|
const diff = threeHourAvrPressure - medianPressure;
|
||||||
|
|
||||||
|
if (diff == 0) {
|
||||||
|
icon = atob("DAyBAAAAAAAAIAEAGD+AEAIAAAAAAA=="); // allow right
|
||||||
|
} else {
|
||||||
|
if (diff < 0) {
|
||||||
|
icon = atob("DAyBAAAAAAAAfAHALATAgBAAAAAAAA=="); // arrow up
|
||||||
|
} else {
|
||||||
|
icon = atob("DAyBAAAAAAABAAgATALAHAHAeAAAAA=="); // arrow down
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g.drawImage(icon, x, y + 6 + 4);
|
||||||
|
g.drawString((diff < 0 ? "+" : "-" ) + Math.round(diff), x + 24, y + 6 + 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (interval > 0) {
|
if (interval > 0) {
|
||||||
setInterval(check, interval * 60000);
|
setInterval(check, interval * 60000);
|
||||||
}
|
}
|
||||||
draw();
|
draw();
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue