Add new Weather Clock clock face.
16
apps.json
|
@ -4675,5 +4675,21 @@
|
||||||
"data": [
|
"data": [
|
||||||
{"name":"pooqroman.json"}
|
{"name":"pooqroman.json"}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "weatherclk",
|
||||||
|
"name": "Weather Clock",
|
||||||
|
"version": "0.01",
|
||||||
|
"description": "A clock which displays current weather conditions.",
|
||||||
|
"icon": "app.png",
|
||||||
|
"screenshots": [{"url":"screens/screenshot1.png"}],
|
||||||
|
"type": "clock",
|
||||||
|
"tags": "clock, weather",
|
||||||
|
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||||
|
"allow_emulator": true,
|
||||||
|
"storage": [
|
||||||
|
{"name":"weatherclk.app.js","url":"app.js"},
|
||||||
|
{"name":"weatherclk.img","url":"app-icon.js","evaluate":true}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0.01: New App!
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Weather Clock
|
||||||
|
|
||||||
|
A clock which displays the current weather conditions. Temperature, wind speed, and an icon indicating the weather conditions are displayed.
|
||||||
|
|
||||||
|
Standard widgets are displayed.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
**This clock requires Gadgetbridge and the weather app in order to get weather data!**
|
||||||
|
|
||||||
|
See the [Bangle.js Gadgetbridge documentation](https://www.espruino.com/Gadgetbridge) for instructions on setting up Gadgetbridge and weather.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Creator
|
||||||
|
|
||||||
|
James Gough
|
|
@ -0,0 +1 @@
|
||||||
|
require("heatshrink").decompress(atob("mEwwkE/4A/AH4A/ADEzAgk/AogACn/zAgYLBmMACAQEBgMvAwUQgAABj8wAgUD//yAgIQFBQIXFl4XFmETC4QcBn8xgQXDGgYACmAXBmQMBC4UB//zAQJoBC4JmE/8gj4kDC48Qn8QJAIxEBIIXFCgM/+IXELIIGBBwYcEAYcBCARHCiczNIINB+JrDC4inBFAjKCLQZ2CC4zRCHYgXFkBkFKAUSPQYABkJEBVQZ2DmUigEikfzgESiA7BkU/mEBkJfCOwjdFL4QnBEwL8CHIJ2F+ciAAI6CmUjAYRmCAwQSBbgoA/AG3zXoMvkMv+Uj+U/mcxBYP/kciTQMimKRCBYPyj/xXIMydYMvmKqBUYIWBkcyC4bmBmMT+P/C4Uzn/xEYXziYXBkYnBbAczmfyC4MT+bWBkMiiQKBiUyAoMhj6RzMgYASn3dmazIAYYmG/ve93dC48iCYMzAYQXF93u9oXIl4uBAQIAFCwIAB74XKkYvGIwIXJYQIDCC43+I4QKFAoh6Cn4IEO4RfF+QtDGQcTMQn97oABC4si+cRkcikIUBAQQAE6a8GiXzkUykUiZgMjj7gNEwMzXoLWCL4oANCSQAl"))
|
|
@ -0,0 +1,136 @@
|
||||||
|
const Layout = require("Layout");
|
||||||
|
const storage = require('Storage');
|
||||||
|
const locale = require("locale");
|
||||||
|
|
||||||
|
// weather icons from https://icons8.com/icon/set/weather/color
|
||||||
|
var sunIcon = require("heatshrink").decompress(atob("mEwwhC/AH4AbhvQC6vd7ouVC4IwUCwIwUFwQwQCYgAHDZQXc9wACC6QWDDAgXN7wXF9oXPCwowDC5guGGAYXMCw4wCC5RGJJAZGTJBiNISIylQVJrLCC5owGF65fXR7AwBC5jvhC7JIILxapDFxAXOGAy9KC4owGBAQXODAgHDC54AHC8T0FAAQSOGg4qPGA4WUGAIuVC7AA/AH4AEA="));
|
||||||
|
|
||||||
|
var partSunIcon = require("heatshrink").decompress(atob("mEwwhC/AH4AY6AWVhvdC6vd7owUFwIABFiYAFGR4Xa93u9oXTCwIYDC6HeC4fuC56MBC4ySOIwpIQXYQXHmYABRpwXECwQYKF5HjC4kwL5gQCAYYwO7wqFAAowK7wWKJBgXLJBPd6YX/AAoVMAAM/Cw0DC5yRHCx5JGFyAwGCyIwFC/4XyR4inXa64wRFwowQCw4A/AH4AkA"));
|
||||||
|
|
||||||
|
var cloudIcon = require("heatshrink").decompress(atob("mEwwhC/AH4A/AH4AtgczmYWWDCgWDmcwIKAuEGBoSGGCAWKC7BIKIxYX6CpgABn4tUSJIWPJIwuQGAwWRGAoX/C+SPEU67XXGCIuFGCAWHAH4A/AH4A/ADg="));
|
||||||
|
|
||||||
|
var snowIcon = require("heatshrink").decompress(atob("mEwwhC/AH4AhxGAC9YUBC4QZRhAVBAIWIC6QAEI6IYEI5cIBgwWOC64NCKohHPNox3RBgqnQEo7XPHpKONR5AXYAH4ASLa4XWXILiBC6r5LDBgWWDBRrKC5hsCEacIHawvMCIwvQC5QvQFAROEfZ5ADLJ4YGCywvVI7CPGC9IA/AH4AF"));
|
||||||
|
|
||||||
|
var rainIcon = require("heatshrink").decompress(atob("mEwwhC/AH4AFgczmYWWDCgWDmcwIKAuEGBoSGGCAWKC7BIKIxYX6CpgABn4tUSJIWPJIwuQGAwWRGAoX/C+SPEU67XXGCIuFGCAWHAGeIBJEIwAVJhGIC5AJBC5QMJEJQMEC44JBC6QSCC54FHLxgNBBgYSEDgKpPMhQXneSwuUAH4A/AA4="));
|
||||||
|
|
||||||
|
var stormIcon = require("heatshrink").decompress(atob("mEwwhC/AFEzmcwCyoYUgYXDmYuVGAY0OFwocHC6pNLCxYXYJBQXuCxhhJRpgYKCyBKFFyIXFCyJIFC/4XaO66nU3eza6k7C4IWFGBwXBCwwwO3ewC5AZMC6RaCIxZiI3e7AYYwRCQIIBC4QwPIQIpDC5owDhYREIxgAEFIouNC4orDFyBGBGAcLC6BaFhYWRLSRIFISQXcCyqhRAH4Az"));
|
||||||
|
|
||||||
|
// err icon - https://icons8.com/icons/set/error
|
||||||
|
var errIcon = require("heatshrink").decompress(atob("mEwwkBiIA/AH4AZUAIWUiAXBWqgXXdIYuVGCgXBgICCIyYXCJCQTDC6QrEMCQSEJCQRFC6ApGJCCiDDQSpQFAYXEJBqNGJCA/EC4ZIOEwgXFJBgNEAhKlNAgxIKBgoXEJBjsLC5TsIeRycMBhRrMMBKzQEozjOBxAgHGww+IA6wfSH4hnIC47OMSJqlRIJAXCACIXaGoQARPwwuTAH4A/ABw"));
|
||||||
|
|
||||||
|
/**
|
||||||
|
Choose weather icon to display based on condition.
|
||||||
|
Based on function from the Bangle weather app so it should handle all of the conditions
|
||||||
|
sent from gadget bridge.
|
||||||
|
*/
|
||||||
|
function chooseIcon(condition) {
|
||||||
|
condition = condition.toLowerCase();
|
||||||
|
if (condition.includes("thunderstorm")) return stormIcon;
|
||||||
|
if (condition.includes("freezing")||condition.includes("snow")||
|
||||||
|
condition.includes("sleet")) {
|
||||||
|
return snowIcon;
|
||||||
|
}
|
||||||
|
if (condition.includes("drizzle")||
|
||||||
|
condition.includes("shower")) {
|
||||||
|
return rainIcon;
|
||||||
|
}
|
||||||
|
if (condition.includes("rain")) return rainIcon;
|
||||||
|
if (condition.includes("clear")) return sunIcon;
|
||||||
|
if (condition.includes("few clouds")) return partSunIcon;
|
||||||
|
if (condition.includes("scattered clouds")) return cloudIcon;
|
||||||
|
if (condition.includes("clouds")) return cloudIcon;
|
||||||
|
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 cloudIcon;
|
||||||
|
}
|
||||||
|
return cloudIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get weather stored in json file by weather app.
|
||||||
|
*/
|
||||||
|
function getWeather() {
|
||||||
|
let jsonWeather = storage.readJSON('weather.json');
|
||||||
|
return jsonWeather;
|
||||||
|
}
|
||||||
|
|
||||||
|
var clockLayout = 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: [
|
||||||
|
{type:"txt", font:"10%", label:"THU", id:"dow" },
|
||||||
|
{type:"txt", font:"10%", label:"01/01/1970", id:"date" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{type: "v", fillx: 1, c: [
|
||||||
|
{type: "h", valign : 1, fillx:1, c: [
|
||||||
|
{type: "img", filly: 1, id: "weatherIcon", src: sunIcon},
|
||||||
|
{type: "v", fillx:1, c: [
|
||||||
|
{type: "h", c: [
|
||||||
|
{type: "txt", font: "10%", id: "temp", label: "000"},
|
||||||
|
{type: "txt", font: "10%", id: "tempUnit", label: "°C"},
|
||||||
|
]},
|
||||||
|
{type: "h", c: [
|
||||||
|
{type: "txt", font: "10%", id: "wind", label: "00"},
|
||||||
|
{type: "txt", font: "10%", id: "windUnit", label: "km/h"},
|
||||||
|
]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]},
|
||||||
|
]}]
|
||||||
|
});
|
||||||
|
|
||||||
|
// timeout used to update every minute
|
||||||
|
var drawTimeout;
|
||||||
|
|
||||||
|
// schedule a draw for the next minute
|
||||||
|
function queueDraw() {
|
||||||
|
if (drawTimeout) clearTimeout(drawTimeout);
|
||||||
|
drawTimeout = setTimeout(function() {
|
||||||
|
drawTimeout = undefined;
|
||||||
|
draw();
|
||||||
|
}, 60000 - (Date.now() % 60000));
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
var date = new Date();
|
||||||
|
clockLayout.time.label = locale.time(date, 1);
|
||||||
|
clockLayout.date.label = locale.date(date, 1).toUpperCase();
|
||||||
|
clockLayout.dow.label = locale.dow(date, 1).toUpperCase();
|
||||||
|
var weatherJson = getWeather();
|
||||||
|
if(weatherJson){
|
||||||
|
var currentWeather = weatherJson.weather;
|
||||||
|
const temp = locale.temp(currentWeather.temp-273.15).match(/^(\D*\d*)(.*)$/);
|
||||||
|
clockLayout.temp.label = temp[1];
|
||||||
|
clockLayout.tempUnit.label = temp[2];
|
||||||
|
clockLayout.weatherIcon.src = chooseIcon(currentWeather.txt);
|
||||||
|
const wind = locale.speed(currentWeather.wind).match(/^(\D*\d*)(.*)$/);
|
||||||
|
clockLayout.wind.label = wind[1] + " ";
|
||||||
|
clockLayout.windUnit.label = wind[2] + " " + (currentWeather.wrose||'').toUpperCase();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
clockLayout.temp.label = "Err";
|
||||||
|
clockLayout.tempUnit.label = "";
|
||||||
|
clockLayout.wind.label = "No Data";
|
||||||
|
clockLayout.windUnit.label = "";
|
||||||
|
clockLayout.weatherIcon.src = errIcon;
|
||||||
|
}
|
||||||
|
clockLayout.clear();
|
||||||
|
clockLayout.render();
|
||||||
|
// queue draw in one minute
|
||||||
|
queueDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
g.clear();
|
||||||
|
Bangle.setUI("clock"); // Show launcher when middle button pressed
|
||||||
|
Bangle.loadWidgets();
|
||||||
|
Bangle.drawWidgets();
|
||||||
|
clockLayout.render();
|
||||||
|
draw();
|
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 654 B |
After Width: | Height: | Size: 683 B |
After Width: | Height: | Size: 950 B |
After Width: | Height: | Size: 863 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 725 B |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 3.1 KiB |