Merge pull request #3612 from Aircoookie/sunset-fix

workaround for invalid sunrise/sunset times (#3601)
This commit is contained in:
Frank 2023-12-23 20:26:02 +01:00 committed by GitHub
commit 39e0a1fb9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -447,8 +447,8 @@ void checkTimers()
}
#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) {
// get sunrise (or sunset) time (in minutes) for a given day at a given geo location. Returns >= INT16_MAX in case of "no sunset"
static 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 = 275 * month / 9;
float N2 = (month + 9) / 12;
@ -482,8 +482,8 @@ int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunse
//7a. calculate the Sun's local hour angle
float cosH = (sinf(DEG_TO_RAD*ZENITH) - (sinDec * sinf(DEG_TO_RAD*lat))) / (cosDec * cosf(DEG_TO_RAD*lat));
if ((cosH > 1.0f) && !sunset) return 0; // the sun never rises on this location (on the specified date)
if ((cosH < -1.0f) && sunset) return 0; // the sun never sets on this location (on the specified date)
if ((cosH > 1.0f) && !sunset) return INT16_MAX; // the sun never rises on this location (on the specified date)
if ((cosH < -1.0f) && sunset) return INT16_MAX; // 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*acosf(cosH) : 360 - RAD_TO_DEG*acosf(cosH);
@ -499,6 +499,7 @@ int getSunriseUTC(int year, int month, int day, float lat, float lon, bool sunse
return UT*60;
}
#define SUNSET_MAX (24*60) // 1day = max expected absolute value for sun offset in minutes
// calculate sunrise and sunset (if longitude and latitude are set)
void calculateSunriseAndSunset() {
if ((int)(longitude*10.) || (int)(latitude*10.)) {
@ -509,8 +510,19 @@ void calculateSunriseAndSunset() {
tim_0.tm_sec = 0;
tim_0.tm_isdst = 0;
int minUTC = getSunriseUTC(year(localTime), month(localTime), day(localTime), latitude, longitude);
if (minUTC) {
// Due to limited accuracy, its possible to get a bad sunrise/sunset displayed as "00:00" (see issue #3601)
// So in case of invalid result, we try to use the sunset/sunrise of previous day. Max 3 days back, this worked well in all cases I tried.
// When latitude = 66,6 (N or S), the functions sometimes returns 2147483647, so this "unexpected large" is another condition for retry
int minUTC = 0;
int retryCount = 0;
do {
time_t theDay = localTime - retryCount * 86400; // one day back = 86400 seconds
minUTC = getSunriseUTC(year(theDay), month(theDay), day(theDay), latitude, longitude, false);
DEBUG_PRINT(F("* sunrise (minutes from UTC) = ")); DEBUG_PRINTLN(minUTC);
retryCount ++;
} while ((abs(minUTC) > SUNSET_MAX) && (retryCount <= 3));
if (abs(minUTC) <= SUNSET_MAX) {
// there is a sunrise
if (minUTC < 0) minUTC += 24*60; // add a day if negative
tim_0.tm_hour = minUTC / 60;
@ -521,8 +533,15 @@ void calculateSunriseAndSunset() {
sunrise = 0;
}
minUTC = getSunriseUTC(year(localTime), month(localTime), day(localTime), latitude, longitude, true);
if (minUTC) {
retryCount = 0;
do {
time_t theDay = localTime - retryCount * 86400; // one day back = 86400 seconds
minUTC = getSunriseUTC(year(theDay), month(theDay), day(theDay), latitude, longitude, true);
DEBUG_PRINT(F("* sunset (minutes from UTC) = ")); DEBUG_PRINTLN(minUTC);
retryCount ++;
} while ((abs(minUTC) > SUNSET_MAX) && (retryCount <= 3));
if (abs(minUTC) <= SUNSET_MAX) {
// there is a sunset
if (minUTC < 0) minUTC += 24*60; // add a day if negative
tim_0.tm_hour = minUTC / 60;