forked from FOSS/BangleApps
Initial version of Barometer Alarm Widget
parent
600f7f45a6
commit
40db573458
|
@ -0,0 +1 @@
|
|||
0.01: Initial version
|
|
@ -0,0 +1,24 @@
|
|||
# Barometer alarm widget
|
||||
|
||||
Get a notification when the pressure reaches defined thresholds.
|
||||
|
||||

|
||||
|
||||
## 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
|
||||
* Change alarm: Warn when pressure changes 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))
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"buzz": true,
|
||||
"lowalarm": false,
|
||||
"min": 950,
|
||||
"highalarm": false,
|
||||
"max": 1030,
|
||||
"changeIn3h": 2,
|
||||
"show": true,
|
||||
"interval": 15
|
||||
}
|
|
@ -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",
|
||||
"screenshots": [{"url":"screenshot.png"}],
|
||||
"type": "widget",
|
||||
"tags": "tool,barometer",
|
||||
"supports": ["BANGLEJS2"],
|
||||
"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"}]
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,85 @@
|
|||
(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),
|
||||
},
|
||||
"Change alarm": {
|
||||
value: settings.changeIn3h,
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 1,
|
||||
format: x => {
|
||||
return x != 0 ? x + ' hPa/3h' : 'off';
|
||||
},
|
||||
onchange: x => save("changeIn3h", 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();
|
||||
});
|
|
@ -0,0 +1,199 @@
|
|||
(function() {
|
||||
let lastPressure;
|
||||
let avrPressure;
|
||||
let threeHourAvrPressure;
|
||||
|
||||
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(text, value, value2, icon) {
|
||||
if (text == undefined || value == undefined) return;
|
||||
const Layout = require("Layout");
|
||||
layout = new Layout({
|
||||
type: "v",
|
||||
c: [{
|
||||
type: "h",
|
||||
c: [{
|
||||
type: "img",
|
||||
pad: 0,
|
||||
src: function() {
|
||||
return icon || require("heatshrink").decompress(atob("jEY4cA///gH4/++mkK30kiWC4H8x3BGDmSGgYDCgmSoEAg3bsAIDpAIFkmSpMAm3btgIFDQwIGNQpTYkAIJwAHEgMoCA0JgMEyBnBCAW3KoQQDhu3oAIH5JnDBAW24IIBEYm2EYwACBCIACA"));
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "txt",
|
||||
id: "title",
|
||||
font: "6x8:2",
|
||||
label: "Alarm",
|
||||
pad: 2
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "txt",
|
||||
id: "text",
|
||||
font: "6x8:2",
|
||||
label: text,
|
||||
pad: 3
|
||||
},
|
||||
{
|
||||
type: "txt",
|
||||
id: "value",
|
||||
font: "6x8:2",
|
||||
label: value,
|
||||
halign: 0,
|
||||
pad: 3
|
||||
},
|
||||
{
|
||||
type: "txt",
|
||||
id: "value2",
|
||||
font: "6x8:1",
|
||||
label: value2 || "",
|
||||
halign: 0,
|
||||
pad: 3
|
||||
},
|
||||
]
|
||||
}, {
|
||||
btns: [{
|
||||
label: "OK",
|
||||
cb: function() {
|
||||
load(); // close
|
||||
}
|
||||
}],
|
||||
lazy: false
|
||||
});
|
||||
|
||||
g.clear();
|
||||
layout.render();
|
||||
|
||||
if (setting("buzz") &&
|
||||
!(storage.readJSON('setting.json', 1) || {}).quiet) {
|
||||
Bangle.buzz();
|
||||
}
|
||||
}
|
||||
|
||||
let alreadyWarned = false;
|
||||
|
||||
function baroHandler(data) {
|
||||
if (data === undefined) {
|
||||
setTimeout(() => Bangle.getPressure().then(baroHandler), 500);
|
||||
} else {
|
||||
lastPressure = Math.round(data.pressure);
|
||||
if (lastPressure == undefined || lastPressure <= 0) return;
|
||||
|
||||
const ts = Math.round(Date.now() / 1000); // seconds
|
||||
const d = {
|
||||
"ts": ts,
|
||||
"p": lastPressure
|
||||
};
|
||||
|
||||
// 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);
|
||||
|
||||
// we need at least three entries for reliable detection
|
||||
if (history3.length >= 3) {
|
||||
|
||||
// calculate average of recent three entries
|
||||
avrPressure = (history3[history3.length - 1]["p"] + history3[history3.length - 2]["p"] + history3[history3.length - 3]["p"]) / 3;
|
||||
|
||||
if (setting("lowalarm") && avrPressure <= setting("min")) {
|
||||
showAlarm("Pressure low", Math.round(avrPressure) + " hPa");
|
||||
alreadyWarned = true;
|
||||
}
|
||||
if (setting("highalarm") && avrPressure >= setting("max")) {
|
||||
showAlarm("Pressure high", Math.round(avrPressure) + " hPa");
|
||||
alreadyWarned = true;
|
||||
}
|
||||
|
||||
if (!alreadyWarned) {
|
||||
// 3h change detection
|
||||
const threeHourChange = setting("changeIn3h");
|
||||
if (threeHourChange > 0) {
|
||||
// we need at least 30min of data for reliable detection
|
||||
if (history3[0]["ts"] > ts - (30 * 60)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Average of oldest three entries
|
||||
const oldestAvgPressure = (history3[0]["p"] + history3[1]["p"] + history3[2]["p"]) / 3;
|
||||
if (oldestAvgPressure != undefined && oldestAvgPressure > 0) {
|
||||
const diff = oldestAvgPressure - avrPressure;
|
||||
if (Math.abs(diff) > threeHourChange) {
|
||||
showAlarm("Pressure " + (diff > 0 ? "drop" : "raise"), (Math.round(Math.abs(diff) * 10) / 10) + " hPa/3h",
|
||||
Math.round(oldestAvgPressure) + " hPa -> " + Math.round(avrPressure) + " hPa");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 check() {
|
||||
Bangle.getPressure().then(baroHandler);
|
||||
}
|
||||
|
||||
function reload() {
|
||||
check();
|
||||
}
|
||||
|
||||
function draw() {
|
||||
g.reset();
|
||||
if (setting("show") && lastPressure != undefined) {
|
||||
g.setFont("6x8", 1).setFontAlign(1, 0);
|
||||
g.drawString(Math.round(lastPressure), 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 check a bit
|
||||
setTimeout(function() {
|
||||
check();
|
||||
if (interval > 0) {
|
||||
setInterval(check, interval * 60000);
|
||||
}
|
||||
}, 10000);
|
||||
|
||||
})();
|
Binary file not shown.
After Width: | Height: | Size: 9.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
Loading…
Reference in New Issue