From 5925628cf6098cb5447d608b90375dc66d08a8f5 Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Sun, 19 Sep 2021 14:28:56 -0400 Subject: [PATCH] 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. --- apps.json | 2 +- apps/weather/ChangeLog | 3 +- apps/weather/app.js | 23 +++++++------- apps/weather/lib.js | 72 +++++++++++++++++------------------------- apps/weather/widget.js | 70 +++++++++++++++++++--------------------- 5 files changed, 76 insertions(+), 94 deletions(-) diff --git a/apps.json b/apps.json index 1dafc8f40..0d0492ce7 100644 --- a/apps.json +++ b/apps.json @@ -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", diff --git a/apps/weather/ChangeLog b/apps/weather/ChangeLog index 8e99f8faf..fd5d4d146 100644 --- a/apps/weather/ChangeLog +++ b/apps/weather/ChangeLog @@ -3,4 +3,5 @@ 0.04: Adjust "weather unknown" message according to Bluetooth connection. 0.05: Add wind direction. 0.06: Use setUI for launcher. -0.07: Add theme support and unknown icon. \ No newline at end of file +0.07: Add theme support and unknown icon. +0.08: Refactor and reduce widget ram usage. \ No newline at end of file diff --git a/apps/weather/app.js b/apps/weather/app.js index f5200c8ae..9d64583e9 100644 --- a/apps/weather/app.js +++ b/apps/weather/app.js @@ -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?"); diff --git a/apps/weather/lib.js b/apps/weather/lib.js index 6a57e1f00..f08df4a4a 100644 --- a/apps/weather/lib.js +++ b/apps/weather/lib.js @@ -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')||{}; - json.weather = weather; + + 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) { diff --git a/apps/weather/widget.js b/apps/weather/widget.js index ba0c8604d..4871ceda4 100644 --- a/apps/weather/widget.js +++ b/apps/weather/widget.js @@ -1,45 +1,23 @@ (() => { const weather = require('weather'); - function draw() { - const w = weather.current; - if (!w) return; - g.reset(); - g.clearRect(this.x, this.y, this.x+this.width-1, this.y+23); - if (w.txt) { - 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 - t = t.match(/[\d\-]*/)[0]; // but we have no room for units - g.reset(); - g.setFontAlign(0, 1); // center horizontally at bottom of widget - 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; + 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(); } - } - - function hide() { - WIDGETS["weather"].width = 0; - Bangle.drawWidgets(); - } - - weather.on("update", () => { - if (weather.current) update(); - else hide(); }); Bangle.on('lcdPower', on => { @@ -51,7 +29,23 @@ WIDGETS["weather"] = { area: "tl", - width: weather.current ? 20 : 0, - draw: draw, + 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); + if (w.txt) { + 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 + t = t.match(/[\d\-]*/)[0]; // but we have no room for units + g.reset(); + g.setFontAlign(0, 1); // center horizontally at bottom of widget + g.setFont('6x8', 1); + g.drawString(t, this.x+10, this.y+24); + } + }, }; })();