Merge pull request #1546 from myxor/baroalarm

Barometer Alarm Widget
pull/1549/head
Gordon Williams 2022-03-08 10:36:34 +00:00 committed by GitHub
commit a64f6dbdcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 337 additions and 0 deletions

View File

@ -0,0 +1 @@
0.01: Initial version

View File

@ -0,0 +1,26 @@
# Barometer alarm widget
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
* High alarm: Toggle high alarm
* High threshold: Warn when pressure exceeds above this value
* Drop alarm: Warn when pressure drops more than this value in the recent 3 hours (having at least 30 min of data)
0 to disable this alarm.
* Raise alarm: Warn when pressure raises more than this value in the recent 3 hours (having at least 30 min of data)
0 to disable this alarm.
* Show widget: Enable/disable widget visibility
* Buzz on alarm: Enable/disable buzzer on alarm
## Widget
The widget shows two rows: pressure value of last measurement and pressure average of the the last three hours.
## Creator
Marco ([myxor](https://github.com/myxor))

View File

@ -0,0 +1,11 @@
{
"buzz": true,
"lowalarm": false,
"min": 950,
"highalarm": false,
"max": 1030,
"drop3halarm": 2,
"raise3halarm": 0,
"show": true,
"interval": 15
}

View File

@ -0,0 +1,19 @@
{
"id": "widbaroalarm",
"name": "Barometer alarm widget",
"shortName": "Barometer alarm",
"version": "0.01",
"description": "A widget that can alarm on when the pressure reaches defined thresholds.",
"icon": "widget.png",
"type": "widget",
"tags": "tool,barometer",
"supports": ["BANGLEJS2"],
"dependencies": {"notify":"type"},
"readme": "README.md",
"storage": [
{"name":"widbaroalarm.wid.js","url":"widget.js"},
{"name":"widbaroalarm.settings.js","url":"settings.js"},
{"name":"widbaroalarm.default.json","url":"default.json"}
],
"data": [{"name":"widbaroalarm.json"}, {"name":"widbaroalarm.log"}]
}

View File

@ -0,0 +1,95 @@
(function(back) {
const SETTINGS_FILE = "widbaroalarm.json";
const storage = require('Storage');
let settings = Object.assign(
storage.readJSON("widbaroalarm.default.json", true) || {},
storage.readJSON(SETTINGS_FILE, true) || {}
);
function save(key, value) {
settings[key] = value;
storage.write(SETTINGS_FILE, settings);
}
function showMainMenu() {
let menu ={
'': { 'title': 'Barometer alarm widget' },
/*LANG*/'< Back': back,
"Interval": {
value: settings.interval,
min: 0,
max: 120,
step: 1,
format: x => {
return x != 0 ? x + ' min' : 'off';
},
onchange: x => save("interval", x)
},
"Low alarm": {
value: settings.lowalarm,
format: x => {
return x ? 'Yes' : 'No';
},
onchange: x => save("lowalarm", x),
},
"Low threshold": {
value: settings.min,
min: 600,
max: 1000,
step: 10,
onchange: x => save("min", x),
},
"High alarm": {
value: settings.highalarm,
format: x => {
return x ? 'Yes' : 'No';
},
onchange: x => save("highalarm", x),
},
"High threshold": {
value: settings.max,
min: 1000,
max: 1100,
step: 10,
onchange: x => save("max", x),
},
"Drop alarm": {
value: settings.drop3halarm,
min: 0,
max: 10,
step: 1,
format: x => {
return x != 0 ? x + ' hPa/3h' : 'off';
},
onchange: x => save("drop3halarm", x)
},
"Raise alarm": {
value: settings.raise3halarm,
min: 0,
max: 10,
step: 1,
format: x => {
return x != 0 ? x + ' hPa/3h' : 'off';
},
onchange: x => save("raise3halarm", x)
},
"Show widget": {
value: settings.show,
format: x => {
return x ? 'Yes' : 'No';
},
onchange: x => save('show', x)
},
"Buzz on alarm": {
value: settings.buzz,
format: x => {
return x ? 'Yes' : 'No';
},
onchange: x => save('buzz', x)
},
};
E.showMenu(menu);
}
showMainMenu();
});

185
apps/widbaroalarm/widget.js Normal file
View File

@ -0,0 +1,185 @@
(function() {
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(
storage.readJSON("widbaroalarm.default.json", true) || {},
storage.readJSON(SETTINGS_FILE, true) || {}
);
function setting(key) {
return settings[key];
}
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();
}
}
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
};
// 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("highalarm") && pressure >= setting("max")) {
showAlarm("Pressure high: " + Math.round(pressure) + " hPa");
alreadyWarned = true;
}
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;
// 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");
}
}
// raise alarm
if (raise3halarm > 0 && oldestPressure < pressure) {
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");
}
}
}
}
}
// 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);
}
}
}
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);
}
}, 5000);
})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB