BangleApps_old/apps/zambretti/app.js

248 lines
6.4 KiB
JavaScript

/**
* https://web.archive.org/web/20110610213848/http://www.meteormetrics.com/zambretti.htm
*/
const storage = require('Storage');
const Layout = require("Layout");
let height;
let mainScreen = false;
const ZAMBRETTI_FORECAST = {
A: /*LANG*/'Settled Fine',
B: /*LANG*/'Fine Weather',
C: /*LANG*/'Becoming Fine',
D: /*LANG*/'Fine Becoming Less Settled',
E: /*LANG*/'Fine, Possibly showers',
F: /*LANG*/'Fairly Fine, Improving',
G: /*LANG*/'Fairly Fine, Possibly showers, early',
H: /*LANG*/'Fairly Fine Showery Later',
I: /*LANG*/'Showery Early, Improving',
J: /*LANG*/'Changeable Mending',
K: /*LANG*/'Fairly Fine, Showers likely',
L: /*LANG*/'Rather Unsettled Clearing Later',
M: /*LANG*/'Unsettled, Probably Improving',
N: /*LANG*/'Showery Bright Intervals',
O: /*LANG*/'Showery Becoming more unsettled',
P: /*LANG*/'Changeable some rain',
Q: /*LANG*/'Unsettled, short fine Intervals',
R: /*LANG*/'Unsettled, Rain later',
S: /*LANG*/'Unsettled, rain at times',
T: /*LANG*/'Very Unsettled, Finer at times',
U: /*LANG*/'Rain at times, worse later.',
V: /*LANG*/'Rain at times, becoming very unsettled',
W: /*LANG*/'Rain at Frequent Intervals',
X: /*LANG*/'Very Unsettled, Rain',
Y: /*LANG*/'Stormy, possibly improving',
Z: /*LANG*/'Stormy, much rain',
};
const ZAMBRETTI_FALLING = {
1050: 'A',
1040: 'B',
1024: 'C',
1018: 'H',
1010: 'O',
1004: 'R',
998: 'U',
991: 'V',
985: 'X',
};
const ZAMBRETTI_STEADY = {
1033: 'A',
1023: 'B',
1014: 'E',
1008: 'K',
1000: 'N',
994: 'P',
989: 'S',
981: 'W',
974: 'X',
960: 'Z',
};
const ZAMBRETTI_RISING = {
1030: 'A',
1022: 'B',
1012: 'C',
1007: 'F',
1000: 'G',
995: 'I',
990: 'J',
984: 'L',
978: 'M',
970: 'Q',
965: 'T',
959: 'Y',
947: 'Z',
};
function correct_season(letter, dir) {
const month = new Date().getMonth() + 1;
const location = require("Storage").readJSON("mylocation.json",1)||{"lat":51.5072,"lon":0.1276,"location":"London"};
const northern_hemisphere = location.lat > 0;
const summer = northern_hemisphere ? (month >= 4 && month <= 9) : (month >= 10 || month <= 3);
let corr = 0;
if (dir < 0 && !summer) { // Winter falling
corr = -1;
} else if (dir > 0 && summer) { // Summer rising
corr = 1;
}
return String.fromCharCode(letter.charCodeAt(0)+corr);
}
function get_zambretti_letter(pressure, dir) {
let table = () => {
if (dir < 0) { // Barometer Falling
return ZAMBRETTI_FALLING;
} else if (dir == 0) { // Barometer Steady
return ZAMBRETTI_STEADY;
} else { // Barometer Rising
return ZAMBRETTI_RISING;
}
}();
const closest = Object.keys(table).reduce(function(prev, curr) {
return (Math.abs(curr - pressure) < Math.abs(prev - pressure) ? curr : prev);
});
return correct_season(table[closest], dir);
}
function loadSettings() {
const settings = require('Storage').readJSON("zambretti.json", true) || {};
height = settings.height;
}
function showMenu() {
const menu = {
"" : {
title : "Zambretti Forecast",
},
"< Back": () => {
E.showMenu();
layout.forgetLazyState();
show();
},
/*LANG*/"Exit": () => load(),
/*LANG*/"Settings": () =>
eval(require('Storage').read('zambretti.settings.js'))(() => {
loadSettings();
showMenu();
}),
'Plot history': () => {E.showMenu(); history();},
};
E.showMenu(menu);
}
const layout = new Layout({
type:"v", c: [
{type:"txt", font:"9%", label:/*LANG*/"Zambretti Forecast", bgCol:g.theme.bgH, fillx: true, pad: 1},
{type:"txt", font:"12%", id:"forecast", filly: 1, wrap: 1, width: Bangle.appRect.w, pad: 1},
{type:"h", c:[
{type: 'v', c:[
{type:"txt", font:"9%", label:/*LANG*/"Pressure ", pad: 3, halign: -1},
{type:"txt", font:"9%", label:/*LANG*/"Difference", pad: 3, halign: -1},
{type:"txt", font:"9%", label:/*LANG*/"Temperature", pad: 3, halign: -1},
]},
{type: 'v', c:[
{type:"txt", font:"9%", id:"pressure", pad: 3, halign: -1},
{type:"txt", font:"9%", id:"diff", pad: 3, halign: -1},
{type:"txt", font:"9%", id:"temp", pad: 3, halign: -1},
]}
]},
]
}, {lazy:true});
function draw(temperature) {
const history3 = storage.readJSON("zambretti.log.json", true) || []; // history of recent 3 hours
const pressure_cur = history3[history3.length-1].p;
const pressure_last = history3[0].p;
const diff = pressure_cur - pressure_last;
const pressure_sea = Math.round(pressure_cur * Math.pow(1 - (0.0065 * height) / (temperature + (0.0065 * height) + 273.15),-5.257));
layout.forecast.label = ZAMBRETTI_FORECAST[get_zambretti_letter(pressure_sea, diff)];
layout.pressure.label = pressure_sea;
layout.diff.label = diff;
layout.temp.label = require("locale").number(temperature,1);
layout.render();
//layout.debug();
mainScreen = true;
Bangle.setUI({
mode: "custom",
btn: (n) => {mainScreen = false; showMenu();},
});
}
function show() {
Bangle.getPressure().then(p =>{if (p) draw(p.temperature);});
}
function history() {
const interval = 15; // minutes
const history3 = require('Storage').readJSON("zambretti.log.json", true) || []; // history of recent 3 hours
const now = new Date()/(1000);
let curtime = now-3*60*60; // 3h ago
const data = [];
while (curtime <= now) {
// find closest value in history for this timestamp
const closest = history3.reduce((prev, curr) => {
return (Math.abs(curr.ts - curtime) < Math.abs(prev.ts - curtime) ? curr : prev);
});
data.push(closest.p);
curtime += interval*60;
}
Bangle.setUI({
mode: "custom",
back: () => showMenu(),
});
g.reset().setFont("6x8",1);
require("graph").drawLine(g, data, {
axes: true,
x: 4,
y: Bangle.appRect.y+8,
height: Bangle.appRect.h-20,
gridx: 1,
gridy: 1,
miny: Math.min.apply(null, data)-1,
maxy: Math.max.apply(null, data)+1,
title: /*LANG*/"Barometer history (mBar)",
ylabel: y => y,
xlabel: i => {
const t = -3*60 + interval*i;
if (t % 60 === 0) {
return "-" + t/60 + "h";
}
return "";
},
});
}
g.reset().clear();
loadSettings();
Bangle.loadWidgets();
if (height === undefined) {
// setting of height required
eval(require('Storage').read('zambretti.settings.js'))(() => {
loadSettings();
show();
});
} else {
show();
}
Bangle.drawWidgets();
// Update every 15 minutes
setInterval(() => {
if (mainScreen) {
show();
}
}, 15*60*1000);