diff --git a/openBeken_win32_mvsc2017.vcxproj b/openBeken_win32_mvsc2017.vcxproj index ff57c94a7..393039a89 100644 --- a/openBeken_win32_mvsc2017.vcxproj +++ b/openBeken_win32_mvsc2017.vcxproj @@ -745,6 +745,7 @@ + @@ -1173,4 +1174,4 @@ - \ No newline at end of file + diff --git a/openBeken_win32_mvsc2017.vcxproj.filters b/openBeken_win32_mvsc2017.vcxproj.filters index 3420535df..3ecf3e506 100644 --- a/openBeken_win32_mvsc2017.vcxproj.filters +++ b/openBeken_win32_mvsc2017.vcxproj.filters @@ -274,6 +274,7 @@ + @@ -535,4 +536,4 @@ - \ No newline at end of file + diff --git a/src/cmnds/cmd_if.c b/src/cmnds/cmd_if.c index d1697297c..69654c341 100644 --- a/src/cmnds/cmd_if.c +++ b/src/cmnds/cmd_if.c @@ -298,7 +298,11 @@ float getMonth(const char *s) { float getMDay(const char *s) { return NTP_GetMDay(); } - +#if ENABLE_NTP_DST +float isDST(const char *s){ + return Time_IsDST(); +} +#endif #if ENABLE_NTP_SUNRISE_SUNSET float getSunrise(const char *s) { @@ -475,6 +479,13 @@ const constant_t g_constants[] = { ////cnstdetail:"descr":"", ////cnstdetail:"requires":""} { "$today", &getToday }, +#if ENABLE_NTP_DST + ////cnstdetail:{"name":"$isDST", + ////cnstdetail:"title":"$isDST", + ////cnstdetail:"descr":"", + ////cnstdetail:"requires":""} + { "$isDST", &isDST }, +#endif #if ENABLE_NTP_SUNRISE_SUNSET ////cnstdetail:{"name":"$sunrise", ////cnstdetail:"title":"$sunrise", diff --git a/src/driver/drv_ntp.c b/src/driver/drv_ntp.c index b9ff90fdf..4cbc8678e 100644 --- a/src/driver/drv_ntp.c +++ b/src/driver/drv_ntp.c @@ -14,6 +14,9 @@ #include "drv_ntp.h" +#define LTSTR "Local Time: %04d-%02d-%02d %02d:%02d:%02d" +#define LTM2TIME(T) (T)->tm_year+1900, (T)->tm_mon+1, (T)->tm_mday, (T)->tm_hour, (T)->tm_min, (T)->tm_sec + extern void NTP_Init_Events(void); extern void NTP_RunEvents(unsigned int newTime, bool bTimeValid); @@ -22,6 +25,19 @@ extern void NTP_CalculateSunrise(byte *outHour, byte *outMinute); extern void NTP_CalculateSunset(byte *outHour, byte *outMinute); #endif +#if ENABLE_NTP_DST +static uint32_t Start_DST_epoch=0 , End_DST_epoch=0, next_DST_switch_epoch=0; +static uint8_t nthWeekEnd, monthEnd, dayEnd, hourEnd, nthWeekStart, monthStart, dayStart, hourStart; +static int8_t g_DST_offset=0, g_DST=-128; // g_DST_offset: offset during DST; 0: unset / g_DST: actual DST_offset in hours; -128: not initialised +#define useDST (g_DST_offset) +const uint32_t SECS_PER_MIN = 60UL; +const uint32_t SECS_PER_HOUR = 3600UL; +const uint32_t SECS_PER_DAY = 3600UL * 24UL; +const uint32_t MINS_PER_HOUR = 60UL; +#define LEAP_YEAR(Y) ((!(Y%4) && (Y%100)) || !(Y%400)) +static const uint8_t DaysMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +#endif + #define LOG_FEATURE LOG_FEATURE_NTP typedef struct @@ -104,7 +120,18 @@ commandResult_t NTP_SetTimeZoneOfs(const void *context, const char *cmd, const c } g_ntpTime -= oldOfs; g_ntpTime += g_timeOffsetSeconds; - addLogAdv(LOG_INFO, LOG_FEATURE_NTP,"NTP offset set"); +#if ENABLE_NTP_DST +// in rare cases time can be decreased so time of next DST is wrong +// e.g. by mistake we set offset to two hours in EU and we have just passed start of summertime - next DST switch will be end of summertime +// if we now adjust the clock to the correct offset of one hour, we are slightliy before start of summertime +// so just to be sure, recalculate DST in any case + setDST(1); // setDST will take care of all details +#endif + addLogAdv(LOG_INFO, LOG_FEATURE_NTP,"NTP offset set" +#if ENABLE_NTP_DST + " - DST offset set to %i hours",g_DST +#endif + ); return CMD_RES_OK; } @@ -185,6 +212,182 @@ commandResult_t NTP_Info(const void *context, const char *cmd, const char *args, addLogAdv(LOG_INFO, LOG_FEATURE_NTP, "Server=%s, Time offset=%d", CFG_GetNTPServer(), g_timeOffsetSeconds); return CMD_RES_OK; } + +#if ENABLE_NTP_DST + +// derived from tasmotas "RuleToTime" + +uint32_t RuleToTime(uint8_t dow, uint8_t mo, uint8_t week, uint8_t hr, int yr) { + struct tm tm={0}; + uint32_t t=0; + int i; + uint8_t m=mo-1; // we use struct tm here, so month values are 0..11 + uint8_t w=week; // m and w are copies of mo(nth) and week + + if (0 == w) { // for "Last XX" (w=0), we compute first occurence in following month and go back 7 days + if (++m > 11) { // so go to the next month ... + m = 0; // .. and to next year, if we need last XX in December + yr++; + } + w = 1; // search first week of next month, we will subtract 7 days later + } + + // avoid mktime - this enlarges the image especially for BL602! + // so calculate seconds from epoch locally + // we start by calculating the number of days since 1970 - will also be used to get weekday + uint16_t days; + days = (yr - 1970) * 365; // days per full years + // add one day every leap year - first leap after 1970 is 1972, possible leap years every 4 years + for (i=1972; i < yr; i+=4) days += LEAP_YEAR(i); + for (i=0; i begin before end + if (g_ntpTime < Start_DST_epoch) { + // we are in winter time before start of summer time + next_DST_switch_epoch=Start_DST_epoch; + g_DST=0; +// tempt = (time_t)Start_DST_epoch; +// ADDLOG_INFO(LOG_FEATURE_RAW, "Before first DST switch in %i. Info: DST starts at %lu (%.24s local time)\r\n",year,Start_DST_epoch,ctime(&tempt)); + } else if (g_ntpTime < End_DST_epoch ){ + // we in summer time + next_DST_switch_epoch=End_DST_epoch; + g_DST=g_DST_offset; +// tempt = (time_t)End_DST_epoch; +// ADDLOG_INFO(LOG_FEATURE_RAW, "In DST of %i. Info: DST ends at %lu (%.24s local time)\r\n",year,End_DST_epoch,ctime(&tempt)); + } else { + // we are in winter time, after summer time --> next DST starts in next year + Start_DST_epoch = RuleToTime(dayStart,monthStart,nthWeekStart,hourStart,year+1); + next_DST_switch_epoch=Start_DST_epoch; + g_DST=0; +// tempt = (time_t)Start_DST_epoch; +// ADDLOG_INFO(LOG_FEATURE_RAW, "After DST in %i. Info: Next DST start in next year at %lu (%.24s local time)\r\n",year,Start_DST_epoch,ctime(&tempt)); + } + } else { // so end of DST before begin of DST --> southern + if (g_ntpTime < End_DST_epoch) { + // we in summer time at beginning of the yeay + next_DST_switch_epoch=End_DST_epoch; + g_DST=g_DST_offset; +// tempt = (time_t)End_DST_epoch; +// ADDLOG_INFO(LOG_FEATURE_RAW, "In first DST period of %i. Info: DST ends at %lu (%.24s local time)\r\n",year,End_DST_epoch,ctime(&tempt)); + } else if (g_ntpTime < Start_DST_epoch ){ + // we are in winter time + next_DST_switch_epoch=Start_DST_epoch; + g_DST=0; +// tempt = (time_t)Start_DST_epoch; +// ADDLOG_INFO(LOG_FEATURE_RAW, "Regular time of %i. Info: DST starts at %lu (%.24s local time)\r\n",year,Start_DST_epoch,ctime(&tempt)); + } else { + // we in summer time at the end of the year --> DST will end next year + End_DST_epoch = RuleToTime(dayEnd,monthEnd,nthWeekEnd,hourEnd,year+1); + next_DST_switch_epoch=End_DST_epoch; + g_DST=g_DST_offset; +// tempt = (time_t)End_DST_epoch; +// ADDLOG_INFO(LOG_FEATURE_RAW, "In second DST of %i. Info: DST ends next year at %lu (%.24s local time)\r\n",year,End_DST_epoch,ctime(&tempt)); + } + } + g_ntpTime += (g_DST-old_DST)*3600*setNTP; + tempt = (time_t)next_DST_switch_epoch; + + struct tm *ltm; + ltm = gmtime(&tempt); + ADDLOG_INFO(LOG_FEATURE_RAW, "In %s time - next DST switch at %lu (" LTSTR ")\r\n", + (g_DST)?"summer":"standard", next_DST_switch_epoch, LTM2TIME(ltm)); + return g_DST; + } + else return 0; // DST not (yet) set or can't be calculated (if ntp not synced) + +} + +int IsDST() +{ + if (( g_DST == -128) || (g_ntpTime > next_DST_switch_epoch)) return (setDST(1)); // only in case we don't know DST status, calculate it - and while at it: set ntpTime correctly... + return (g_DST); // otherwise we can safely return the prevously calkulated value +} + +commandResult_t CLOCK_CalcDST(const void *context, const char *cmd, const char *args, int cmdFlags) { + int year=NTP_GetYear(); + time_t te,tb; // time_t of timestamps needed for ctime() to get string of timestamp + + Tokenizer_TokenizeString(args, TOKENIZER_ALLOW_QUOTES); + // following check must be done after 'Tokenizer_TokenizeString', + // so we know arguments count in Tokenizer. 'cmd' argument is + // only for warning display + if (Tokenizer_CheckArgsCountAndPrintWarning(cmd, 8)) { + return CMD_RES_NOT_ENOUGH_ARGUMENTS; + } + +// ADDLOG_INFO(LOG_FEATURE_RAW, "CLOCK_SetConfigs: we have %u Args\r\n", Tokenizer_GetArgsCount()); + nthWeekEnd = Tokenizer_GetArgInteger(0); + monthEnd = Tokenizer_GetArgInteger(1); + dayEnd = Tokenizer_GetArgInteger(2); + hourEnd = Tokenizer_GetArgInteger(3); + nthWeekStart = Tokenizer_GetArgInteger(4); + monthStart = Tokenizer_GetArgInteger(5); + dayStart = Tokenizer_GetArgInteger(6); + hourStart = Tokenizer_GetArgInteger(7); + g_DST_offset=Tokenizer_GetArgIntegerDefault(8, 1); + ADDLOG_INFO(LOG_FEATURE_RAW, "read values: %u,%u,%u,%u,%u,%u,%u,%u,(%u)\r\n", nthWeekEnd, monthEnd, dayEnd, hourEnd, nthWeekStart, monthStart, dayStart, hourStart,g_DST_offset); + +/* Start_DST_epoch = RuleToTime(dayStart,monthStart,nthWeekStart,hourStart,year); + End_DST_epoch = RuleToTime(dayEnd,monthEnd,nthWeekEnd,hourEnd,year); + te=(time_t)End_DST_epoch; + tb=(time_t)Start_DST_epoch; + + ADDLOG_INFO(LOG_FEATURE_RAW, "Calculated DST switch epochs in %i. DST start at %lu (%.24s local time) - DST end at %lu (%.24s local time)\r\n",year,Start_DST_epoch,ctime(&tb),End_DST_epoch,ctime(&te)); +*/ + return CMD_RES_OK; +}; + + + +#endif + + + int NTP_GetWeekDay() { struct tm *ltm; @@ -269,11 +472,19 @@ int NTP_GetYear() { return ltm->tm_year+1900; } +#if ENABLE_NTP_DST +int Time_IsDST(){ + return IsDST(); +} +#endif #if WINDOWS bool b_ntp_simulatedTime = false; void NTP_SetSimulatedTime(unsigned int timeNow) { g_ntpTime = timeNow; g_ntpTime += g_timeOffsetSeconds; +#if ENABLE_NTP_DST + g_ntpTime += setDST(0)*3600; +#endif g_synced = true; b_ntp_simulatedTime = true; } @@ -309,7 +520,13 @@ void NTP_Init() { #if ENABLE_CALENDAR_EVENTS NTP_Init_Events(); #endif - +#if ENABLE_NTP_DST + //cmddetail:{"name":"CLOCK_CalcDST","args":"[nthWeekEnd monthEnd dayEnd hourEnd nthWeekStart monthStart dayStart hourStart [g_DSToffset hours - default is 1 if unset]", + //cmddetail:"descr":"Checks, if actual time is during DST or not.", + //cmddetail:"fn":"CLOCK_CalcDST","file":"driver/drv_ntp.c","requires":"", + //cmddetail:"examples":""} + CMD_RegisterCommand("clock_calcDST",CLOCK_CalcDST, NULL); +#endif addLogAdv(LOG_INFO, LOG_FEATURE_NTP, "NTP driver initialized with server=%s, offset=%d", CFG_GetNTPServer(), g_timeOffsetSeconds); g_synced = false; @@ -319,7 +536,12 @@ unsigned int NTP_GetCurrentTime() { return g_ntpTime; } unsigned int NTP_GetCurrentTimeWithoutOffset() { +#if ENABLE_NTP_DST + return g_ntpTime - g_timeOffsetSeconds - g_DST%128; // if g_DST is unset, it's -128 --> -128%128 = 0 as needed +#else return g_ntpTime - g_timeOffsetSeconds; +#endif + } @@ -440,10 +662,12 @@ void NTP_CheckForReceive() { g_ntpTime = secsSince1900 - NTP_OFFSET; g_ntpTime += g_timeOffsetSeconds; +#if ENABLE_NTP_DST + g_ntpTime += setDST(0)*3600; // just to be sure: recalculate DST before setting, in case we somehow "moved back in time" we start with freshly set g_ntpTime, so don't change it inside setDST()! +#endif addLogAdv(LOG_INFO, LOG_FEATURE_NTP,"Unix time : %u",(unsigned int)g_ntpTime); ltm = gmtime(&g_ntpTime); - addLogAdv(LOG_INFO, LOG_FEATURE_NTP,"Local Time : %04d-%02d-%02d %02d:%02d:%02d", - ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday, ltm->tm_hour, ltm->tm_min, ltm->tm_sec); + addLogAdv(LOG_INFO, LOG_FEATURE_NTP, LTSTR, LTM2TIME(ltm)); if (g_synced == false) { EventHandlers_FireEvent(CMD_EVENT_NTP_STATE, 1); @@ -475,6 +699,13 @@ void NTP_SendRequest_BlockingMode() { void NTP_OnEverySecond() { g_ntpTime++; +#if ENABLE_NTP_DST + if (useDST && (g_ntpTime >= next_DST_switch_epoch)){ + int8_t old_DST=g_DST; + setDST(1); + addLogAdv(LOG_INFO, LOG_FEATURE_NTP,"Passed DST switch time - recalculated DST offset. Was:%i - now:%i",old_DST,g_DST); + } +#endif #if ENABLE_CALENDAR_EVENTS NTP_RunEvents(g_ntpTime, g_synced); @@ -523,8 +754,8 @@ void NTP_AppendInformationToHTTPIndexPage(http_request_t* request) ltm = gmtime(&g_ntpTime); if (g_synced == true) - hprintf255(request, "
NTP (%s): Local Time: %04d-%02d-%02d %02d:%02d:%02d
", - CFG_GetNTPServer(),ltm->tm_year+1900, ltm->tm_mon+1, ltm->tm_mday, ltm->tm_hour, ltm->tm_min, ltm->tm_sec); + hprintf255(request, "
NTP (%s): " LTSTR "
", + CFG_GetNTPServer(),LTM2TIME(ltm)); else hprintf255(request, "
NTP: Syncing with %s....
",CFG_GetNTPServer()); } diff --git a/src/driver/drv_ntp.h b/src/driver/drv_ntp.h index 611505b3e..db29f00a4 100644 --- a/src/driver/drv_ntp.h +++ b/src/driver/drv_ntp.h @@ -27,6 +27,13 @@ int NTP_PrintEventList(); int NTP_GetEventTime(int id); int NTP_RemoveClockEvent(int id); int NTP_ClearEvents(); +#if ENABLE_NTP_DST +int Time_IsDST(); +// usually we want to set/correct g_ntpTime inside setDST() --> call setDST(1) +// only after setting g_ntpTime freshly from an NTP packet --> call setDST(0) +// we must not alter g_ntpTime inside setDST in this case (the old offsets are no longer valid) +uint32_t setDST(bool setNTP); +#endif extern time_t g_ntpTime; extern struct SUN_DATA { /* sunrise / sunset globals */ diff --git a/src/obk_config.h b/src/obk_config.h index 4af7d34bb..bfcc0b304 100644 --- a/src/obk_config.h +++ b/src/obk_config.h @@ -24,6 +24,7 @@ // Some limited drivers are supported on W600, OBK_DISABLE_ALL_DRIVERS is not defined #define ENABLE_TASMOTADEVICEGROUPS 1 #define ENABLE_NTP 1 +//#define ENABLE_NTP_DST 1 #define ENABLE_DRIVER_BL0937 1 #define ENABLE_DRIVER_DHT 1 #define ENABLE_TASMOTA_JSON 1 @@ -41,6 +42,7 @@ #define ENABLE_TASMOTADEVICEGROUPS 1 #define ENABLE_LITTLEFS 1 #define ENABLE_NTP 1 +#define ENABLE_NTP_DST 1 #define ENABLE_DRIVER_LED 1 #define ENABLE_DRIVER_BL0937 1 #define ENABLE_DRIVER_BL0942 1 @@ -87,6 +89,7 @@ #define ENABLE_TASMOTADEVICEGROUPS 1 #define ENABLE_LITTLEFS 1 #define ENABLE_NTP 1 +//#define ENABLE_NTP_DST 1 #define ENABLE_CALENDAR_EVENTS 1 #define ENABLE_DRIVER_LED 1 #define ENABLE_DRIVER_BL0937 1 @@ -109,6 +112,7 @@ #define ENABLE_TASMOTADEVICEGROUPS 1 #define ENABLE_LITTLEFS 1 #define ENABLE_NTP 1 +//#define ENABLE_NTP_DST 1 #define ENABLE_NTP_SUNRISE_SUNSET 1 #define ENABLE_DRIVER_LED 1 #define ENABLE_DRIVER_BL0937 1 @@ -166,6 +170,7 @@ //#define OBK_DISABLE_ALL_DRIVERS 1 #define ENABLE_TASMOTADEVICEGROUPS 1 #define ENABLE_NTP 1 +//#define ENABLE_NTP_DST 1 #define ENABLE_DRIVER_BL0937 1 #define ENABLE_DRIVER_LED 1 #define ENABLE_DRIVER_WEMO 1 @@ -182,6 +187,7 @@ #define ENABLE_I2C 1 #define ENABLE_NTP 1 +//#define ENABLE_NTP_DST 1 #define ENABLE_DRIVER_LED 1 #define ENABLE_DRIVER_TUYAMCU 1 #define ENABLE_LITTLEFS 1 diff --git a/src/selftest/selftest_local.h b/src/selftest/selftest_local.h index 71d314d4c..c028f8286 100644 --- a/src/selftest/selftest_local.h +++ b/src/selftest/selftest_local.h @@ -115,6 +115,7 @@ void Test_RepeatingEvents(); void Test_HTTP_Client(); void Test_DeviceGroups(); void Test_NTP(); +void Test_NTP_DST(); void Test_NTP_SunsetSunrise(); void Test_MQTT(); void Test_Tasmota(); diff --git a/src/selftest/selftest_ntp_DST.c b/src/selftest/selftest_ntp_DST.c new file mode 100644 index 000000000..a0a074cc0 --- /dev/null +++ b/src/selftest/selftest_ntp_DST.c @@ -0,0 +1,161 @@ +#ifdef WINDOWS + +#include "selftest_local.h" + +void Test_NTP_DST() { + // reset whole device + SIM_ClearOBK(0); + + CMD_ExecuteCommand("startDriver NTP", 0); + CMD_ExecuteCommand("ntp_timeZoneOfs 1", 0); + // set Sunday, Mar 31 2024 01:59:55 CET + // that's 5 seconds before DST starts in Europe + NTP_SetSimulatedTime(1711846795); + + SELFTEST_ASSERT_EXPRESSION("$minute",59); + SELFTEST_ASSERT_EXPRESSION("$hour", 1); + SELFTEST_ASSERT_EXPRESSION("$second", 55); + SELFTEST_ASSERT_EXPRESSION("$day", 0); + SELFTEST_ASSERT_EXPRESSION("$mday", 31); + SELFTEST_ASSERT_EXPRESSION("$month", 3); + SELFTEST_ASSERT_EXPRESSION("$year", 2024); + + + + // now set DST information for Europe: + // DST ends last Sunday of October at 3 local (summer) time + // DST starts last Sunday of March at 2 local (standard) time + // arguments are: nthWeekEnd, monthEnd, dayEnd, hourEnd, nthWeekStart, monthStart, dayStart, hourStart + // + // 0 10 1 3 means "End of DST on last(=0) Octobers(=10) Sunday(=1) at 3" + // 0 3 1 2 means "Start of DST on last(=0) Marchs(=3) Sunday(=1) at 2" + CMD_ExecuteCommand("CLOCK_calcDST 0 10 1 3 0 3 1 2", 0); + // test - we are (slightly) "before" DST + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + + // advace 6 seconds, so we are 1 second after 2:00, hence summertime started + // in fact the actual time could never happen, since clock + // advances from 2:00:00 to 3:00:00 clock can't be 2:00:01 on this day + // --> NTP offset should be 2 now, we will set that later + Sim_RunSeconds(6, false); + + // check time + // DST switch should have been done by system + + SELFTEST_ASSERT_EXPRESSION("$hour", 3); + SELFTEST_ASSERT_EXPRESSION("$minute",00); + SELFTEST_ASSERT_EXPRESSION("$second", 01); + // test, that we are _in_ DST now + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + + // set Sunday, Oct 27 2024 02:59:55 CEST + // it's summertime now (for another 5 seconds) + // because that's 5 seconds before DST ends in Europe + NTP_SetSimulatedTime(1729990795); + + SELFTEST_ASSERT_EXPRESSION("$minute",59); + SELFTEST_ASSERT_EXPRESSION("$hour", 2); + SELFTEST_ASSERT_EXPRESSION("$second", 55); + SELFTEST_ASSERT_EXPRESSION("$day", 0); + SELFTEST_ASSERT_EXPRESSION("$mday", 27); + SELFTEST_ASSERT_EXPRESSION("$month", 10); + SELFTEST_ASSERT_EXPRESSION("$year", 2024); + // test, that we are still _in_ DST now + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + + // advace 6 seconds, so we are 1 second after 3:00, hence summertime ended + Sim_RunSeconds(6, false); + + // check time - DST switch should have hapened, so clock was + // turned back for 1 hour + SELFTEST_ASSERT_EXPRESSION("$hour", 2); + SELFTEST_ASSERT_EXPRESSION("$minute",00); + SELFTEST_ASSERT_EXPRESSION("$second", 01); + // test, that we are _not_ in DST any more + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + + // some more tests with directly setting the ntp time + // just checking DST function ... + + // 1743296395 = Sun, Mar 30 2025 01:59:55 CET + CMD_ExecuteCommand("ntp_timeZoneOfs 1", 0); + NTP_SetSimulatedTime(1743296395); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + // 1761440395 = Sun, Oct 26 2025 02:59:55 CEST +// CMD_ExecuteCommand("ntp_timeZoneOfs 2", 0); + NTP_SetSimulatedTime(1761440395); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + + // 1774745995 = Sun, Mar 29 2026 01:59:55 CET + CMD_ExecuteCommand("ntp_timeZoneOfs 1", 0); + NTP_SetSimulatedTime(1774745995); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + // 1792889995 = Sun, Oct 25 2026 02:59:55 CEST +// CMD_ExecuteCommand("ntp_timeZoneOfs 2", 0); + NTP_SetSimulatedTime(1792889995); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + + // 1806195595 = Sun, Mar 28 2027 01:59:55 CET + CMD_ExecuteCommand("ntp_timeZoneOfs 1", 0); + NTP_SetSimulatedTime(1806195595); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + // 1824944395 = Sun, Oct 31 2027 02:59:55 CEST +// CMD_ExecuteCommand("ntp_timeZoneOfs 2", 0); + NTP_SetSimulatedTime(1824944395); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + + // 1837645195 = Sun, Mar 26 2028 01:59:55 CET + CMD_ExecuteCommand("ntp_timeZoneOfs 1", 0); + NTP_SetSimulatedTime(1837645195); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + // 1856393995 = Sun, Oct 29 2028 02:59:55 CEST +// CMD_ExecuteCommand("ntp_timeZoneOfs 2", 0); + NTP_SetSimulatedTime(1856393995); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + + // 1869094795 = Sun, Mar 25 2029 01:59:55 CET + CMD_ExecuteCommand("ntp_timeZoneOfs 1", 0); + NTP_SetSimulatedTime(1869094795); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + // 1887843595 = Sun, Oct 28 2029 02:59:55 CEST +// CMD_ExecuteCommand("ntp_timeZoneOfs 2", 0); + NTP_SetSimulatedTime(1887843595); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + + // 1901149195 = Sun, Mar 31 2030 01:59:55 CET + CMD_ExecuteCommand("ntp_timeZoneOfs 1", 0); + NTP_SetSimulatedTime(1901149195); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + // 1919293195 = Sun, Oct 27 2030 02:59:55 CEST +// CMD_ExecuteCommand("ntp_timeZoneOfs 2", 0); + NTP_SetSimulatedTime(1919293195); + SELFTEST_ASSERT_EXPRESSION("$isDST", 1); + Sim_RunSeconds(6, false); + SELFTEST_ASSERT_EXPRESSION("$isDST", 0); + +} + + +#endif diff --git a/src/win_main.c b/src/win_main.c index 695fc4a11..9d364d0a7 100644 --- a/src/win_main.c +++ b/src/win_main.c @@ -178,6 +178,7 @@ void Win_DoUnitTests() { Test_DHT(); Test_Tasmota(); Test_NTP(); + Test_NTP_DST(); Test_NTP_SunsetSunrise(); Test_HTTP_Client(); Test_ExpandConstant();