diff --git a/apps/weather/lib.js b/apps/weather/lib.js index 14ca77ec6..3d5fe44fd 100644 --- a/apps/weather/lib.js +++ b/apps/weather/lib.js @@ -158,10 +158,10 @@ exports.getColor = function(code) { */ exports.drawIcon = function(cond, x, y, r, ovr) { var palette; - var monochrome=1; + var monochrome = B2 ? 0 : 1; if(!ovr) { ovr = g; - monochrome=0; + monochrome = 0; } palette = getPalette(monochrome, ovr); diff --git a/apps/weatherClock/ChangeLog b/apps/weatherClock/ChangeLog index ceb5a7e1c..4c32f4a6c 100644 --- a/apps/weatherClock/ChangeLog +++ b/apps/weatherClock/ChangeLog @@ -3,4 +3,4 @@ 0.03: Minor layout extra spaces. 0.04: Layout now compatible with Bangle.js 2. 0.05: Use weather condition code for icon selection. -0.06: Dev13-New settings to optionally hide elements. Images placed into functions for performance. +0.06: Dev15-New settings to optionally hide elements. Images placed into functions for performance. diff --git a/apps/weatherClock/app.js b/apps/weatherClock/app.js index e7bfe5220..ff467cc53 100644 --- a/apps/weatherClock/app.js +++ b/apps/weatherClock/app.js @@ -2,8 +2,8 @@ const Layout = require("Layout"); const storage = require('Storage'); const locale = require("locale"); const SETTINGS_FILE = "weatherClock.json"; -let settings; -const weather = require('weatherClock'); +let s; +const w = require('weather'); // weather icons from https://icons8.com/icon/set/weather/color function getSun() { @@ -39,30 +39,28 @@ sent from gadget bridge. */ function chooseIcon(condition) { condition = condition.toLowerCase(); - if (condition.includes("thunderstorm")) return getStorm; + if (condition.includes("thunderstorm")|| + condition.includes("squalls")|| + condition.includes("tornado")) return getStorm; if (condition.includes("freezing")||condition.includes("snow")|| condition.includes("sleet")) { return getSnow; } if (condition.includes("drizzle")|| - condition.includes("shower")) { - return getRain; - } - if (condition.includes("rain")) return getRain; + condition.includes("shower")|| + condition.includes("rain")) return getRain; if (condition.includes("clear")) return getSun; - if (condition.includes("few clouds")) return getPartSun; - if (condition.includes("scattered clouds")) return getCloud; if (condition.includes("clouds")) return getCloud; - if (condition.includes("mist") || - condition.includes("smoke") || - condition.includes("haze") || - condition.includes("sand") || - condition.includes("dust") || - condition.includes("fog") || - condition.includes("ash") || - condition.includes("squalls") || - condition.includes("tornado")) { - return getCloud; + if (condition.includes("few clouds")|| + condition.includes("scattered clouds")|| + condition.includes("mist")|| + condition.includes("smoke")|| + condition.includes("haze")|| + condition.includes("sand")|| + condition.includes("dust")|| + condition.includes("fog")|| + condition.includes("ash")) { + return getPartSun; } return getCloud; } @@ -76,14 +74,18 @@ function chooseIconByCode(code) { switch (codeGroup) { case 2: return getStorm; case 3: return getRain; - case 5: return getRain; + case 5: + switch (code) { + case 511: return getSnow; + default: return getRain; + } case 6: return getSnow; - case 7: return getCloud; + case 7: return getPartSun; case 8: switch (code) { - case 800: return getSun; - case 801: return getPartSun; - default: return getCloud; + case 800: return getSun; + case 804: return getCloud; + default: return getPartSun; } default: return getCloud; } @@ -111,62 +113,62 @@ function queueDraw() { function draw() { var date = new Date(); - clockLayout.time.label = locale.time(date, 1); - clockLayout.date.label = settings.date ? locale.date(date, 1).toUpperCase() : ""; - clockLayout.dow.label = settings.day ? locale.dow(date, 1).toUpperCase() + " " : ""; - let current = weather.get(); - if(current){ - const temp = locale.temp(current.temp-273.15).match(/^(\D*\d*)(.*)$/); - clockLayout.temp.label = temp[1] + " " + temp[2]; - const code = current.code || -1; + cLayout.time.label = locale.time(date, 1); + cLayout.dow.label = s.day ? locale.dow(date, 1).toUpperCase() + " " : ""; + cLayout.date.label = s.date ? locale.date(date, 1).toUpperCase() : ""; + let curr = w.get(); // Get weather from weather app. + if(curr){ + const temp = locale.temp(curr.temp-273.15).match(/^(\D*\d*)(.*)$/); + cLayout.temp.label = temp[1] + " " + temp[2]; + const code = curr.code || -1; if (code > 0) { - let srcIconsCode = settings.src ? weatherIcon(current.code) : chooseIconByCode(current.code); - clockLayout.weatherIcon.src = settings.icon ? srcIconsCode : getDummy; + let showIconC = s.src ? wDrawIcon(curr.code) : chooseIconByCode(curr.code); + cLayout.wIcon.src = s.icon ? showIconC : getDummy; } else { - let srcIconsTxt = settings.src ? weatherIcon(current.txt) : chooseIcon(current.txt); - clockLayout.weatherIcon.src = settings.icon ? srcIconsTxt : getDummy; + let showIconT = s.src ? wDrawIcon(curr.txt) : chooseIcon(curr.txt); + cLayout.wIcon.src = s.icon ? showIconT : getDummy; } - const wind = locale.speed(current.wind).match(/^(\D*\d*)(.*)$/); - clockLayout.wind.label = wind[1] + " " + wind[2] + " " + (current.wrose||'').toUpperCase(); + const wind = locale.speed(curr.wind).match(/^(\D*\d*)(.*)$/); + cLayout.wind.label = wind[1] + " " + wind[2] + " " + (curr.wrose||'').toUpperCase(); } else{ - clockLayout.temp.label = "Err"; - clockLayout.wind.label = "No Data"; - clockLayout.weatherIcon.src = settings.icon ? getErr : getDummy; + cLayout.temp.label = "Err"; + cLayout.wind.label = "No Data"; + cLayout.wIcon.src = s.icon ? getErr : getDummy; } - clockLayout.clear(); - clockLayout.render(); + cLayout.clear(); + cLayout.render(); // queue draw in one minute queueDraw(); } function loadSettings() { - settings = storage.readJSON(SETTINGS_FILE,1)||{}; - settings.src = settings.src === undefined ? false : settings.src; - settings.icon = settings.icon === undefined ? true : settings.icon; - settings.day = settings.day === undefined ? true : settings.day; - settings.date = settings.date === undefined ? true : settings.date; - settings.wind = settings.wind === undefined ? true : settings.wind; + s = storage.readJSON(SETTINGS_FILE,1)||{}; + s.src = s.src === undefined ? false : s.src; + s.icon = s.icon === undefined ? true : s.icon; + s.day = s.day === undefined ? true : s.day; + s.date = s.date === undefined ? true : s.date; + s.wind = s.wind === undefined ? true : s.wind; } loadSettings(); -function weatherIcon(code) { +function wDrawIcon(code) { var ovr = Graphics.createArrayBuffer(50,50,8,{msb:true}); - if (typeof code == "number") weather.drawIcon({code:code},24,24,24,ovr); - if (typeof code == "string") weather.drawIcon({code},24,24,24,ovr); + if (typeof code == "number") w.drawIcon({code:code},24,24,24,ovr); + if (typeof code == "string") w.drawIcon({txt:code},24,24,24,ovr); var img = ovr.asImage(); img.transparent = 0; return img; } -let srcIcons = settings.src ? weatherIcon(800) : getSun; -let srcWeather = settings.icon ? srcIcons : getDummy; -let fontTemp = settings.wind ? "10%" : "20%"; -let fontWind = settings.wind ? "10%" : "0%"; -let labelDay = settings.day ? "THU" : ""; -let labelDate = settings.date ? "01/01/1970" : ""; -var clockLayout = new Layout( { +let srcIcons = s.src ? wDrawIcon(800) : getSun; +let srcWeather = s.icon ? srcIcons : getDummy; +let fontTemp = s.wind ? "10%" : "20%"; +let fontWind = s.wind ? "10%" : "0%"; +let labelDay = s.day ? "THU" : ""; +let labelDate = s.date ? "01/01/1970" : ""; +var cLayout = new Layout( { type:"v", c: [ {type:"txt", font:"35%", halign: 0, fillx:1, pad: 8, label:"00:00", id:"time" }, {type: "h", fillx: 1, c: [ @@ -177,7 +179,7 @@ var clockLayout = new Layout( { ] }, {type: "h", valign : 1, fillx:1, c: [ - {type: "img", filly: 1, pad: 8, id: "weatherIcon", src: srcWeather}, + {type: "img", filly: 1, pad: 8, id: "wIcon", src: srcWeather}, {type: "v", fillx:1, c: [ {type: "h", c: [ {type: "txt", font: fontTemp, id: "temp", label: "000 °C"}, @@ -194,5 +196,5 @@ g.clear(); Bangle.setUI("clock"); // Show launcher when middle button pressed Bangle.loadWidgets(); Bangle.drawWidgets(); -clockLayout.render(); +cLayout.render(); draw(); diff --git a/apps/weatherClock/lib.js b/apps/weatherClock/lib.js deleted file mode 100644 index 48a290824..000000000 --- a/apps/weatherClock/lib.js +++ /dev/null @@ -1,399 +0,0 @@ -const storage = require('Storage'); -const B2 = process.env.HWVERSION===2; - -let expiryTimeout; -function scheduleExpiry(json) { - if (expiryTimeout) { - clearTimeout(expiryTimeout); - expiryTimeout = undefined; - } - 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(update, t); - } -} - -function update(weatherEvent) { - 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); - scheduleExpiry(json); - exports.emit("update", json.weather); -} - -const _GB = global.GB; -global.GB = (event) => { - if (event.t==="weather") update(event); - if (_GB) setTimeout(_GB, 0, event); -}; - -exports.get = function() { - return (storage.readJSON('weather.json')||{}).weather; -} - -scheduleExpiry(storage.readJSON('weather.json')||{}); - -function getPalette(monochrome, ovr) { - var palette; - if(monochrome) { - palette = { - sun: '#FFF', - cloud: '#FFF', - bgCloud: '#FFF', - rain: '#FFF', - lightning: '#FFF', - snow: '#FFF', - mist: '#FFF', - background: '#000' - }; - } else { - if (B2) { - if (ovr.theme.dark) { - palette = { - sun: '#FF0', - cloud: '#FFF', - bgCloud: '#777', // dithers on B2, but that's ok - rain: '#0FF', - lightning: '#FF0', - snow: '#FFF', - mist: '#FFF' - }; - } else { - palette = { - sun: '#FF0', - cloud: '#777', // dithers on B2, but that's ok - bgCloud: '#000', - rain: '#00F', - lightning: '#FF0', - snow: '#0FF', - mist: '#0FF' - }; - } - } else { - if (ovr.theme.dark) { - palette = { - sun: '#FE0', - cloud: '#BBB', - bgCloud: '#777', - rain: '#0CF', - lightning: '#FE0', - snow: '#FFF', - mist: '#FFF' - }; - } else { - palette = { - sun: '#FC0', - cloud: '#000', - bgCloud: '#777', - rain: '#07F', - lightning: '#FC0', - snow: '#CCC', - mist: '#CCC' - }; - } - } - } - return palette; -} - -exports.getColor = function(code) { - const codeGroup = Math.round(code / 100); - const palette = getPalette(0, g); - const cloud = g.blendColor(palette.cloud, palette.bgCloud, .5); //theme independent - switch (codeGroup) { - case 2: return g.blendColor(cloud, palette.lightning, .5); - case 3: return palette.rain; - case 5: - switch (code) { - case 511: return palette.snow; - case 520: return g.blendColor(palette.rain, palette.sun, .5); - case 521: return g.blendColor(palette.rain, palette.sun, .5); - case 522: return g.blendColor(palette.rain, palette.sun, .5); - case 531: return g.blendColor(palette.rain, palette.sun, .5); - default: return palette.rain; - } - case 6: return palette.snow; - case 7: return palette.mist; - case 8: - switch (code) { - case 800: return palette.sun; - case 801: return palette.sun; - case 802: return cloud; - default: return cloud; - } - default: return cloud; - } -} - -/** - * - * @param cond Weather condition, as one of: - * {number} code: (Preferred form) https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2 - * {string} weather description (in English: breaks for other languages!) - * {object} use cond.code if present, or fall back to cond.txt - * @param x Left - * @param y Top - * @param r Icon Size - * @param ovr Graphics instance (or undefined for g) - */ -exports.drawIcon = function(cond, x, y, r, ovr) { - var palette; - var monochrome=0; - if(!ovr) { - ovr = g; - monochrome=0; - } - - palette = getPalette(monochrome, ovr); - - function drawSun(x, y, r) { - ovr.setColor(palette.sun); - ovr.fillCircle(x, y, r); - } - - function drawCloud(x, y, r, c) { - const u = r/12; - if (c==null) c = palette.cloud; - ovr.setColor(c); - ovr.fillCircle(x-8*u, y+3*u, 4*u); - ovr.fillCircle(x-4*u, y-2*u, 5*u); - ovr.fillCircle(x+4*u, y+0*u, 4*u); - ovr.fillCircle(x+9*u, y+4*u, 3*u); - ovr.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, palette.bgCloud); - if(monochrome) - drawCloud(x-1/8*r, y+2/16*r, r, palette.background); - 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); - if(monochrome) - drawCloud(x-1/8*r, y+2/16*r, r, palette.background); - drawCloud(x-1/8*r, y+1/8*r, 7/8*r); - } - - function drawRainLines(x, y, r) { - ovr.setColor(palette.rain); - const y1 = y+1/2*r; - const y2 = y+1*r; - const poly = ovr.fillPolyAA ? p => ovr.fillPolyAA(p) : p => ovr.fillPoly(p); - poly([ - x-6/12*r, y1, - x-8/12*r, y2, - x-7/12*r, y2, - x-5/12*r, y1, - ]); - poly([ - x-2/12*r, y1, - x-4/12*r, y2, - x-3/12*r, y2, - x-1/12*r, y1, - ]); - poly([ - x+2/12*r, y1, - x+0/12*r, 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) { - ovr.setColor(palette.lightning); - ovr.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, - ]); - } - - if(monochrome) drawBrokenClouds(x, y-1/3*r, r); - drawLightning(x-1/12*r, y+1/2*r, 1/2*r); - drawBrokenClouds(x, y-1/3*r, r); - } - - function drawSnow(x, y, r) { - function rotatePoints(points, pivotX, pivotY, angle) { - for(let i = 0; i {}; - txt = txt.toLowerCase(); - if (txt.includes("thunderstorm")) return drawThunderstorm; - if (txt.includes("freezing")||txt.includes("snow")|| - txt.includes("sleet")) { - return drawSnow; - } - if (txt.includes("drizzle")|| - txt.includes("shower")) { - return drawRain; - } - if (txt.includes("rain")) return drawShowerRain; - if (txt.includes("clear")) return drawSun; - if (txt.includes("few clouds")) return drawFewClouds; - if (txt.includes("scattered clouds")) return drawCloud; - if (txt.includes("clouds")) return drawBrokenClouds; - if (txt.includes("mist") || - txt.includes("smoke") || - txt.includes("haze") || - txt.includes("sand") || - txt.includes("dust") || - txt.includes("fog") || - txt.includes("ash") || - txt.includes("squalls") || - txt.includes("tornado")) { - return drawMist; - } - return drawUnknown; - } - - /* - * Choose weather icon to display based on weather conditition code - * https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2 - */ - function chooseIconByCode(code) { - const codeGroup = Math.round(code / 100); - switch (codeGroup) { - case 2: return drawThunderstorm; - case 3: return drawRain; - case 5: - switch (code) { - case 511: return drawSnow; - case 520: return drawShowerRain; - case 521: return drawShowerRain; - case 522: return drawShowerRain; - case 531: return drawShowerRain; - default: return drawRain; - } - case 6: return drawSnow; - case 7: return drawMist; - case 8: - switch (code) { - case 800: return drawSun; - case 801: return drawFewClouds; - case 802: return drawCloud; - default: return drawBrokenClouds; - } - default: return drawUnknown; - } - } - - function chooseIcon(cond) { - if (typeof (cond)==="object") { - if ("code" in cond) return chooseIconByCode(cond.code); - if ("txt" in cond) return chooseIconByTxt(cond.txt); - } else if (typeof (cond)==="number") { - return chooseIconByCode(cond.code); - } else if (typeof (cond)==="string") { - return chooseIconByTxt(cond.txt); - } - return drawUnknown; - } - chooseIcon(cond)(x, y, r); - -}; diff --git a/apps/weatherClock/metadata.json b/apps/weatherClock/metadata.json index 4addc67ac..270591c74 100644 --- a/apps/weatherClock/metadata.json +++ b/apps/weatherClock/metadata.json @@ -15,8 +15,7 @@ "storage": [ {"name":"weatherClock.app.js","url":"app.js"}, {"name":"weatherClock.img","url":"app-icon.js","evaluate":true}, - {"name":"weatherClock.settings.js","url":"settings.js"}, - {"name":"weatherClock","url":"lib.js"} + {"name":"weatherClock.settings.js","url":"settings.js"} ], "data": [{"name":"weatherClock.json"}] } diff --git a/apps/weatherClock/settings.js b/apps/weatherClock/settings.js index bc4544b31..0aa7330c1 100644 --- a/apps/weatherClock/settings.js +++ b/apps/weatherClock/settings.js @@ -5,11 +5,11 @@ const storage = require('Storage'); let settings = storage.readJSON(SETTINGS_FILE, 1) || {}; let s = {}; - s.src = (settings.src === undefined ? false : settings.src); - s.icon = (settings.icon === undefined ? true : settings.icon); - s.day = (settings.day === undefined ? true : settings.day); s.date = (settings.date === undefined ? true : settings.date); + s.day = (settings.day === undefined ? true : settings.day); + s.icon = (settings.icon === undefined ? true : settings.icon); s.wind = (settings.wind === undefined ? true : settings.wind); + s.src = (settings.src === undefined ? false : settings.src); function save() { settings = s @@ -19,35 +19,35 @@ E.showMenu({ '': { 'title': 'Weather Clock' }, '< Back': back, - 'Weather Icon': { - value: !!s.icon, - onchange: v => { - s.icon = v; - save(); - }, - }, - 'Day Of Week': { - value: !!s.day, - onchange: v => { - s.day = v; - save(); - }, - }, - 'Date': { + 'Show date': { value: !!s.date, onchange: v => { s.date = v; save(); }, }, - 'Wind Speed': { + 'Show day Of Week': { + value: !!s.day, + onchange: v => { + s.day = v; + save(); + }, + }, + 'Show weather Icon': { + value: !!s.icon, + onchange: v => { + s.icon = v; + save(); + }, + }, + 'Show wind Speed': { value: !!s.wind, onchange: v => { s.wind = v; save(); }, }, - 'Icons from weather app': { + 'Use weather app icons': { value: !!s.src, onchange: v => { s.src = v;