1
0
Fork 0
BangleApps/apps/widbaroalarm/widget.js

311 lines
8.5 KiB
JavaScript
Raw Normal View History

(function() {
let medianPressure;
let threeHourAvrPressure;
let currentPressures = [];
let stop = false; // semaphore
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) || {});
}
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
2022-05-26 17:13:40 +00:00
function showAlarm(body, key, type) {
if (body == undefined)
return;
stop = true;
E.showPrompt(body, {
title : "Pressure " + (type != undefined ? type : "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();
});
2022-05-26 18:07:15 +00:00
if (setting("buzz") && !(storage.readJSON('setting.json', 1) || {}).quiet) {
Bangle.buzz();
}
setTimeout(function() {
stop = false;
load();
}, 20000);
}
2022-06-22 13:14:18 +00:00
/*
* returns true if an alarm should be triggered
*/
2022-06-23 09:43:28 +00:00
function doWeNeedToAlarm(key) {
const tsNow = Math.round(Date.now() / 1000); // seconds
return setting(key) == undefined || setting(key) == 0 || tsNow > setting(key);
}
function isValidPressureValue(pressure) {
if (pressure == undefined || pressure <= 0)
return false;
return pressure > 800 && pressure < 1200; // very rough values
}
2022-06-23 09:43:28 +00:00
function handlePressureValue(pressure) {
if (pressure == undefined || pressure <= 0)
return;
const ts = Math.round(Date.now() / 1000); // seconds
const d = {"ts" : ts, "p" : pressure};
2022-06-23 09:43:28 +00:00
history3.push(d);
// delete oldest entries until we have max 50
while (history3.length > 50) {
history3.shift();
}
// delete entries older than 3h
for (let i = 0; i < history3.length; i++) {
if (history3[i]["ts"] < ts - (3 * 60 * 60)) {
history3.shift();
} else {
break;
}
}
2022-06-23 09:43:28 +00:00
// write data to storage
storage.writeJSON(LOG_FILE, history3);
calculcate3hAveragePressure();
if (setting("lowalarm") || setting("highalarm") || setting("drop3halarm") ||
setting("raise3halarm")) {
checkForAlarms(pressure, ts);
}
}
function checkForAlarms(pressure, ts) {
let alreadyWarned = false;
if (setting("lowalarm")) {
// Is below the alarm threshold?
if (pressure <= setting("min")) {
2022-06-23 09:43:28 +00:00
if (!doWeNeedToAlarm("lowWarnTs")) {
showAlarm("Pressure low: " + Math.round(pressure) + " hPa", "lowWarnTs",
"low");
alreadyWarned = true;
}
} else {
2022-06-22 13:14:18 +00:00
saveSetting("lowWarnTs", 0);
}
}
if (setting("highalarm")) {
// Is above the alarm threshold?
if (pressure >= setting("max")) {
2022-06-23 09:43:28 +00:00
if (doWeNeedToAlarm("highWarnTs")) {
showAlarm("Pressure high: " + Math.round(pressure) + " hPa",
"highWarnTs", "high");
alreadyWarned = true;
}
} else {
2022-06-22 13:14:18 +00:00
saveSetting("highWarnTs", 0);
}
}
if (history3.length > 0 && !alreadyWarned) {
// 3h change detection
const drop3halarm = setting("drop3halarm");
const raise3halarm = setting("raise3halarm");
if (drop3halarm > 0 || raise3halarm > 0) {
2022-06-22 13:14:18 +00:00
// we need at least 30 minutes of data for reliable detection
const diffDateAge = Math.abs(history3[0]["ts"] - ts);
if (diffDateAge > 30 * 60) {
// Get oldest entry:
const oldestPressure = history3[0]["p"];
if (oldestPressure != undefined && oldestPressure > 0) {
const diffPressure = Math.abs(oldestPressure - pressure);
// drop alarm
if (drop3halarm > 0 && oldestPressure > pressure) {
if (diffPressure >= drop3halarm) {
2022-06-23 09:43:28 +00:00
if (doWeNeedToAlarm("dropWarnTs")) {
showAlarm((Math.round(diffPressure * 10) / 10) +
" hPa/3h from " + Math.round(oldestPressure) +
" to " + Math.round(pressure) + " hPa",
"dropWarnTs", "drop");
}
} else {
if (ts > setting("dropWarnTs"))
saveSetting("dropWarnTs", 0);
}
} else {
2022-06-22 13:14:18 +00:00
if (ts > setting("dropWarnTs"))
saveSetting("dropWarnTs", 0);
}
// raise alarm
if (raise3halarm > 0 && oldestPressure < pressure) {
if (diffPressure >= raise3halarm) {
2022-06-23 09:43:28 +00:00
if (doWeNeedToAlarm("raiseWarnTs")) {
showAlarm((Math.round(diffPressure * 10) / 10) +
" hPa/3h from " + Math.round(oldestPressure) +
" to " + Math.round(pressure) + " hPa",
"raiseWarnTs", "raise");
}
} else {
if (ts > setting("raiseWarnTs"))
saveSetting("raiseWarnTs", 0);
}
} else {
2022-06-22 13:14:18 +00:00
if (ts > setting("raiseWarnTs"))
saveSetting("raiseWarnTs", 0);
}
}
}
}
}
}
function calculcate3hAveragePressure() {
if (history3 != undefined && history3.length > 0) {
let sum = 0;
for (let i = 0; i < history3.length; i++) {
sum += history3[i]["p"];
}
threeHourAvrPressure = sum / history3.length;
} else {
threeHourAvrPressure = undefined;
}
}
function barometerPressureHandler(e) {
const MEDIANLENGTH = 20;
while (currentPressures.length > MEDIANLENGTH)
currentPressures.pop();
const pressure = e.pressure;
if (isValidPressureValue(pressure)) {
currentPressures.unshift(pressure);
2024-03-13 10:51:40 +00:00
let 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();
WIDGETS.baroalarm.draw();
handlePressureValue(medianPressure);
}
}
}
}
/*
turn on barometer power
take multiple measurements
sort the results
take the middle one (median)
turn off barometer power
*/
2022-06-23 09:43:28 +00:00
function getPressureValue() {
if (stop) return;
Bangle.setBarometerPower(true, "widbaroalarm");
Bangle.on('pressure', barometerPressureHandler);
setTimeout(turnOff, 30000);
}
function turnOff() {
Bangle.removeListener('pressure', barometerPressureHandler);
Bangle.setBarometerPower(false, "widbaroalarm");
}
function draw() {
g.reset();
if (this.x == undefined || this.y != 0)
return; // widget not yet there
g.clearRect(this.x, this.y, this.x + this.width - 1, this.y + 23);
if (setting("show")) {
g.setFont("6x8", 1).setFontAlign(1, 0);
if (medianPressure == undefined) {
// lets load last value from log (if available)
if (history3.length > 0) {
medianPressure = history3[history3.length - 1]["p"];
g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6);
} else {
g.drawString("...", this.x + 24, this.y + 6);
}
} else {
g.drawString(Math.round(medianPressure), this.x + 24, this.y + 6);
}
if (threeHourAvrPressure == undefined) {
calculcate3hAveragePressure();
2022-06-22 12:25:46 +00:00
}
if (threeHourAvrPressure != undefined) {
if (medianPressure != undefined) {
2022-06-22 12:25:46 +00:00
const diff = Math.round(medianPressure - threeHourAvrPressure);
g.drawString((diff > 0 ? "+" : "") + diff, this.x + 24,
this.y + 6 + 10);
}
}
}
}
WIDGETS["baroalarm"] = {
width : setting("show") ? 24 : 0,
area : "tr",
draw : draw
};
// delay pressure measurement by interval-lastrun
const lastRun = history3.length > 0 ? history3[history3.length-1].ts : 0;
const lastRunAgo = Math.round(Date.now() / 1000) - lastRun;
let diffNextRun = interval*60-lastRunAgo;
if (diffNextRun < 0) {
diffNextRun = 0; // run asap
}
setTimeout(() => {
if (interval > 0) {
setInterval(getPressureValue, interval * 60000);
}
getPressureValue();
}, diffNextRun*1000);
})();