weather: general refactoring

pull/443/head
Ben Whittaker 2020-05-24 05:21:24 -04:00
parent eed9868b76
commit e0cea37238
3 changed files with 215 additions and 202 deletions

View File

@ -1,4 +1,6 @@
(() => {
const weather = require('weather');
function formatDuration(millis) {
let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s");
if (millis < 60000) return pluralize(Math.floor(millis/1000), "second");
@ -7,11 +9,12 @@
return pluralize(Math.floor(millis/86400000), "day");
}
function draw(w) {
function draw() {
let w = weather.current;
g.reset();
g.setColor(0).fillRect(0, 24, 239, 239);
require('weather').drawIcon(w.txt, 65, 90, 55);
weather.drawIcon(w.txt, 65, 90, 55);
const locale = require("locale");
g.setColor(-1);
@ -43,25 +46,22 @@
g.flip();
}
let updateTime = undefined;
function drawUpdateTime(w) {
if (!updateTime) return;
let text = `Last update received ${formatDuration(Date.now() - updateTime)} ago`;
function drawUpdateTime() {
if (!weather.current || !weather.current.time) return;
let text = `Last update received ${formatDuration(Date.now() - weather.current.time)} ago`;
g.reset();
g.setColor(0).fillRect(0, 202, 239, 210);
g.setColor(-1).setFont("6x8", 1).setFontAlign(0, 0, 0);
g.drawString(text, 120, 206);
}
const _GB = global.GB;
global.GB = (event) => {
if (event.t==="weather") {
updateTime = Date.now();
draw(event);
function update() {
if (weather.current) {
draw();
} else {
E.showMessage('Weather unknown\n\nIs Gadgetbridge\nconnected?');
}
if (_GB) setTimeout(_GB, 0, event);
};
}
let interval = setInterval(drawUpdateTime, 1000);
Bangle.on('lcdPower', (on) => {
@ -75,17 +75,13 @@
}
});
Bangle.loadWidgets();
Bangle.drawWidgets();
weather.on("update", update);
const weather = require('weather').load();
if (weather) {
updateTime = weather.time;
draw(weather);
} else {
E.showMessage('Weather unknown\n\nIs Gadgetbridge\nconnected?');
}
update(weather.current);
// Show launcher when middle button pressed
setWatch(Bangle.showLauncher, BTN2, {repeat: false, edge: 'falling'});
Bangle.loadWidgets();
Bangle.drawWidgets();
})()

View File

@ -1,5 +1,7 @@
const storage = require('Storage');
let expiryTimeout = undefined;
function updateExpiry(json) {
function scheduleExpiry(json) {
if (expiryTimeout) {
clearTimeout(expiryTimeout);
expiryTimeout = undefined;
@ -8,191 +10,205 @@ function updateExpiry(json) {
let t = json.weather.time + json.expiry - Date.now();
expiryTimeout = setTimeout(() => {
expiryTimeout = undefined;
let json = require('Storage').readJSON('weather.json')||{};
let json = storage.readJSON('weather.json')||{};
delete json.weather;
require('Storage').write('weather.json', json);
exports.emit("expiry");
storage.write('weather.json', json);
exports.current = undefined;
exports.emit("update");
}, t);
}
}
exports = {
save: weather => {
let json = require('Storage').readJSON('weather.json')||{};
json.weather = Object.assign({}, weather); // don't mutate GB events
delete json.weather.t; // don't save the event type (if present)
json.weather.time = Date.now();
require('Storage').write('weather.json', json);
updateExpiry(json);
},
load: () => {
let json = require('Storage').readJSON('weather.json')||{};
return json.weather;
},
drawIcon: (cond, x, y, r) => {
function drawSun(x, y, r) {
function setCurrentWeather(json) {
scheduleExpiry(json);
exports.current = json.weather;
}
function update(weatherEvent) {
let weather = Object.assign({}, weatherEvent);
weather.time = Date.now();
delete weather.t;
let json = storage.readJSON('weather.json')||{};
json.weather = weather;
storage.write('weather.json', json);
setCurrentWeather(json);
exports.emit("update");
}
const _GB = global.GB;
global.GB = (event) => {
if (event.t==="weather") update(event);
if (_GB) setTimeout(_GB, 0, event);
};
setCurrentWeather(storage.readJSON('weather.json')||{});
exports.drawIcon = function(cond, x, y, r) {
function drawSun(x, y, r) {
g.setColor("#FF7700");
g.fillCircle(x, y, r);
}
function drawCloud(x, y, r, c) {
const u = r/12;
if (c==null) c = "#EEEEEE";
g.setColor(c);
g.fillCircle(x-8*u, y+3*u, 4*u);
g.fillCircle(x-4*u, y-2*u, 5*u);
g.fillCircle(x+4*u, y+0*u, 4*u);
g.fillCircle(x+9*u, y+4*u, 3*u);
g.fillPoly([
x-8*u, y+7*u,
x-8*u, y+3*u,
x-4*u, y-2*u,
x+4*u, y+0*u,
x+9*u, y+4*u,
x+9*u, y+7*u,
]);
}
function drawBrokenClouds(x, y, r) {
drawCloud(x+1/8*r, y-1/8*r, 7/8*r, "#777777");
drawCloud(x-1/8*r, y+1/8*r, 7/8*r);
}
function drawFewClouds(x, y, r) {
drawSun(x+3/8*r, y-1/8*r, 5/8*r);
drawCloud(x-1/8*r, y+1/8*r, 7/8*r);
}
function drawRainLines(x, y, r) {
g.setColor("#FFFFFF");
const y1 = y+1/2*r;
const y2 = y+1*r;
g.fillPoly([
x-6/12*r+1, y1,
x-8/12*r+1, y2,
x-7/12*r, y2,
x-5/12*r, y1,
]);
g.fillPoly([
x-2/12*r+1, y1,
x-4/12*r+1, y2,
x-3/12*r, y2,
x-1/12*r, y1,
]);
g.fillPoly([
x+2/12*r+1, y1,
x+0/12*r+1, y2,
x+1/12*r, y2,
x+3/12*r, y1,
]);
}
function drawShowerRain(x, y, r) {
drawFewClouds(x, y-1/3*r, r);
drawRainLines(x, y, r);
}
function drawRain(x, y, r) {
drawBrokenClouds(x, y-1/3*r, r);
drawRainLines(x, y, r);
}
function drawThunderstorm(x, y, r) {
function drawLightning(x, y, r) {
g.setColor("#FF7700");
g.fillCircle(x, y, r);
}
function drawCloud(x, y, r, c) {
const u = r/12;
if (c==null) c = "#EEEEEE";
g.setColor(c);
g.fillCircle(x-8*u, y+3*u, 4*u);
g.fillCircle(x-4*u, y-2*u, 5*u);
g.fillCircle(x+4*u, y+0*u, 4*u);
g.fillCircle(x+9*u, y+4*u, 3*u);
g.fillPoly([
x-8*u, y+7*u,
x-8*u, y+3*u,
x-4*u, y-2*u,
x+4*u, y+0*u,
x+9*u, y+4*u,
x+9*u, y+7*u,
x-2/6*r, y-r,
x-4/6*r, y+1/6*r,
x-1/6*r, y+1/6*r,
x-3/6*r, y+1*r,
x+3/6*r, y-1/6*r,
x+0/6*r, y-1/6*r,
x+3/6*r, y-r,
]);
}
function drawBrokenClouds(x, y, r) {
drawCloud(x+1/8*r, y-1/8*r, 7/8*r, "#777777");
drawCloud(x-1/8*r, y+1/8*r, 7/8*r);
}
drawBrokenClouds(x, y-1/3*r, r);
drawLightning(x-1/12*r, y+1/2*r, 1/2*r);
}
function drawFewClouds(x, y, r) {
drawSun(x+3/8*r, y-1/8*r, 5/8*r);
drawCloud(x-1/8*r, y+1/8*r, 7/8*r);
}
function drawRainLines(x, y, r) {
g.setColor("#FFFFFF");
const y1 = y+1/2*r;
const y2 = y+1*r;
g.fillPoly([
x-6/12*r+1, y1,
x-8/12*r+1, y2,
x-7/12*r, y2,
x-5/12*r, y1,
]);
g.fillPoly([
x-2/12*r+1, y1,
x-4/12*r+1, y2,
x-3/12*r, y2,
x-1/12*r, y1,
]);
g.fillPoly([
x+2/12*r+1, y1,
x+0/12*r+1, y2,
x+1/12*r, y2,
x+3/12*r, y1,
]);
}
function drawShowerRain(x, y, r) {
drawFewClouds(x, y-1/3*r, r);
drawRainLines(x, y, r);
}
function drawRain(x, y, r) {
drawBrokenClouds(x, y-1/3*r, r);
drawRainLines(x, y, r);
}
function drawThunderstorm(x, y, r) {
function drawLightning(x, y, r) {
g.setColor("#FF7700");
g.fillPoly([
x-2/6*r, y-r,
x-4/6*r, y+1/6*r,
x-1/6*r, y+1/6*r,
x-3/6*r, y+1*r,
x+3/6*r, y-1/6*r,
x+0/6*r, y-1/6*r,
x+3/6*r, y-r,
]);
function drawSnow(x, y, r) {
function rotatePoints(points, pivotX, pivotY, angle) {
for(let i = 0; i<points.length; i += 2) {
const x = points[i];
const y = points[i+1];
points[i] = Math.cos(angle)*(x-pivotX)-Math.sin(angle)*(y-pivotY)+
pivotX;
points[i+1] = Math.sin(angle)*(x-pivotX)+Math.cos(angle)*(y-pivotY)+
pivotY;
}
drawBrokenClouds(x, y-1/3*r, r);
drawLightning(x-1/12*r, y+1/2*r, 1/2*r);
}
function drawSnow(x, y, r) {
function rotatePoints(points, pivotX, pivotY, angle) {
for(let i = 0; i<points.length; i += 2) {
const x = points[i];
const y = points[i+1];
points[i] = Math.cos(angle)*(x-pivotX)-Math.sin(angle)*(y-pivotY)+
pivotX;
points[i+1] = Math.sin(angle)*(x-pivotX)+Math.cos(angle)*(y-pivotY)+
pivotY;
}
}
g.setColor("#FFFFFF");
const w = 1/12*r;
for(let i = 0; i<=6; ++i) {
const points = [
x+w, y,
x-w, y,
x-w, y+r,
x+w, y+r,
];
rotatePoints(points, x, y, i/3*Math.PI);
g.fillPoly(points);
g.setColor("#FFFFFF");
const w = 1/12*r;
for(let i = 0; i<=6; ++i) {
for(let j = -1; j<=1; j += 2) {
const points = [
x+w, y,
x-w, y,
x+w, y+7/12*r,
x-w, y+7/12*r,
x-w, y+r,
x+w, y+r,
];
rotatePoints(points, x, y+7/12*r, j/3*Math.PI);
rotatePoints(points, x, y, i/3*Math.PI);
g.fillPoly(points);
for(let j = -1; j<=1; j += 2) {
const points = [
x+w, y+7/12*r,
x-w, y+7/12*r,
x-w, y+r,
x+w, y+r,
];
rotatePoints(points, x, y+7/12*r, j/3*Math.PI);
rotatePoints(points, x, y, i/3*Math.PI);
g.fillPoly(points);
}
}
}
}
function drawMist(x, y, r) {
const layers = [
[-0.4, 0.5],
[-0.8, 0.3],
[-0.2, 0.9],
[-0.9, 0.7],
[-0.2, 0.3],
];
function drawMist(x, y, r) {
const layers = [
[-0.4, 0.5],
[-0.8, 0.3],
[-0.2, 0.9],
[-0.9, 0.7],
[-0.2, 0.3],
];
g.setColor("#FFFFFF");
for(let i = 0; i<5; ++i) {
g.fillRect(x+layers[i][0]*r, y+(0.4*i-0.9)*r, x+layers[i][1]*r,
y+(0.4*i-0.7)*r-1);
g.fillCircle(x+layers[i][0]*r, y+(0.4*i-0.8)*r-0.5, 0.1*r-0.5);
g.fillCircle(x+layers[i][1]*r, y+(0.4*i-0.8)*r-0.5, 0.1*r-0.5);
}
g.setColor("#FFFFFF");
for(let i = 0; i<5; ++i) {
g.fillRect(x+layers[i][0]*r, y+(0.4*i-0.9)*r, x+layers[i][1]*r,
y+(0.4*i-0.7)*r-1);
g.fillCircle(x+layers[i][0]*r, y+(0.4*i-0.8)*r-0.5, 0.1*r-0.5);
g.fillCircle(x+layers[i][1]*r, y+(0.4*i-0.8)*r-0.5, 0.1*r-0.5);
}
}
function chooseIcon(condition) {
if (!condition) return () => {};
condition = condition.toLowerCase();
if (condition.includes("thunderstorm")) return drawThunderstorm;
if (condition.includes("freezing")||condition.includes("snow")||
condition.includes("sleet")) {
return drawSnow;
}
if (condition.includes("drizzle")||
condition.includes("shower")) {
return drawRain;
}
if (condition.includes("rain")) return drawShowerRain;
if (condition.includes("clear")) return drawSun;
if (condition.includes("few clouds")) return drawFewClouds;
if (condition.includes("scattered clouds")) return drawCloud;
if (condition.includes("clouds")) return drawBrokenClouds;
return drawMist;
function chooseIcon(condition) {
if (!condition) return () => {};
condition = condition.toLowerCase();
if (condition.includes("thunderstorm")) return drawThunderstorm;
if (condition.includes("freezing")||condition.includes("snow")||
condition.includes("sleet")) {
return drawSnow;
}
if (condition.includes("drizzle")||
condition.includes("shower")) {
return drawRain;
}
if (condition.includes("rain")) return drawShowerRain;
if (condition.includes("clear")) return drawSun;
if (condition.includes("few clouds")) return drawFewClouds;
if (condition.includes("scattered clouds")) return drawCloud;
if (condition.includes("clouds")) return drawBrokenClouds;
return drawMist;
}
chooseIcon(cond)(x, y, r);
},
}
updateExpiry(require('Storage').readJSON('weather.json')||{});
chooseIcon(cond)(x, y, r);
};

View File

@ -1,11 +1,13 @@
(() => {
const weather = require('weather');
function draw() {
const w = require('weather').load();
const w = weather.current;
if (!w) return;
g.reset();
g.setColor(0).fillRect(this.x, this.y, this.x+this.width-1, this.y+23);
if (w.txt) {
require('weather').drawIcon(w.txt, this.x+10, this.y+8, 7.5);
weather.drawIcon(w.txt, this.x+10, this.y+8, 7.5);
}
if (w.temp) {
let t = require('locale').temp(w.temp-273.15); // applies conversion
@ -19,8 +21,7 @@
var dirty = false;
function update(weather) {
require('weather').save(weather);
function update() {
if (!WIDGETS["weather"].width) {
WIDGETS["weather"].width = 20;
Bangle.drawWidgets();
@ -31,26 +32,26 @@
}
}
Bangle.on('lcdPower', (on) => {
function hide() {
WIDGETS["weather"].width = 0;
Bangle.drawWidgets();
}
weather.on("update", () => {
if (weather.current) update();
else hide();
});
Bangle.on('lcdPower', on => {
if (on && dirty) {
WIDGETS["weather"].draw();
dirty = false;
}
});
const _GB = global.GB;
global.GB = (event) => {
if (event.t==="weather") update(event);
if (_GB) setTimeout(_GB, 0, event);
WIDGETS["weather"] = {
area: "tl",
width: weather.current ? 20 : 0,
draw: draw,
};
require('weather').on("expiry", () => {
WIDGETS["weather"].width = 0;
Bangle.drawWidgets();
});
WIDGETS["weather"] = {area: "tl", width: 20, draw: draw};
if (!require('weather').load()) {
WIDGETS["weather"].width = 0;
}
})();