Weather: refactoring and reduced ram usage

These changes reduce the memory usage of the ram widget by up to 70
JSVars, depending on the weather.
pull/817/head
Ben Whittaker 2021-09-19 14:28:56 -04:00
parent 50ec8d970e
commit 5925628cf6
5 changed files with 76 additions and 94 deletions

View File

@ -571,7 +571,7 @@
{ "id": "weather",
"name": "Weather",
"icon": "icon.png",
"version":"0.07",
"version":"0.08",
"description": "Show Gadgetbridge weather report",
"readme": "readme.md",
"tags": "widget,outdoors",

View File

@ -4,3 +4,4 @@
0.05: Add wind direction.
0.06: Use setUI for launcher.
0.07: Add theme support and unknown icon.
0.08: Refactor and reduce widget ram usage.

View File

@ -1,5 +1,6 @@
(() => {
const weather = require('weather');
let current = weather.get();
function formatDuration(millis) {
let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s");
@ -10,16 +11,15 @@
}
function draw() {
let w = weather.current;
g.reset();
g.clearRect(0, 24, 239, 239);
weather.drawIcon(w.txt, 65, 90, 55);
weather.drawIcon(current.txt, 65, 90, 55);
const locale = require("locale");
g.reset();
const temp = locale.temp(w.temp-273.15).match(/^(\D*\d*)(.*)$/);
const temp = locale.temp(current.temp-273.15).match(/^(\D*\d*)(.*)$/);
let width = g.setFont("Vector", 40).stringWidth(temp[1]);
width += g.setFont("Vector", 20).stringWidth(temp[2]);
g.setFont("Vector", 40).setFontAlign(-1, -1, 0);
@ -31,19 +31,19 @@
g.setFontAlign(-1, 0, 0);
g.drawString("Humidity", 135, 130);
g.setFontAlign(1, 0, 0);
g.drawString(w.hum+"%", 225, 130);
if ('wind' in w) {
g.drawString(current.hum+"%", 225, 130);
if ('wind' in current) {
g.setFontAlign(-1, 0, 0);
g.drawString("Wind", 135, 142);
g.setFontAlign(1, 0, 0);
g.drawString(locale.speed(w.wind)+' '+w.wrose.toUpperCase(), 225, 142);
g.drawString(locale.speed(current.wind)+' '+current.wrose.toUpperCase(), 225, 142);
}
g.setFont("6x8", 2).setFontAlign(0, 0, 0);
g.drawString(w.loc, 120, 170);
g.drawString(current.loc, 120, 170);
g.setFont("6x8", 1).setFontAlign(0, 0, 0);
g.drawString(w.txt.charAt(0).toUpperCase()+w.txt.slice(1), 120, 190);
g.drawString(current.txt.charAt(0).toUpperCase()+current.txt.slice(1), 120, 190);
drawUpdateTime();
@ -51,8 +51,8 @@
}
function drawUpdateTime() {
if (!weather.current || !weather.current.time) return;
let text = `Last update received ${formatDuration(Date.now() - weather.current.time)} ago`;
if (!current || !current.time) return;
let text = `Last update received ${formatDuration(Date.now() - current.time)} ago`;
g.reset();
g.clearRect(0, 202, 239, 210);
g.setFont("6x8", 1).setFontAlign(0, 0, 0);
@ -60,8 +60,9 @@
}
function update() {
current = weather.get();
NRF.removeListener("connect", update);
if (weather.current) {
if (current) {
draw();
} else if (NRF.getSecurityStatus().connected) {
E.showMessage("Weather unknown\n\nIs Gadgetbridge\nweather reporting\nset up on your\nphone?");

View File

@ -1,6 +1,6 @@
const storage = require('Storage');
let expiryTimeout = undefined;
let expiryTimeout;
function scheduleExpiry(json) {
if (expiryTimeout) {
clearTimeout(expiryTimeout);
@ -9,53 +9,35 @@ function scheduleExpiry(json) {
let expiry = "expiry" in json ? json.expiry : 2*3600000;
if (json.weather && json.weather.time && expiry) {
let t = json.weather.time + expiry - Date.now();
expiryTimeout = setTimeout(() => {
expiryTimeout = undefined;
let json = storage.readJSON('weather.json')||{};
delete json.weather;
storage.write('weather.json', json);
exports.current = undefined;
exports.emit("update");
}, t);
expiryTimeout = setTimeout(update, t);
}
}
/**
* Convert numeric direction into human-readable label
*
* @param {number} deg - Direction in degrees
* @return {string|null} - Nearest compass point
*/
function compassRose(deg) {
if (typeof deg === 'undefined') return null;
while (deg<0 || deg>360) {
deg = (deg+360)%360;
}
return ['n','ne','e','se','s','sw','w','nw','n'][Math.floor((deg+22.5)/45)];
}
function setCurrentWeather(json) {
scheduleExpiry(json);
exports.current = json.weather;
}
function update(weatherEvent) {
let weather = Object.assign({}, weatherEvent);
weather.time = Date.now();
if ('wdir' in weather) {
weather.wrose = compassRose(weather.wdir);
}
delete weather.t;
let json = storage.readJSON('weather.json')||{};
if (weatherEvent) {
let weather = weatherEvent.clone();
delete weather.t;
weather.time = Date.now();
if (weather.wdir != null) {
// Convert numeric direction into human-readable label
let deg = weather.wdir;
while (deg<0 || deg>360) {
deg = (deg+360)%360;
}
weather.wrose = ['n','ne','e','se','s','sw','w','nw','n'][Math.floor((deg+22.5)/45)];
}
json.weather = weather;
}
else {
delete json.weather;
}
storage.write('weather.json', json);
setCurrentWeather(json);
exports.emit("update");
scheduleExpiry(json);
exports.emit("update", json.weather);
}
const _GB = global.GB;
@ -64,7 +46,11 @@ global.GB = (event) => {
if (_GB) setTimeout(_GB, 0, event);
};
setCurrentWeather(storage.readJSON('weather.json')||{});
exports.get = function() {
return storage.readJSON('weather.json').weather;
}
scheduleExpiry(storage.readJSON('weather.json')||{});
exports.drawIcon = function(cond, x, y, r) {
function drawSun(x, y, r) {

View File

@ -1,8 +1,37 @@
(() => {
const weather = require('weather');
function draw() {
const w = weather.current;
var dirty = false;
weather.on("update", w => {
if (w) {
if (!WIDGETS["weather"].width) {
WIDGETS["weather"].width = 20;
Bangle.drawWidgets();
} else if (Bangle.isLCDOn()) {
WIDGETS["weather"].draw();
} else {
dirty = true;
}
}
else {
WIDGETS["weather"].width = 0;
Bangle.drawWidgets();
}
});
Bangle.on('lcdPower', on => {
if (on && dirty) {
WIDGETS["weather"].draw();
dirty = false;
}
});
WIDGETS["weather"] = {
area: "tl",
width: weather.get() ? 20 : 0,
draw: function() {
const w = weather.get();
if (!w) return;
g.reset();
g.clearRect(this.x, this.y, this.x+this.width-1, this.y+23);
@ -17,41 +46,6 @@
g.setFont('6x8', 1);
g.drawString(t, this.x+10, this.y+24);
}
}
var dirty = false;
function update() {
if (!WIDGETS["weather"].width) {
WIDGETS["weather"].width = 20;
Bangle.drawWidgets();
} else if (Bangle.isLCDOn()) {
WIDGETS["weather"].draw();
} else {
dirty = true;
}
}
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;
}
});
WIDGETS["weather"] = {
area: "tl",
width: weather.current ? 20 : 0,
draw: draw,
},
};
})();