forked from FOSS/BangleApps
weatherclock v0.06
parent
97a6beab55
commit
5ca69aa0a4
|
@ -158,10 +158,10 @@ exports.getColor = function(code) {
|
||||||
*/
|
*/
|
||||||
exports.drawIcon = function(cond, x, y, r, ovr) {
|
exports.drawIcon = function(cond, x, y, r, ovr) {
|
||||||
var palette;
|
var palette;
|
||||||
var monochrome=1;
|
var monochrome = B2 ? 0 : 1;
|
||||||
if(!ovr) {
|
if(!ovr) {
|
||||||
ovr = g;
|
ovr = g;
|
||||||
monochrome=0;
|
monochrome = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
palette = getPalette(monochrome, ovr);
|
palette = getPalette(monochrome, ovr);
|
||||||
|
|
|
@ -3,4 +3,4 @@
|
||||||
0.03: Minor layout extra spaces.
|
0.03: Minor layout extra spaces.
|
||||||
0.04: Layout now compatible with Bangle.js 2.
|
0.04: Layout now compatible with Bangle.js 2.
|
||||||
0.05: Use weather condition code for icon selection.
|
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.
|
||||||
|
|
|
@ -2,8 +2,8 @@ const Layout = require("Layout");
|
||||||
const storage = require('Storage');
|
const storage = require('Storage');
|
||||||
const locale = require("locale");
|
const locale = require("locale");
|
||||||
const SETTINGS_FILE = "weatherClock.json";
|
const SETTINGS_FILE = "weatherClock.json";
|
||||||
let settings;
|
let s;
|
||||||
const weather = require('weatherClock');
|
const w = require('weather');
|
||||||
|
|
||||||
// weather icons from https://icons8.com/icon/set/weather/color
|
// weather icons from https://icons8.com/icon/set/weather/color
|
||||||
function getSun() {
|
function getSun() {
|
||||||
|
@ -39,30 +39,28 @@ sent from gadget bridge.
|
||||||
*/
|
*/
|
||||||
function chooseIcon(condition) {
|
function chooseIcon(condition) {
|
||||||
condition = condition.toLowerCase();
|
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")||
|
if (condition.includes("freezing")||condition.includes("snow")||
|
||||||
condition.includes("sleet")) {
|
condition.includes("sleet")) {
|
||||||
return getSnow;
|
return getSnow;
|
||||||
}
|
}
|
||||||
if (condition.includes("drizzle")||
|
if (condition.includes("drizzle")||
|
||||||
condition.includes("shower")) {
|
condition.includes("shower")||
|
||||||
return getRain;
|
condition.includes("rain")) return getRain;
|
||||||
}
|
|
||||||
if (condition.includes("rain")) return getRain;
|
|
||||||
if (condition.includes("clear")) return getSun;
|
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("clouds")) return getCloud;
|
||||||
if (condition.includes("mist") ||
|
if (condition.includes("few clouds")||
|
||||||
condition.includes("smoke") ||
|
condition.includes("scattered clouds")||
|
||||||
condition.includes("haze") ||
|
condition.includes("mist")||
|
||||||
condition.includes("sand") ||
|
condition.includes("smoke")||
|
||||||
condition.includes("dust") ||
|
condition.includes("haze")||
|
||||||
condition.includes("fog") ||
|
condition.includes("sand")||
|
||||||
condition.includes("ash") ||
|
condition.includes("dust")||
|
||||||
condition.includes("squalls") ||
|
condition.includes("fog")||
|
||||||
condition.includes("tornado")) {
|
condition.includes("ash")) {
|
||||||
return getCloud;
|
return getPartSun;
|
||||||
}
|
}
|
||||||
return getCloud;
|
return getCloud;
|
||||||
}
|
}
|
||||||
|
@ -76,14 +74,18 @@ function chooseIconByCode(code) {
|
||||||
switch (codeGroup) {
|
switch (codeGroup) {
|
||||||
case 2: return getStorm;
|
case 2: return getStorm;
|
||||||
case 3: return getRain;
|
case 3: return getRain;
|
||||||
case 5: return getRain;
|
case 5:
|
||||||
|
switch (code) {
|
||||||
|
case 511: return getSnow;
|
||||||
|
default: return getRain;
|
||||||
|
}
|
||||||
case 6: return getSnow;
|
case 6: return getSnow;
|
||||||
case 7: return getCloud;
|
case 7: return getPartSun;
|
||||||
case 8:
|
case 8:
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 800: return getSun;
|
case 800: return getSun;
|
||||||
case 801: return getPartSun;
|
case 804: return getCloud;
|
||||||
default: return getCloud;
|
default: return getPartSun;
|
||||||
}
|
}
|
||||||
default: return getCloud;
|
default: return getCloud;
|
||||||
}
|
}
|
||||||
|
@ -111,62 +113,62 @@ function queueDraw() {
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
var date = new Date();
|
var date = new Date();
|
||||||
clockLayout.time.label = locale.time(date, 1);
|
cLayout.time.label = locale.time(date, 1);
|
||||||
clockLayout.date.label = settings.date ? locale.date(date, 1).toUpperCase() : "";
|
cLayout.dow.label = s.day ? locale.dow(date, 1).toUpperCase() + " " : "";
|
||||||
clockLayout.dow.label = settings.day ? locale.dow(date, 1).toUpperCase() + " " : "";
|
cLayout.date.label = s.date ? locale.date(date, 1).toUpperCase() : "";
|
||||||
let current = weather.get();
|
let curr = w.get(); // Get weather from weather app.
|
||||||
if(current){
|
if(curr){
|
||||||
const temp = locale.temp(current.temp-273.15).match(/^(\D*\d*)(.*)$/);
|
const temp = locale.temp(curr.temp-273.15).match(/^(\D*\d*)(.*)$/);
|
||||||
clockLayout.temp.label = temp[1] + " " + temp[2];
|
cLayout.temp.label = temp[1] + " " + temp[2];
|
||||||
const code = current.code || -1;
|
const code = curr.code || -1;
|
||||||
if (code > 0) {
|
if (code > 0) {
|
||||||
let srcIconsCode = settings.src ? weatherIcon(current.code) : chooseIconByCode(current.code);
|
let showIconC = s.src ? wDrawIcon(curr.code) : chooseIconByCode(curr.code);
|
||||||
clockLayout.weatherIcon.src = settings.icon ? srcIconsCode : getDummy;
|
cLayout.wIcon.src = s.icon ? showIconC : getDummy;
|
||||||
} else {
|
} else {
|
||||||
let srcIconsTxt = settings.src ? weatherIcon(current.txt) : chooseIcon(current.txt);
|
let showIconT = s.src ? wDrawIcon(curr.txt) : chooseIcon(curr.txt);
|
||||||
clockLayout.weatherIcon.src = settings.icon ? srcIconsTxt : getDummy;
|
cLayout.wIcon.src = s.icon ? showIconT : getDummy;
|
||||||
}
|
}
|
||||||
const wind = locale.speed(current.wind).match(/^(\D*\d*)(.*)$/);
|
const wind = locale.speed(curr.wind).match(/^(\D*\d*)(.*)$/);
|
||||||
clockLayout.wind.label = wind[1] + " " + wind[2] + " " + (current.wrose||'').toUpperCase();
|
cLayout.wind.label = wind[1] + " " + wind[2] + " " + (curr.wrose||'').toUpperCase();
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
clockLayout.temp.label = "Err";
|
cLayout.temp.label = "Err";
|
||||||
clockLayout.wind.label = "No Data";
|
cLayout.wind.label = "No Data";
|
||||||
clockLayout.weatherIcon.src = settings.icon ? getErr : getDummy;
|
cLayout.wIcon.src = s.icon ? getErr : getDummy;
|
||||||
}
|
}
|
||||||
clockLayout.clear();
|
cLayout.clear();
|
||||||
clockLayout.render();
|
cLayout.render();
|
||||||
// queue draw in one minute
|
// queue draw in one minute
|
||||||
queueDraw();
|
queueDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
settings = storage.readJSON(SETTINGS_FILE,1)||{};
|
s = storage.readJSON(SETTINGS_FILE,1)||{};
|
||||||
settings.src = settings.src === undefined ? false : settings.src;
|
s.src = s.src === undefined ? false : s.src;
|
||||||
settings.icon = settings.icon === undefined ? true : settings.icon;
|
s.icon = s.icon === undefined ? true : s.icon;
|
||||||
settings.day = settings.day === undefined ? true : settings.day;
|
s.day = s.day === undefined ? true : s.day;
|
||||||
settings.date = settings.date === undefined ? true : settings.date;
|
s.date = s.date === undefined ? true : s.date;
|
||||||
settings.wind = settings.wind === undefined ? true : settings.wind;
|
s.wind = s.wind === undefined ? true : s.wind;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
function weatherIcon(code) {
|
function wDrawIcon(code) {
|
||||||
var ovr = Graphics.createArrayBuffer(50,50,8,{msb:true});
|
var ovr = Graphics.createArrayBuffer(50,50,8,{msb:true});
|
||||||
if (typeof code == "number") weather.drawIcon({code:code},24,24,24,ovr);
|
if (typeof code == "number") w.drawIcon({code:code},24,24,24,ovr);
|
||||||
if (typeof code == "string") weather.drawIcon({code},24,24,24,ovr);
|
if (typeof code == "string") w.drawIcon({txt:code},24,24,24,ovr);
|
||||||
var img = ovr.asImage();
|
var img = ovr.asImage();
|
||||||
img.transparent = 0;
|
img.transparent = 0;
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
let srcIcons = settings.src ? weatherIcon(800) : getSun;
|
let srcIcons = s.src ? wDrawIcon(800) : getSun;
|
||||||
let srcWeather = settings.icon ? srcIcons : getDummy;
|
let srcWeather = s.icon ? srcIcons : getDummy;
|
||||||
let fontTemp = settings.wind ? "10%" : "20%";
|
let fontTemp = s.wind ? "10%" : "20%";
|
||||||
let fontWind = settings.wind ? "10%" : "0%";
|
let fontWind = s.wind ? "10%" : "0%";
|
||||||
let labelDay = settings.day ? "THU" : "";
|
let labelDay = s.day ? "THU" : "";
|
||||||
let labelDate = settings.date ? "01/01/1970" : "";
|
let labelDate = s.date ? "01/01/1970" : "";
|
||||||
var clockLayout = new Layout( {
|
var cLayout = new Layout( {
|
||||||
type:"v", c: [
|
type:"v", c: [
|
||||||
{type:"txt", font:"35%", halign: 0, fillx:1, pad: 8, label:"00:00", id:"time" },
|
{type:"txt", font:"35%", halign: 0, fillx:1, pad: 8, label:"00:00", id:"time" },
|
||||||
{type: "h", fillx: 1, c: [
|
{type: "h", fillx: 1, c: [
|
||||||
|
@ -177,7 +179,7 @@ var clockLayout = new Layout( {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{type: "h", valign : 1, fillx:1, c: [
|
{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: "v", fillx:1, c: [
|
||||||
{type: "h", c: [
|
{type: "h", c: [
|
||||||
{type: "txt", font: fontTemp, id: "temp", label: "000 °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.setUI("clock"); // Show launcher when middle button pressed
|
||||||
Bangle.loadWidgets();
|
Bangle.loadWidgets();
|
||||||
Bangle.drawWidgets();
|
Bangle.drawWidgets();
|
||||||
clockLayout.render();
|
cLayout.render();
|
||||||
draw();
|
draw();
|
||||||
|
|
|
@ -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<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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ovr.setColor(palette.snow);
|
|
||||||
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);
|
|
||||||
ovr.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);
|
|
||||||
ovr.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],
|
|
||||||
];
|
|
||||||
|
|
||||||
ovr.setColor(palette.mist);
|
|
||||||
for(let i = 0; i<5; ++i) {
|
|
||||||
ovr.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);
|
|
||||||
ovr.fillCircle(x+layers[i][0]*r, y+(0.4*i-0.8)*r-0.5, 0.1*r-0.5);
|
|
||||||
ovr.fillCircle(x+layers[i][1]*r, y+(0.4*i-0.8)*r-0.5, 0.1*r-0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawUnknown(x, y, r) {
|
|
||||||
drawCloud(x, y, r, palette.bgCloud);
|
|
||||||
ovr.setColor(ovr.theme.fg).setFontAlign(0, 0).setFont('Vector', r*2).drawString("?", x+r/10, y+r/6);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Choose weather icon to display based on weather description
|
|
||||||
*/
|
|
||||||
function chooseIconByTxt(txt) {
|
|
||||||
if (!txt) return () => {};
|
|
||||||
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);
|
|
||||||
|
|
||||||
};
|
|
|
@ -15,8 +15,7 @@
|
||||||
"storage": [
|
"storage": [
|
||||||
{"name":"weatherClock.app.js","url":"app.js"},
|
{"name":"weatherClock.app.js","url":"app.js"},
|
||||||
{"name":"weatherClock.img","url":"app-icon.js","evaluate":true},
|
{"name":"weatherClock.img","url":"app-icon.js","evaluate":true},
|
||||||
{"name":"weatherClock.settings.js","url":"settings.js"},
|
{"name":"weatherClock.settings.js","url":"settings.js"}
|
||||||
{"name":"weatherClock","url":"lib.js"}
|
|
||||||
],
|
],
|
||||||
"data": [{"name":"weatherClock.json"}]
|
"data": [{"name":"weatherClock.json"}]
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
const storage = require('Storage');
|
const storage = require('Storage');
|
||||||
let settings = storage.readJSON(SETTINGS_FILE, 1) || {};
|
let settings = storage.readJSON(SETTINGS_FILE, 1) || {};
|
||||||
let s = {};
|
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.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.wind = (settings.wind === undefined ? true : settings.wind);
|
||||||
|
s.src = (settings.src === undefined ? false : settings.src);
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
settings = s
|
settings = s
|
||||||
|
@ -19,35 +19,35 @@
|
||||||
E.showMenu({
|
E.showMenu({
|
||||||
'': { 'title': 'Weather Clock' },
|
'': { 'title': 'Weather Clock' },
|
||||||
'< Back': back,
|
'< Back': back,
|
||||||
'Weather Icon': {
|
'Show date': {
|
||||||
value: !!s.icon,
|
|
||||||
onchange: v => {
|
|
||||||
s.icon = v;
|
|
||||||
save();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'Day Of Week': {
|
|
||||||
value: !!s.day,
|
|
||||||
onchange: v => {
|
|
||||||
s.day = v;
|
|
||||||
save();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'Date': {
|
|
||||||
value: !!s.date,
|
value: !!s.date,
|
||||||
onchange: v => {
|
onchange: v => {
|
||||||
s.date = v;
|
s.date = v;
|
||||||
save();
|
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,
|
value: !!s.wind,
|
||||||
onchange: v => {
|
onchange: v => {
|
||||||
s.wind = v;
|
s.wind = v;
|
||||||
save();
|
save();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'Icons from weather app': {
|
'Use weather app icons': {
|
||||||
value: !!s.src,
|
value: !!s.src,
|
||||||
onchange: v => {
|
onchange: v => {
|
||||||
s.src = v;
|
s.src = v;
|
||||||
|
|
Loading…
Reference in New Issue