mirror of https://github.com/espruino/BangleApps
Support to show time and progress until next sunrise or sunset
parent
7cfb207781
commit
e6326301fb
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
# 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
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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]),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue