Merge pull request #1742 from frigis1/mtnclock

New clock - Mountain Pass Clock
master
Gordon Williams 2022-04-25 11:59:26 +01:00 committed by GitHub
commit 9e697c80cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 397 additions and 0 deletions

21
apps/mtnclock/README.md Normal file
View File

@ -0,0 +1,21 @@
# Mountain Pass Clock
Based on the Pebble watchface Weather Land.
Mountain Pass Clock changes depending on time (day/night) and weather conditions.
This clock requires Gadgetbridge and an app that Gadgetbridge can use to get the current weather from OpenWeatherMap (e.g. Weather Notification). To set up Gadgetbridge and weather, see https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Weather.
The scene will change according to the following OpenWeatherMap conditions: clear, cloudy, overcast, lightning, drizzle, rain, fog and snow. Each weather condition has night/day scenes.
If you choose not to set up weather (or are not connected to Gadgetbridge, for that matter), this clock will default to clear weather, and the scenery will still change from night to day.
Special thanks to Serj for testing this on the original Bangle.
## Images
![](screenshot1.png)
![](screenshot2.png)
![](screenshot3.png)
![](screenshot4.png)
![](screenshot5.png)

View File

@ -0,0 +1 @@
atob("MDCEBVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVUAVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVQAzAFVVVVVVVVVVVVVVVVVVVVVVVVVVVQLzIFVVVVVVAFVVVVVVVVVVVVVVVVVVUB//MQVVVVVQAQVVVVVVVVVVVVVVVVVVAB8RMQBVVVVQIwBVVVVVVVVVVVVVVVVQAQAAABAFVVUB8zAFVVVVVVVVVVVVVVVQExAiAYEFVVAD/zIFVVVVVVVVVVVVVVUBMzgzg4gQVQAvMvMAVVVVVVVVVVVVVVAIMzMzM4iABQACABAABVVVVVVVVVVVVQAjMzMzMziCABgQAQAiAFVVVVVVVVVVVQEzMzMzMzOIECMyIyKIEFVVVVVVVVVVUBMzMzMzMzM4gQIzMzM4gQVVVVVVVVVVAIMzMzMzMzM4iACDMzM4iABVVVVVVVVQAjMzMzMzMzMziCATMzMziCAFVVVVVVVQEzMzMzMzMzMzOIECMzMzOIEFVVVVVVUBMzMzMzMzMzMzM4gQIzMzM4gQVVVVVVAIMiMzMzMzMzMiM4iACDMzMiiABVVVVQAjIAIzMzMzMzIAIziCATMzIAKCAFVVVQE4AACDMzMzM4AACDOIECM4AACIEFVVUAERAiARERERERAiAREREAERAiAREAVVUAAAEyEAAAAAAAEyEAAAAAAAEyEAAAVVVVUBMzIQVVVVUBMzIQVVVVUBMzIQVVVVVVABEREQBVVVABEREQBVVVABEREQBVVVVVAAAAAABVVVAAAAAABVVVAAAAAABVVVVVUGIiJgVVVVUGIiJgVVVVUGIiJgVVVVVVACIiIgBVVVACIiIgBVVVACIiIgBVVVVQAiIiInAFVQAiIiInAFVQAiIiInAFVVVQEiIiInYFVQEiIiInYFVQEiIiInYFVVUAAAAAAAAAUAAAAAAAAAUAAAAAAAAAVVVVAHd3dwBVVVAHd3dwBVVVAHd3dwBVVVVQB3d3d3AFVQB3d3d3AFVQB3d3d3AFVVVQYiIiInYFVQYiIiInYFVQYiIiInYFVVUAIiIiIicAUAIiIiIicAUAIiIiIicAVVUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVUAAAARAAAAUAAAARAAAAUAAAARAAAAVVVVVVBEBVVVVVVVBEBVVVVVVVBEBVVVVVVVVVBEBVVVVVVVBEBVVVVVVVBEBVVVVVVVVVBEAFVVVVVVBEBVVVVVVQBEBVVVVVVVVVAAAAAAAAVVBEBVUAAAAAAABVVVVVVVUAASM/MyIQAAAAAAABIjPzMhAAVVVVVVABP///////MyIiIjP///////MQBVVVVQE////////////////////////zEFVVUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ==")

350
apps/mtnclock/app.js Normal file
View File

@ -0,0 +1,350 @@
var data = require("Storage").readJSON("mtnclock.json", 1) || {};
//seeded RNG to generate stars, snow, etc
function sfc32(a, b, c, d) {
return function() {
a >>>= 0; b >>>= 0; c >>>= 0; d >>>= 0;
var t = (a + b) | 0;
a = b ^ b >>> 9;
b = c + (c << 3) | 0;
c = (c << 21 | c >>> 11);
d = d + 1 | 0;
t = t + d | 0;
c = c + t | 0;
return (t >>> 0) / 4294967296;
};
}
//scale x, y coords to screen
function px(x) {
return x*g.getWidth()/100;
}
function py(y) {
return y*g.getHeight()/100;
}
function drawMtn(color, coord, dimen) {
//scale mountains to different sizes
g.setColor(color.mtn1).fillPoly([
coord.x,coord.y,
coord.x,coord.y+dimen.h,
coord.x-dimen.w/2,coord.y+dimen.h
]);
g.setColor(color.mtn2).fillPoly([
coord.x,coord.y,
coord.x,coord.y+dimen.h,
coord.x+dimen.w/2,coord.y+dimen.h
]);
}
function drawTree(color, coord, dimen) {
//scale trees to different sizes
g.setColor(color.tree1).fillPoly([
coord.x,coord.y,
coord.x-dimen.w/5,coord.y+dimen.h/4,
coord.x-dimen.w/12,coord.y+dimen.h/4,
coord.x-dimen.w/2.8,coord.y+1.95*dimen.h/4,
coord.x-dimen.w/8,coord.y+1.95*dimen.h/4,
coord.x-dimen.w/2,coord.y+3*dimen.h/4,
coord.x,coord.y+3*dimen.h/4
]);
g.setColor(color.tree2).fillPoly([
coord.x,coord.y,
coord.x+dimen.w/5,coord.y+dimen.h/4,
coord.x+dimen.w/12,coord.y+dimen.h/4,
coord.x+dimen.w/2.8,coord.y+1.95*dimen.h/4,
coord.x+dimen.w/8,coord.y+1.95*dimen.h/4,
coord.x+dimen.w/2,coord.y+3*dimen.h/4,
coord.x,coord.y+3*dimen.h/4
]);
g.setColor(color.tree3).fillRect(
coord.x-dimen.w/12,coord.y+3*dimen.h/4,
coord.x+dimen.w/12,coord.y+dimen.h
);
}
function drawSnow(color, coord, size) {
g.setColor(color).drawLine(coord.x-px(size),coord.y-py(size),coord.x+px(size),coord.y+py(size));
g.drawLine(coord.x-px(size),coord.y+py(size),coord.x+px(size),coord.y-py(size));
g.drawLine(coord.x,coord.y+py(size),coord.x,coord.y-py(size));
g.drawLine(coord.x-px(size),coord.y,coord.x+px(size),coord.y);
}
function draw(color) {
var seed;
var rand;
g.clear();
//background
g.setColor(color.bg1).fillRect(
px(0),py(0),
px(100),py(45)
);
g.setColor(color.bg2).fillRect(
px(0),py(45),
px(100),py(100)
);
//lightning
if (color.ltn) {
g.setColor(color.ltn).fillPoly([
px(70),py(20),
px(60),py(28),
px(71),py(29),
px(63),py(40),
px(75),py(28),
px(64),py(27)
]);
g.fillPoly([
px(40),py(20),
px(30),py(28),
px(41),py(29),
px(33),py(40),
px(45),py(28),
px(34),py(27)
]);
}
//stars
if (color.star) {
seed = 4;
rand = sfc32(0x9E3779B9, 0x243F6A88, 0xB7E15162, seed);
for (let i = 0; i < 40; i++) {
g.setColor(color.star).drawCircle(Math.floor(rand() * px(100)),Math.floor(rand() * py(33)),Math.floor(rand() * 2));
}
}
//birds
if (color.bird) {
g.setColor(color.bird).fillCircle(px(17),py(12),px(5)).fillCircle(px(23),py(10),px(5));
g.setColor(color.bg1).fillCircle(px(18),py(15),px(6)).fillCircle(px(24),py(13),px(6));
g.setColor(color.bird).fillCircle(px(28),py(19),px(4)).fillCircle(px(33),py(19),px(4));
g.setColor(color.bg1).fillCircle(px(28),py(21),px(5)).fillCircle(px(34),py(21),px(5));
}
//sun/moon
if (color.sun) g.setColor(color.sun).fillCircle(px(65), py(22), py(20));
//path
g.setColor(color.path).fillPoly([
px(60),py(44),
px(39),py(55),
px(72),py(57),
px(30),py(100),
px(70),py(100),
px(78),py(55),
px(46),py(53)
]);
//fog
if (color.fog) {
g.setColor(color.fog);
for (let i = 1; i <= 47; i = i+2) {
g.drawLine(px(0),py(i),px(100),py(i));
}
}
//rain
if (color.rain1) {
g.setColor(color.rain1);
for (let i = 0; i <= 6; i++) {
g.drawLine(px(6+i*20),py(20),px(-14+i*20),py(45));
}
if (color.rain2) {
for (let i = 0; i <= 6; i++) {
g.drawLine(px(16+i*20),py(20),px(-4+i*20),py(45));
}
}
}
//snow
if (color.snow) {
seed = 11;
rand = sfc32(0x9E3779B9, 0x243F6A88, 0xB7E15162, seed);
for (let i = 0; i < 30; i++) {
drawSnow(color.snow, {x:Math.floor(rand() * px(100)), y:(Math.floor(rand() * py(25))+py(20))}, Math.floor(rand() * 3));
}
}
//mountains
drawMtn({mtn1:color.mtn2, mtn2:color.mtn1}, {x:px(35), y:py(30)}, {w:px(38), h:py(17)});
drawMtn({mtn1:color.mtn2, mtn2:color.mtn1}, {x:px(10), y:py(20)}, {w:px(50), h:py(30)});
drawMtn({mtn1:color.mtn1, mtn2:color.mtn2}, {x:px(90), y:py(20)}, {w:px(70), h:py(30)});
//lake
g.setColor(color.lake).fillEllipse(px(-15), py(52), px(30), py(57));
//trees
drawTree({tree1:color.tree2, tree2:color.tree1, tree3:color.tree3}, {x:px(12),y:py(52)}, {w:px(13),h:py(13)});
drawTree({tree1:color.tree2, tree2:color.tree1, tree3:color.tree3}, {x:px(48),y:py(52)}, {w:px(13),h:py(13)});
drawTree({tree1:color.tree2, tree2:color.tree1, tree3:color.tree3}, {x:px(34),y:py(46)}, {w:px(6),h:py(6)});
drawTree({tree1:color.tree1, tree2:color.tree2, tree3:color.tree3}, {x:px(70),y:py(46)}, {w:px(6),h:py(6)});
drawTree({tree1:color.tree1, tree2:color.tree2, tree3:color.tree3}, {x:px(90),y:py(52)}, {w:px(13),h:py(13)});
//clouds
if (color.cloud1) {
g.setColor(color.cloud1);
if (color.cloud2) g.fillRect(0, 0, px(100), py(10));
g.fillCircle(px(3), py(12), py(4));
g.fillCircle(px(10), py(12), py(5));
g.fillCircle(px(16), py(11), py(6));
g.fillCircle(px(24), py(10), py(8));
g.fillCircle(px(30), py(11), py(6));
g.fillCircle(px(35), py(12), py(5));
g.fillCircle(px(40), py(12), py(6));
g.fillCircle(px(48), py(13), py(5));
g.fillCircle(px(55), py(14), py(5));
g.fillCircle(px(60), py(12), py(5));
g.fillCircle(px(65), py(11), py(6));
g.fillCircle(px(75), py(10), py(8));
g.fillCircle(px(85), py(11), py(6));
g.fillCircle(px(90), py(12), py(5));
g.fillCircle(px(97), py(13), py(4));
}
//clock text
(color.clock == undefined) ? g.setColor(0xFFFF) : g.setColor(color.clock);
g.setFont("Vector", py(20)).setFontAlign(-1, -1).drawString((require("locale").time(new Date(), 1).replace(" ", "")), px(2), py(67));
g.setFont("Vector", py(10)).drawString(require('locale').dow(new Date(), 1)+" "+new Date().getDate()+" "+require('locale').month(new Date(), 1)+((data.temp == undefined) ? "" : " | "+require('locale').temp(Math.round(data.temp-273.15)).replace(".0", "")), px(2), py(87));
}
var i = 0;
function setWeather() {
var a = {};
//clear day/night is default weather
if ((data.code >= 800 && data.code <=802) || data.code == undefined) {
if (new Date().getHours() >= 7 && new Date().getHours() <= 19) {
//day-clear
a = {
bg1:0x4FFF, bg2:0x03E0,
sun:0xFD20,
path:0x8200,
mtn1:0x045f, mtn2:0x000F,
lake:0x000F,
tree1:0x07E0, tree2:0, tree3:0x7BE0,
bird:0xFFFF
};
//day-cloudy
if (data.code == 801 || data.code == 802) a.cloud1 = 0xFFFF;
}
else {
//night-clear
a = {
bg1:0, bg2:0x0005,
sun:0xC618,
path:0,
mtn1:0x0210, mtn2:0x0010,
lake:0x000F,
tree1:0x0200, tree2:0, tree3:0x59E0,
star:0xFFFF
};
//night-cloudy
if (data.code == 801 || data.code == 802) a.cloud1 = 0x4208;
}
}
else if (((data.code >= 300) && (data.code < 600)) || ((data.code >= 200) && (data.code < 300)) || data.code == 803 || data.code == 804) {
if (new Date().getHours() >= 7 && new Date().getHours() <= 19) {
//day-overcast
a = {
bg1:0xC618, bg2:0x0200,
path:0x3000,
mtn1:0x3B38, mtn2:0x0005,
lake:0x000F,
tree1:0x03E0, tree2:0, tree3:0x59E0,
cloud1:0x7BEF, cloud2:1
};
//day-lightning
if (data.code >= 200 && data.code < 300) a.ltn = 0xFFFF;
//day-drizzle
if ((data.code >= 300 && data.code < 600) || (data.code >= 200 && data.code <= 202) || (data.code >= 230 && data.code <= 232)) a.rain1 = 0xFFFF;
//day-rain
if ((data.code >= 500 && data.code < 600) || (data.code >= 200 && data.code <= 202)) a.rain2 = 1;
}
else {
//night-overcast
a = {
bg1:0, bg2:0x0005,
path:0,
mtn1:0x0010, mtn2:0x000F,
lake:0x000F,
tree1:0x0200, tree2:0, tree3:0x59E0,
cloud1:0x4208, cloud2:1
};
//night-lightning
if (data.code >= 200 && data.code < 300) a.ltn = 0xFFFF;
//night-drizzle
if ((data.code >= 300 && data.code < 600) || (data.code >= 200 && data.code <= 202) || (data.code >= 230 && data.code <= 232)) a.rain1 = 0xC618;
//night-rain
if ((data.code >= 500 && data.code < 600) || (data.code >= 200 && data.code <= 202)) rain2 = 1;
}
}
else if ((data.code >= 700) && (data.code < 800)) {
if (new Date().getHours() >= 7 && new Date().getHours() <= 19) {
//day-fog
a = {
bg1:0xC618, bg2:0x0200,
path:0x3000,
mtn1:0x3B38, mtn2:0x0005,
lake:0x000F,
tree1:0x03E0, tree2:0, tree3:0x59E0,
fog:0xFFFF
};
}
else {
//night-fog
a = {
bg1:0, bg2:0x0005,
path:0,
mtn1:0x0010, mtn2:0x000F,
lake:0x000F,
tree1:0x0200, tree2:0, tree3:0x59E0,
fog:0x7BEF
};
}
}
else if ((data.code >= 600) && (data.code < 700)) {
if (new Date().getHours() >= 7 && new Date().getHours() <= 19) {
//day-snow
a = {
bg1:0, bg2:0x7BEF,
path:0xC618,
mtn1:0xFFFF, mtn2:0x7BEF,
lake:0x07FF,
tree1:0xC618, tree2:0xC618, tree3:0x59E0,
cloud1:0x7BEF, cloud2:1,
snow:0xFFFF,
clock: 0
};
}
else {
//night-snow
a = {
bg1:0, bg2:0x0005,
path:0,
mtn1:0x0010, mtn2:0x000F,
lake:0x000F,
tree1:0x39E7, tree2:0x39E7, tree3:0x59E0,
cloud1:0x4208, cloud2:1,
snow:0xFFFF
};
}
}
draw(a);
}
const _GB = global.GB;
global.GB = (event) => {
if (event.t==="weather") {
data = event;
require("Storage").write('mtnclock.json', event);
setWeather();
}
if (_GB) setTimeout(_GB, 0, event);
};
var drawTimeout;
//update watchface in next minute
function queueDraw() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
setWeather();
queueDraw();
}, 60000 - (Date.now() % 60000));
}
queueDraw();
setWeather();
Bangle.setUI("clock");

BIN
apps/mtnclock/app.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,25 @@
{
"id": "mtnclock",
"name": "Mountain Pass Clock",
"shortName": "Mtn Clock",
"version": "0.01",
"description": "A clock that changes scenery based on time and weather.",
"readme":"README.md",
"icon": "app.png",
"screenshots": [
{"url":"screenshot1.png"},
{"url":"screenshot2.png"},
{"url":"screenshot3.png"},
{"url":"screenshot4.png"},
{"url":"screenshot5.png"}
],
"type": "clock",
"tags": "clock",
"supports": ["BANGLEJS","BANGLEJS2"],
"allow_emulator": true,
"storage": [
{"name":"mtnclock.app.js","url":"app.js"},
{"name":"mtnclock.img","url":"app-icon.js","evaluate":true}
],
"data": [{"name":"mtnclock.json"}]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB