Support to show time and progress until next sunrise or sunset

pull/1301/head
Marco Heiming 2022-01-14 22:16:49 +01:00
parent 7cfb207781
commit e6326301fb
4 changed files with 110 additions and 7 deletions

View File

@ -9,3 +9,4 @@
Show humidity as weather circle data Show humidity as weather circle data
0.06: Allow settings empty circles 0.06: Allow settings empty circles
Support to choose between humidity and wind speed for weather circle progress Support to choose between humidity and wind speed for weather circle progress
Support to show time and progress until next sunrise or sunset

View File

@ -13,13 +13,13 @@ It can show the following information (this can be configured):
* Humidity or wind speed as circle progress * Humidity or wind speed as circle progress
* Temperature inside circle * Temperature inside circle
* Condition as icon below circle * Condition as icon below circle
* Time and progress until next sunrise or sunset
## Screenshots ## Screenshots
![Screenshot dark theme](screenshot-dark.png) ![Screenshot dark theme](screenshot-dark.png)
![Screenshot light theme](screenshot-light.png) ![Screenshot light theme](screenshot-light.png)
# TODO # TODO
* Add sunrise and sunset
* Display moon instead of sun during night on weather circle * Display moon instead of sun during night on weather circle
## Creator ## Creator

View File

@ -1,6 +1,7 @@
const locale = require("locale"); const locale = require("locale");
const heatshrink = require("heatshrink"); const heatshrink = require("heatshrink");
const storage = require("Storage"); const storage = require("Storage");
const SunCalc = require("https://raw.githubusercontent.com/mourner/suncalc/master/suncalc.js");
const shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA=")); const shoesIcon = heatshrink.decompress(atob("h0OwYJGgmAAgUBkgECgVJB4cSoAUDyEBkARDpADBhMAyQRBgVAkgmDhIUDAAuQAgY1DAAYA="));
const shoesIconGreen = heatshrink.decompress(atob("h0OwYJGhIEDgVIAgUEyQKDkmACgcggVACIeQAYMSgIRCgmApIbDiQUDAAkBkAFDGoYAD")); const shoesIconGreen = heatshrink.decompress(atob("h0OwYJGhIEDgVIAgUEyQKDkmACgcggVACIeQAYMSgIRCgmApIbDiQUDAAkBkAFDGoYAD"));
@ -18,6 +19,9 @@ const weatherSnowy = heatshrink.decompress(atob("iEQwYROn/8AocH8AECuAFBh0Agf+CIN
const weatherFoggy = heatshrink.decompress(atob("iEQwYROn/8AgUB/EfwAFBh/AgfwgED/wIBuEABwd/4EcDQgFDgE4Fosf///8f//A/Lj/xCQIRNA=")); const weatherFoggy = heatshrink.decompress(atob("iEQwYROn/8AgUB/EfwAFBh/AgfwgED/wIBuEABwd/4EcDQgFDgE4Fosf///8f//A/Lj/xCQIRNA="));
const weatherStormy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AoX8gE4AoQpBnAdBF4IRBDQMH/kOHgY7DAo4AOA==")); const weatherStormy = heatshrink.decompress(atob("iEQwYLIg/gAgUB///wAFBh/AgfwgED/wIBuEAj4OCv0AjgaCh/4AoX8gE4AoQpBnAdBF4IRBDQMH/kOHgY7DAo4AOA=="));
const sunSetDown = heatshrink.decompress(atob("iEQwIHEgOAAocT5EGtEEkF//wLDg1ggfACoo"));
const sunSetUp = heatshrink.decompress(atob("iEQwIHEgOAAocT5EGtEEkF//wRFgfAg1gBIY"));
let settings; let settings;
function loadSettings() { function loadSettings() {
@ -127,8 +131,11 @@ function drawCircle(index) {
case "weather": case "weather":
drawWeather(w); drawWeather(w);
break; break;
case "sunprogress":
drawSunProgress(w);
break;
case "empty": case "empty":
// we do nothing here // we draw nothing here
return; return;
} }
} }
@ -295,6 +302,49 @@ function drawWeather(w) {
} }
} }
function drawSunProgress(w) {
if (!w) w = getCirclePosition("sunprogress");
const percent = getSunProgress();
drawCircleBackground(w);
drawGauge(w, h3, percent, colorYellow);
drawInnerCircleAndTriangle(w);
let icon = powerIcon;
let color = colorFg;
if (percent < 1) { // it is before sunset
color = colorFg;
icon = sunSetUp;
} else {
color = colorGrey;
icon = sunSetDown;
}
const times = getSunData();
if (times != undefined) {
const sunRise = Math.round(times.sunrise.getTime() / 1000);
const sunSet = Math.round(times.sunset.getTime() / 1000);
const now = Math.round(new Date().getTime() / 1000);
let text;
if (now > sunRise && now < sunSet) {
text = formatSeconds(sunSet - now);
} else {
// approx sunrise tomorrow:
const upcomingSunRise = sunRise + 60 * 60 * 24;
text = formatSeconds(upcomingSunRise - now);
}
}
writeCircleText(w, text);
g.drawImage(icon, w - 6, h3 + radiusOuter - 6);
}
/* /*
* Choose weather icon to display based on weather conditition code * Choose weather icon to display based on weather conditition code
* https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2 * https://openweathermap.org/weather-conditions#Weather-Condition-Codes-2
@ -344,6 +394,58 @@ function getWeatherIconByCode(code) {
return undefined; return undefined;
} }
function formatSeconds(s) {
if (s > 60 * 60) { // hours
return Math.round(s / (60 * 60)) + "h";
}
if (s > 60) { // minutes
return Math.round(s / (60)) + "m";
}
return s + "s";
}
/*
* Read location from myLocation app
*/
function getLocation() {
return storage.readJSON("mylocation.json", 1) || {
"lat": 51.5072,
"lon": 8.1276,
"location": "London"
};
}
function getSunData() {
const location = getLocation();
if (location != undefined && location.lat != undefined) {
// get today's sunlight times for lat/lon
return SunCalc.getTimes(new Date(), location.lat, location.lon);
}
return undefined;
}
/*
* Calculated progress of the sun between sunrise and sunset in percent
*
* Taken from rebble app and modified
*/
function getSunProgress() {
const times = getSunData();
const sunRise = Math.round(times.sunrise.getTime() / 1000);
const sunSet = Math.round(times.sunset.getTime() / 1000);
const now = Math.round(new Date().getTime() / 1000);
if (now > sunRise && now < sunSet) {
// during day, progress until sunSet
return (now - sunRise) / (sunSet - sunRise);
} else {
// during night, progress until approx sunrise tomorrow:
const upcomingSunRise = sunRise + 60 * 60 * 24;
return ((upcomingSunRise - now) / (upcomingSunRise - sunSet));
}
}
/* /*
* Draws the background and the grey circle * Draws the background and the grey circle
*/ */

View File

@ -7,8 +7,8 @@
storage.write(SETTINGS_FILE, settings); storage.write(SETTINGS_FILE, settings);
} }
const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "empty"]; const valuesCircleTypes = ["steps", "stepsDist", "hr", "battery", "weather", "sunprogress", "empty"];
const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "empty"]; const namesCircleTypes = ["steps", "distance", "heart", "battery", "weather", "sun progress", "empty"];
const weatherData = ["humidity", "wind", "empty"]; const weatherData = ["humidity", "wind", "empty"];
@ -88,19 +88,19 @@
}, },
'left': { 'left': {
value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0, value: settings.circle1 ? valuesCircleTypes.indexOf(settings.circle1) : 0,
min: 0, max: 5, min: 0, max: 6,
format: v => namesCircleTypes[v], format: v => namesCircleTypes[v],
onchange: x => save('circle1', valuesCircleTypes[x]), onchange: x => save('circle1', valuesCircleTypes[x]),
}, },
'middle': { 'middle': {
value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2, value: settings.circle2 ? valuesCircleTypes.indexOf(settings.circle2) : 2,
min: 0, max: 5, min: 0, max: 6,
format: v => namesCircleTypes[v], format: v => namesCircleTypes[v],
onchange: x => save('circle2', valuesCircleTypes[x]), onchange: x => save('circle2', valuesCircleTypes[x]),
}, },
'right': { 'right': {
value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3, value: settings.circle3 ? valuesCircleTypes.indexOf(settings.circle3) : 3,
min: 0, max: 5, min: 0, max: 6,
format: v => namesCircleTypes[v], format: v => namesCircleTypes[v],
onchange: x => save('circle3', valuesCircleTypes[x]), onchange: x => save('circle3', valuesCircleTypes[x]),
} }