Sunrise and sunset calculation and sunrise/sunset triggered presets.

This commit is contained in:
Blaz Kristan 2021-04-12 21:53:22 +02:00
parent c4201d9a2a
commit 9bfe27dd5e
9 changed files with 862 additions and 709 deletions

View File

@ -306,6 +306,8 @@ void deserializeConfig() {
CJSON(currentTimezone, if_ntp[F("tz")]); CJSON(currentTimezone, if_ntp[F("tz")]);
CJSON(utcOffsetSecs, if_ntp[F("offset")]); CJSON(utcOffsetSecs, if_ntp[F("offset")]);
CJSON(useAMPM, if_ntp[F("ampm")]); CJSON(useAMPM, if_ntp[F("ampm")]);
CJSON(longitude, if_ntp[F("ln")]);
CJSON(latitude, if_ntp[F("lt")]);
JsonObject ol = doc[F("ol")]; JsonObject ol = doc[F("ol")];
CJSON(overlayDefault ,ol[F("clock")]); // 0 CJSON(overlayDefault ,ol[F("clock")]); // 0
@ -334,7 +336,8 @@ void deserializeConfig() {
JsonArray timers = tm[F("ins")]; JsonArray timers = tm[F("ins")];
uint8_t it = 0; uint8_t it = 0;
for (JsonObject timer : timers) { for (JsonObject timer : timers) {
if (it > 7) break; if (it > 9) break;
if (it<8 && timer[F("hour")]==255) it=8; // hour==255 -> sunrise/sunset
CJSON(timerHours[it], timer[F("hour")]); CJSON(timerHours[it], timer[F("hour")]);
CJSON(timerMinutes[it], timer[F("min")]); CJSON(timerMinutes[it], timer[F("min")]);
CJSON(timerMacro[it], timer[F("macro")]); CJSON(timerMacro[it], timer[F("macro")]);
@ -617,6 +620,8 @@ void serializeConfig() {
if_ntp[F("tz")] = currentTimezone; if_ntp[F("tz")] = currentTimezone;
if_ntp[F("offset")] = utcOffsetSecs; if_ntp[F("offset")] = utcOffsetSecs;
if_ntp[F("ampm")] = useAMPM; if_ntp[F("ampm")] = useAMPM;
if_ntp[F("ln")] = longitude;
if_ntp[F("lt")] = latitude;
JsonObject ol = doc.createNestedObject("ol"); JsonObject ol = doc.createNestedObject("ol");
ol[F("clock")] = overlayDefault; ol[F("clock")] = overlayDefault;
@ -638,8 +643,8 @@ void serializeConfig() {
JsonArray timers_ins = timers.createNestedArray("ins"); JsonArray timers_ins = timers.createNestedArray("ins");
for (byte i = 0; i < 8; i++) { for (byte i = 0; i < 10; i++) {
if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue; if (timerMacro[i] == 0 && timerHours[i] == 0 && timerMinutes[i] == 0) continue; // sunrise/sunset get saved always (timerHours=255)
JsonObject timers_ins0 = timers_ins.createNestedObject(); JsonObject timers_ins0 = timers_ins.createNestedObject();
timers_ins0["en"] = (timerWeekday[i] & 0x01); timers_ins0["en"] = (timerWeekday[i] & 0x01);
timers_ins0[F("hour")] = timerHours[i]; timers_ins0[F("hour")] = timerHours[i];

View File

@ -49,19 +49,23 @@
ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"250\"></td>"; ih+="<tr><td><input name=\"W"+i+"\" id=\"W"+i+"\" type=\"number\" style=\"display:none\"><input id=\"W"+i+"0\" type=\"checkbox\"></td><td><input name=\"H"+i+"\" type=\"number\" min=\"0\" max=\"24\"></td><td><input name=\"N"+i+"\" type=\"number\" min=\"0\" max=\"59\"></td><td><input name=\"T"+i+"\" type=\"number\" min=\"0\" max=\"250\"></td>";
for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>"; for (j=1;j<8;j++) ih+="<td><input id=\"W"+i+j+"\" type=\"checkbox\"></td>";
} }
ih+="<tr><td><input name=\"W8\" id=\"W8\" type=\"number\" style=\"display:none\"><input id=\"W80\" type=\"checkbox\"></td><td>Sunrise<input name=\"H8\" value=\"255\" type=\"hidden\"></td><td><input name=\"N8\" type=\"number\" min=\"-59\" max=\"59\"></td><td><input name=\"T8\" type=\"number\" min=\"0\" max=\"250\"></td>";
for (j=1;j<8;j++) ih+="<td><input id=\"W8"+j+"\" type=\"checkbox\"></td>";
ih+="<tr><td><input name=\"W9\" id=\"W9\" type=\"number\" style=\"display:none\"><input id=\"W90\" type=\"checkbox\"></td><td>Sunset<input name=\"H9\" value=\"255\" type=\"hidden\"></td><td><input name=\"N9\" type=\"number\" min=\"-59\" max=\"59\"><td><input name=\"T9\" type=\"number\" min=\"0\" max=\"250\"></td>";
for (j=1;j<8;j++) ih+="<td><input id=\"W9"+j+"\" type=\"checkbox\"></td>";
gId("TMT").innerHTML=ih; gId("TMT").innerHTML=ih;
} }
function FC() function FC()
{ {
for(j=0;j<8;j++) for(j=0;j<8;j++)
{ {
for(i=0;i<8;i++) gId("W"+i+j).checked=gId("W"+i).value>>j&1; for(i=0;i<10;i++) gId("W"+i+j).checked=gId("W"+i).value>>j&1;
} }
} }
function Wd() function Wd()
{ {
a=[0,0,0,0,0,0,0,0]; a=[0,0,0,0,0,0,0,0,0,0];
for(i=0;i<8;i++) for(i=0;i<10;i++)
{ {
m=1; m=1;
for(j=0;j<8;j++) for(j=0;j<8;j++)
@ -111,7 +115,10 @@
<option value="18">HST (Hawaii)</option> <option value="18">HST (Hawaii)</option>
</select><br> </select><br>
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br> UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> seconds (max. 18 hours)<br>
Current local time is <span class="times">unknown</span>. Current local time is <span class="times">unknown</span>.<br>
Latitude (N): <input name="LT" type="number" min="-66.6" max="66.6" step="0.01">
Longitude (E): <input name="LN" type="number" min="-180" max="180" step="0.01">
<div id="sun" class="times"></div>
<h3>Clock</h3> <h3>Clock</h3>
Clock Overlay: Clock Overlay:
<select name="OL" onchange="Cs()"> <select name="OL" onchange="Cs()">

View File

@ -135,6 +135,7 @@ bool checkCountdown();
void setCountdown(); void setCountdown();
byte weekdayMondayFirst(); byte weekdayMondayFirst();
void checkTimers(); void checkTimers();
void calculateSunriseAndSunset();
//overlay.cpp //overlay.cpp
void initCronixie(); void initCronixie();

View File

@ -222,8 +222,8 @@ var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki
id="form_s" name="Sf" method="post"><div class="helpB"><button type="button" id="form_s" name="Sf" method="post"><div class="helpB"><button type="button"
onclick="H()">?</button></div><button type="button" onclick="B()">Back</button> onclick="H()">?</button></div><button type="button" onclick="B()">Back</button>
<button type="submit">Save</button><hr><h2>Sync setup</h2><h3>Button setup</h3> <button type="submit">Save</button><hr><h2>Sync setup</h2><h3>Button setup</h3>
Button: <select name="BT"><option value="0">Disabled</option><option value="2"> Button type: <select name="BT"><option value="0">Disabled</option><option
Pushbutton</option><option value="4">Switch</option></select><br> value="2">Pushbutton</option><option value="4">Switch</option></select><br>
Infrared remote: <select name="IR"><option value="0">Disabled</option><option Infrared remote: <select name="IR"><option value="0">Disabled</option><option
value="1">24-key RGB</option><option value="2">24-key with CT</option><option value="1">24-key RGB</option><option value="2">24-key with CT</option><option
value="3">40-key blue</option><option value="4">44-key RGB</option><option value="3">40-key blue</option><option value="4">44-key RGB</option><option
@ -304,7 +304,7 @@ type="submit">Save</button></form></body></html>)=====";
// Autogenerated from wled00/data/settings_time.htm, do not edit!! // Autogenerated from wled00/data/settings_time.htm, do not edit!!
const char PAGE_settings_time[] PROGMEM = R"=====(<!DOCTYPE html><html lang="en"><head><meta name="viewport" content="width=500"> const char PAGE_settings_time[] PROGMEM = R"=====(<!DOCTYPE html><html lang="en"><head><meta name="viewport" content="width=500">
<meta charset="utf-8"><title>Time Settings</title><script> <meta charset="utf-8"><title>Time Settings</title><script>
var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings")}function B(){window.open("/settings","_self")}function S(){BTa(),GetV(),Cs(),FC()}function gId(t){return d.getElementById(t)}function Cs(){gId("cac").style.display="none",gId("coc").style.display="block",gId("ccc").style.display="none",gId("ca").selected&&(gId("cac").style.display="block"),gId("cc").selected&&(gId("coc").style.display="none",gId("ccc").style.display="block"),gId("cn").selected&&(gId("coc").style.display="none")}function BTa(){var t="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";for(i=0;i<8;i++)for(t+='<tr><td><input name="W'+i+'" id="W'+i+'" type="number" style="display:none"><input id="W'+i+'0" type="checkbox"></td><td><input name="H'+i+'" type="number" min="0" max="24"></td><td><input name="N'+i+'" type="number" min="0" max="59"></td><td><input name="T'+i+'" type="number" min="0" max="250"></td>',j=1;j<8;j++)t+='<td><input id="W'+i+j+'" type="checkbox"></td>';gId("TMT").innerHTML=t}function FC(){for(j=0;j<8;j++)for(i=0;i<8;i++)gId("W"+i+j).checked=gId("W"+i).value>>j&1}function Wd(){for(a=[0,0,0,0,0,0,0,0],i=0;i<8;i++){for(m=1,j=0;j<8;j++)a[i]+=gId("W"+i+j).checked*m,m*=2;gId("W"+i).value=a[i]}}function GetV() { var d=document;function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#time-settings")}function B(){window.open("/settings","_self")}function S(){BTa(),GetV(),Cs(),FC()}function gId(t){return d.getElementById(t)}function Cs(){gId("cac").style.display="none",gId("coc").style.display="block",gId("ccc").style.display="none",gId("ca").selected&&(gId("cac").style.display="block"),gId("cc").selected&&(gId("coc").style.display="none",gId("ccc").style.display="block"),gId("cn").selected&&(gId("coc").style.display="none")}function BTa(){var t="<tr><th>Active</th><th>Hour</th><th>Minute</th><th>Preset</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th><th>S</th></tr>";for(i=0;i<8;i++)for(t+='<tr><td><input name="W'+i+'" id="W'+i+'" type="number" style="display:none"><input id="W'+i+'0" type="checkbox"></td><td><input name="H'+i+'" type="number" min="0" max="24"></td><td><input name="N'+i+'" type="number" min="0" max="59"></td><td><input name="T'+i+'" type="number" min="0" max="250"></td>',j=1;j<8;j++)t+='<td><input id="W'+i+j+'" type="checkbox"></td>';for(t+='<tr><td><input name="W8" id="W8" type="number" style="display:none"><input id="W80" type="checkbox"></td><td>Sunrise<input name="H8" value="255" type="hidden"></td><td><input name="N8" type="number" min="-59" max="59"></td><td><input name="T8" type="number" min="0" max="250"></td>',j=1;j<8;j++)t+='<td><input id="W8'+j+'" type="checkbox"></td>';for(t+='<tr><td><input name="W9" id="W9" type="number" style="display:none"><input id="W90" type="checkbox"></td><td>Sunset<input name="H9" value="255" type="hidden"></td><td><input name="N9" type="number" min="-59" max="59"><td><input name="T9" type="number" min="0" max="250"></td>',j=1;j<8;j++)t+='<td><input id="W9'+j+'" type="checkbox"></td>';gId("TMT").innerHTML=t}function FC(){for(j=0;j<8;j++)for(i=0;i<10;i++)gId("W"+i+j).checked=gId("W"+i).value>>j&1}function Wd(){for(a=[0,0,0,0,0,0,0,0,0,0],i=0;i<10;i++){for(m=1,j=0;j<8;j++)a[i]+=gId("W"+i+j).checked*m,m*=2;gId("W"+i).value=a[i]}}function GetV() {
%CSS%%SCSS%</head><body onload="S()"><form %CSS%%SCSS%</head><body onload="S()"><form
id="form_s" name="Sf" method="post" onsubmit="Wd()"><div class="helpB"><button id="form_s" name="Sf" method="post" onsubmit="Wd()"><div class="helpB"><button
type="button" onclick="H()">?</button></div><button type="button" onclick="B()"> type="button" onclick="H()">?</button></div><button type="button" onclick="B()">
@ -323,24 +323,26 @@ CA-Saskatchewan</option><option value="16">ACST</option><option value="17">
ACST/ACDT</option><option value="18">HST (Hawaii)</option></select><br> ACST/ACDT</option><option value="18">HST (Hawaii)</option></select><br>
UTC offset: <input name="UO" type="number" min="-65500" max="65500" required> UTC offset: <input name="UO" type="number" min="-65500" max="65500" required>
seconds (max. 18 hours)<br>Current local time is <span class="times">unknown seconds (max. 18 hours)<br>Current local time is <span class="times">unknown
</span>.<h3>Clock</h3>Clock Overlay: <select name="OL" onchange="Cs()"><option </span>.<br>Latitude (N): <input name="LT" type="number" min="-66.6" max="66.6"
value="0" id="cn" selected="selected">None</option><option value="1" id="ca"> step="0.01"> Longitude (E): <input name="LN" type="number" min="-180" max="180"
Analog Clock</option><option value="2">Single Digit Clock</option><option step="0.01"><div id="sun" class="times"></div><h3>Clock</h3>Clock Overlay:
value="3" id="cc">Cronixie Clock</option></select><br><div id="coc">First LED: <select name="OL" onchange="Cs()"><option value="0" id="cn" selected="selected">
<input name="O1" type="number" min="0" max="255" required> Last LED: <input None</option><option value="1" id="ca">Analog Clock</option><option value="2">
name="O2" type="number" min="0" max="255" required><br><div id="cac">12h LED: Single Digit Clock</option><option value="3" id="cc">Cronixie Clock</option>
<input name="OM" type="number" min="0" max="255" required><br>Show 5min marks: </select><br><div id="coc">First LED: <input name="O1" type="number" min="0"
<input type="checkbox" name="O5"><br></div>Seconds (as trail): <input max="255" required> Last LED: <input name="O2" type="number" min="0" max="255"
type="checkbox" name="OS"><br></div><div id="ccc">Cronixie Display: <input required><br><div id="cac">12h LED: <input name="OM" type="number" min="0"
name="CX" maxlength="6"><br>Cronixie Backlight: <input type="checkbox" max="255" required><br>Show 5min marks: <input type="checkbox" name="O5"><br>
name="CB"><br></div>Countdown Mode: <input type="checkbox" name="CE"><br> </div>Seconds (as trail): <input type="checkbox" name="OS"><br></div><div
Countdown Goal:<br>Year: 20 <input name="CY" type="number" min="0" max="99" id="ccc">Cronixie Display: <input name="CX" maxlength="6"><br>
required> Month: <input name="CI" type="number" min="1" max="12" required> Day: Cronixie Backlight: <input type="checkbox" name="CB"><br></div>Countdown Mode:
<input name="CD" type="number" min="1" max="31" required><br>Hour: <input <input type="checkbox" name="CE"><br>Countdown Goal:<br>Year: 20 <input
name="CH" type="number" min="0" max="23" required> Minute: <input name="CM" name="CY" type="number" min="0" max="99" required> Month: <input name="CI"
type="number" min="0" max="59" required> Second: <input name="CS" type="number" type="number" min="1" max="12" required> Day: <input name="CD" type="number"
min="0" max="59" required><br><h3>Macro presets</h3><b>Macros have moved!</b> min="1" max="31" required><br>Hour: <input name="CH" type="number" min="0"
<br><i> max="23" required> Minute: <input name="CM" type="number" min="0" max="59"
required> Second: <input name="CS" type="number" min="0" max="59" required><br>
<h3>Macro presets</h3><b>Macros have moved!</b><br><i>
Presets now also can be used as macros to save both JSON and HTTP API commands. Presets now also can be used as macros to save both JSON and HTTP API commands.
<br>Just enter the preset id below!</i> <i> <br>Just enter the preset id below!</i> <i>
Use 0 for the default action instead of a preset</i><br>Alexa On/Off Preset: Use 0 for the default action instead of a preset</i><br>Alexa On/Off Preset:

File diff suppressed because it is too large Load Diff

View File

@ -198,6 +198,9 @@ bool checkNTPResponse()
setTime(epoch); setTime(epoch);
DEBUG_PRINTLN(epoch); DEBUG_PRINTLN(epoch);
if (countdownTime - now() > 0) countdownOverTriggered = false; if (countdownTime - now() > 0) countdownOverTriggered = false;
// if time changed re-calculate sunrise/sunset
updateLocalTime();
calculateSunriseAndSunset();
return true; return true;
} }
return false; return false;
@ -219,9 +222,7 @@ void getTimeString(char* out)
if (hr > 11) hr -= 12; if (hr > 11) hr -= 12;
if (hr == 0) hr = 12; if (hr == 0) hr = 12;
} }
sprintf(out,"%i-%i-%i, %i:%s%i:%s%i",year(localTime), month(localTime), day(localTime), sprintf_P(out,PSTR("%i-%i-%i, %02d:%02d:%02d"),year(localTime), month(localTime), day(localTime), hr, minute(localTime), second(localTime));
hr,(minute(localTime)<10)?"0":"",minute(localTime),
(second(localTime)<10)?"0":"",second(localTime));
if (useAMPM) if (useAMPM)
{ {
strcat(out,(hour(localTime) > 11)? " PM":" AM"); strcat(out,(hour(localTime) > 11)? " PM":" AM");
@ -264,16 +265,136 @@ void checkTimers()
if (lastTimerMinute != minute(localTime)) //only check once a new minute begins if (lastTimerMinute != minute(localTime)) //only check once a new minute begins
{ {
lastTimerMinute = minute(localTime); lastTimerMinute = minute(localTime);
// re-calculate sunrise and sunset just after midnight
if (!hour(localTime) && minute(localTime)==1) calculateSunriseAndSunset();
DEBUG_PRINTF("Local time: %02d:%02d\n", hour(localTime), minute(localTime));
for (uint8_t i = 0; i < 8; i++) for (uint8_t i = 0; i < 8; i++)
{ {
if (timerMacro[i] != 0 if (timerMacro[i] != 0
&& (timerHours[i] == hour(localTime) || timerHours[i] == 24) //if hour is set to 24, activate every hour && (timerHours[i] == hour(localTime) || timerHours[i] == 24) //if hour is set to 24, activate every hour
&& timerMinutes[i] == minute(localTime) && timerMinutes[i] == minute(localTime)
&& (timerWeekday[i] & 0x01) //timer is enabled && (timerWeekday[i] & 0x01) //timer is enabled
&& timerWeekday[i] >> weekdayMondayFirst() & 0x01) //timer should activate at current day of week && ((timerWeekday[i] >> weekdayMondayFirst()) & 0x01)) //timer should activate at current day of week
{ {
applyPreset(timerMacro[i]); applyPreset(timerMacro[i]);
} }
} }
// sunrise macro
if (sunrise) {
time_t tmp = sunrise + timerMinutes[8]*60; // NOTE: may not be ok
DEBUG_PRINTF("Trigger time: %02d:%02d\n", hour(tmp), minute(tmp));
if (timerMacro[8] != 0
&& hour(tmp) == hour(localTime)
&& minute(tmp) == minute(localTime)
&& (timerWeekday[8] & 0x01) //timer is enabled
&& ((timerWeekday[8] >> weekdayMondayFirst()) & 0x01)) //timer should activate at current day of week
{
applyPreset(timerMacro[8]);
DEBUG_PRINTF("Sunrise macro %d triggered.",timerMacro[8]);
}
}
// sunset macro
if (sunset) {
time_t tmp = sunset + timerMinutes[9]*60; // NOTE: may not be ok
DEBUG_PRINTF("Trigger time: %02d:%02d\n", hour(tmp), minute(tmp));
if (timerMacro[9] != 0
&& hour(tmp) == hour(localTime)
&& minute(tmp) == minute(localTime)
&& (timerWeekday[9] & 0x01) //timer is enabled
&& ((timerWeekday[9] >> weekdayMondayFirst()) & 0x01)) //timer should activate at current day of week
{
applyPreset(timerMacro[9]);
DEBUG_PRINTF("Sunset macro %d triggered.",timerMacro[9]);
}
}
}
}
#define ZENITH -0.83
// get sunrise (or sunset) time (in minutes) for a given day at a given geo location
int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunset=false) {
//1. first calculate the day of the year
float N1 = floor(275 * month / 9);
float N2 = floor((month + 9) / 12);
float N3 = (1 + floor((year - 4 * floor(year / 4) + 2) / 3));
float N = N1 - (N2 * N3) + day - 30;
//2. convert the longitude to hour value and calculate an approximate time
float lngHour = lon / 15.0;
float t = N + (((sunset ? 18 : 6) - lngHour) / 24);
//3. calculate the Sun's mean anomaly
float M = (0.9856 * t) - 3.289;
//4. calculate the Sun's true longitude
float L = fmod(M + (1.916 * sin(DEG_TO_RAD*M)) + (0.020 * sin(2*DEG_TO_RAD*M)) + 282.634, 360.0);
//5a. calculate the Sun's right ascension
float RA = fmod(RAD_TO_DEG*atan(0.91764 * tan(DEG_TO_RAD*L)), 360.0);
//5b. right ascension value needs to be in the same quadrant as L
float Lquadrant = floor( L/90) * 90;
float RAquadrant = floor(RA/90) * 90;
RA = RA + (Lquadrant - RAquadrant);
//5c. right ascension value needs to be converted into hours
RA /= 15.;
//6. calculate the Sun's declination
float sinDec = 0.39782 * sin(DEG_TO_RAD*L);
float cosDec = cos(asin(sinDec));
//7a. calculate the Sun's local hour angle
float cosH = (sin(DEG_TO_RAD*ZENITH) - (sinDec * sin(DEG_TO_RAD*lat))) / (cosDec * cos(DEG_TO_RAD*lat));
if (cosH > 1 && !sunset) return 0; // the sun never rises on this location (on the specified date)
if (cosH < -1 && sunset) return 0; // the sun never sets on this location (on the specified date)
//7b. finish calculating H and convert into hours
float H = sunset ? RAD_TO_DEG*acos(cosH) : 360 - RAD_TO_DEG*acos(cosH);
H /= 15.;
//8. calculate local mean time of rising/setting
float T = H + RA - (0.06571 * t) - 6.622;
//9. adjust back to UTC
float UT = fmod(T - lngHour, 24.0);
// return in minutes from midnight
return UT*60;
}
// calculate sunrise and sunset (if longitude and latitude are set)
void calculateSunriseAndSunset() {
if ((int)(longitude*10.) || (int)(latitude*10.)) {
struct tm tim_0;
tim_0.tm_year = year(localTime)-1900;
tim_0.tm_mon = month(localTime)-1;
tim_0.tm_mday = day(localTime);
tim_0.tm_sec = 0;
tim_0.tm_isdst = 0;
int minUTC = getSunriseUTC(year(localTime), month(localTime), day(localTime), latitude, longitude);
if (minUTC) {
// there is a sunrise
tim_0.tm_hour = minUTC / 60;
tim_0.tm_min = minUTC % 60;
sunrise = tz->toLocal(mktime(&tim_0) - utcOffsetSecs);
DEBUG_PRINTF("Sunrise: %02d:%02d\n", hour(sunrise), minute(sunrise));
} else {
sunrise = 0;
}
minUTC = getSunriseUTC(year(localTime), month(localTime), day(localTime), latitude, longitude, true);
if (minUTC) {
// there is a sunset
tim_0.tm_hour = minUTC / 60;
tim_0.tm_min = minUTC % 60;
sunset = tz->toLocal(mktime(&tim_0) - utcOffsetSecs);
DEBUG_PRINTF("Sunset: %02d:%02d\n", hour(sunset), minute(sunset));
} else {
sunset = 0;
}
} }
} }

View File

@ -292,6 +292,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
//start ntp if not already connected //start ntp if not already connected
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort); if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
longitude = request->arg(F("LN")).toFloat();
latitude = request->arg(F("LT")).toFloat();
// force a sunrise/sunset re-calculation
calculateSunriseAndSunset();
if (request->hasArg(F("OL"))) { if (request->hasArg(F("OL"))) {
overlayDefault = request->arg(F("OL")).toInt(); overlayDefault = request->arg(F("OL")).toInt();
overlayCurrent = overlayDefault; overlayCurrent = overlayDefault;
@ -323,7 +328,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
macroDoublePress = request->arg(F("MD")).toInt(); macroDoublePress = request->arg(F("MD")).toInt();
char k[3]; k[2] = 0; char k[3]; k[2] = 0;
for (int i = 0; i<8; i++) for (int i = 0; i<10; i++)
{ {
k[1] = i+48;//ascii 0,1,2,3 k[1] = i+48;//ascii 0,1,2,3

View File

@ -452,10 +452,10 @@ WLED_GLOBAL bool countdownOverTriggered _INIT(true);
// timer // timer
WLED_GLOBAL byte lastTimerMinute _INIT(0); WLED_GLOBAL byte lastTimerMinute _INIT(0);
WLED_GLOBAL byte timerHours[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0 })); WLED_GLOBAL byte timerHours[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
WLED_GLOBAL byte timerMinutes[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0 })); WLED_GLOBAL int8_t timerMinutes[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
WLED_GLOBAL byte timerMacro[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0 })); WLED_GLOBAL byte timerMacro[] _INIT_N(({ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }));
WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 255 })); // weekdays to activate on WLED_GLOBAL byte timerWeekday[] _INIT_N(({ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 })); // weekdays to activate on
// bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity // bit pattern of arr elem: 0b11111111: sun,sat,fri,thu,wed,tue,mon,validity
// blynk // blynk
@ -503,6 +503,10 @@ WLED_GLOBAL unsigned long ntpPacketSentTime _INIT(999000000L);
WLED_GLOBAL IPAddress ntpServerIP; WLED_GLOBAL IPAddress ntpServerIP;
WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390); WLED_GLOBAL uint16_t ntpLocalPort _INIT(2390);
WLED_GLOBAL uint16_t rolloverMillis _INIT(0); WLED_GLOBAL uint16_t rolloverMillis _INIT(0);
WLED_GLOBAL float longitude _INIT(0.0);
WLED_GLOBAL float latitude _INIT(0.0);
WLED_GLOBAL time_t sunrise _INIT(0);
WLED_GLOBAL time_t sunset _INIT(0);
// Temp buffer // Temp buffer
WLED_GLOBAL char* obuf; WLED_GLOBAL char* obuf;

View File

@ -434,8 +434,16 @@ void getSettingsJS(byte subPage, char* dest)
sappend('i',SET_F("TZ"),currentTimezone); sappend('i',SET_F("TZ"),currentTimezone);
sappend('v',SET_F("UO"),utcOffsetSecs); sappend('v',SET_F("UO"),utcOffsetSecs);
char tm[32]; char tm[32];
dtostrf(longitude,4,2,tm);
sappends('s',SET_F("LN"),tm);
dtostrf(latitude,4,2,tm);
sappends('s',SET_F("LT"),tm);
getTimeString(tm); getTimeString(tm);
sappends('m',SET_F("(\"times\")[0]"),tm); sappends('m',SET_F("(\"times\")[0]"),tm);
if ((int)(longitude*10.) || (int)(latitude*10.)) {
sprintf_P(tm, PSTR("Sunrise: %02d:%02d Sunset: %02d:%02d"), hour(sunrise), minute(sunrise), hour(sunset), minute(sunset));
sappends('m',SET_F("(\"times\")[1]"),tm);
}
sappend('i',SET_F("OL"),overlayCurrent); sappend('i',SET_F("OL"),overlayCurrent);
sappend('v',SET_F("O1"),overlayMin); sappend('v',SET_F("O1"),overlayMin);
sappend('v',SET_F("O2"),overlayMax); sappend('v',SET_F("O2"),overlayMax);
@ -462,10 +470,10 @@ void getSettingsJS(byte subPage, char* dest)
char k[4]; char k[4];
k[2] = 0; //Time macros k[2] = 0; //Time macros
for (int i = 0; i<8; i++) for (int i = 0; i<10; i++)
{ {
k[1] = 48+i; //ascii 0,1,2,3 k[1] = 48+i; //ascii 0,1,2,3
k[0] = 'H'; sappend('v',k,timerHours[i]); if (i<8) { k[0] = 'H'; sappend('v',k,timerHours[i]); }
k[0] = 'N'; sappend('v',k,timerMinutes[i]); k[0] = 'N'; sappend('v',k,timerMinutes[i]);
k[0] = 'T'; sappend('v',k,timerMacro[i]); k[0] = 'T'; sappend('v',k,timerMacro[i]);
k[0] = 'W'; sappend('v',k,timerWeekday[i]); k[0] = 'W'; sappend('v',k,timerWeekday[i]);