|
|
|
@ -8,6 +8,8 @@ |
|
|
|
|
#ifdef SYSLOG |
|
|
|
|
#include "syslog.h" |
|
|
|
|
#endif |
|
|
|
|
#include "time.h" |
|
|
|
|
#include "cgiservices.h" |
|
|
|
|
|
|
|
|
|
#ifdef CGISERVICES_DBG |
|
|
|
|
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0) |
|
|
|
@ -26,6 +28,10 @@ char* flash_maps[7] = { |
|
|
|
|
|
|
|
|
|
static ETSTimer reassTimer; |
|
|
|
|
|
|
|
|
|
// Daylight Savings Time support
|
|
|
|
|
static ETSTimer dstTimer; |
|
|
|
|
static bool old_dst; |
|
|
|
|
|
|
|
|
|
// Cgi to update system info (name/description)
|
|
|
|
|
int ICACHE_FLASH_ATTR cgiSystemSet(HttpdConnData *connData) { |
|
|
|
|
if (connData->conn == NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
|
|
|
@ -96,6 +102,144 @@ int ICACHE_FLASH_ATTR cgiSystemInfo(HttpdConnData *connData) { |
|
|
|
|
return HTTPD_CGI_DONE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool ICACHE_FLASH_ATTR isDSTEurope(struct tm *tp) { |
|
|
|
|
int mon = tp->tm_mon + 1; |
|
|
|
|
|
|
|
|
|
if (mon < 3 || tp->tm_mon > 11) return false; |
|
|
|
|
if (mon > 3 && tp->tm_mon < 11) return true; |
|
|
|
|
|
|
|
|
|
int previousSunday = tp->tm_mday - tp->tm_wday; |
|
|
|
|
|
|
|
|
|
if (mon == 10) { |
|
|
|
|
if (previousSunday < 25) |
|
|
|
|
return true; |
|
|
|
|
if (tp->tm_wday > 0) |
|
|
|
|
return false; |
|
|
|
|
if (tp->tm_hour < 2) |
|
|
|
|
return true; |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
if (mon == 3) { |
|
|
|
|
if (previousSunday < 25) |
|
|
|
|
return false; |
|
|
|
|
if (tp->tm_wday > 0) |
|
|
|
|
return true; |
|
|
|
|
if (tp->tm_hour < 2) |
|
|
|
|
return false; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool ICACHE_FLASH_ATTR isDSTUSA(struct tm *tp) { |
|
|
|
|
int month = tp->tm_mon + 1; |
|
|
|
|
|
|
|
|
|
// January, february, and december are out.
|
|
|
|
|
if (month < 3 || month > 11) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
// April to October are in
|
|
|
|
|
if (month > 3 && month < 11) |
|
|
|
|
return true; |
|
|
|
|
|
|
|
|
|
int previousSunday = tp->tm_mday - tp->tm_wday; |
|
|
|
|
|
|
|
|
|
// In march, we are DST if our previous sunday was on or after the 8th.
|
|
|
|
|
if (month == 3) |
|
|
|
|
return previousSunday >= 8; |
|
|
|
|
|
|
|
|
|
// In november we must be before the first sunday to be dst.
|
|
|
|
|
// That means the previous sunday must be before the 1st.
|
|
|
|
|
return previousSunday <= 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* When adding more regions, this must be extended. |
|
|
|
|
* If someone needs a half hour timezone, then it might be better to change |
|
|
|
|
* the return type to int instead of bool. |
|
|
|
|
* It could then mean the number of minutes to add. |
|
|
|
|
*/ |
|
|
|
|
static bool ICACHE_FLASH_ATTR isDST(struct tm *tp) { |
|
|
|
|
switch (flashConfig.dst_mode) { |
|
|
|
|
case DST_EUROPE: |
|
|
|
|
return isDSTEurope(tp); |
|
|
|
|
case DST_USA: |
|
|
|
|
return isDSTUSA(tp); |
|
|
|
|
case DST_NONE: |
|
|
|
|
default: |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static ICACHE_FLASH_ATTR char *dstMode2text(int dm) { |
|
|
|
|
switch(dm) { |
|
|
|
|
case DST_EUROPE: |
|
|
|
|
return "Europe"; |
|
|
|
|
case DST_USA: |
|
|
|
|
return "USA"; |
|
|
|
|
case DST_NONE: |
|
|
|
|
default: |
|
|
|
|
return "None"; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
|
|
/*
|
|
|
|
|
* For debugging only |
|
|
|
|
* This function is called yet another timeout after changing the timezone offset. |
|
|
|
|
* This is the only way to report the time correctly if we're in DST. |
|
|
|
|
*/ |
|
|
|
|
static void ICACHE_FLASH_ATTR dstDelayed2() { |
|
|
|
|
time_t ts = sntp_get_current_timestamp(); |
|
|
|
|
if (ts < 10000) |
|
|
|
|
return; |
|
|
|
|
struct tm *tp = gmtime(&ts); |
|
|
|
|
|
|
|
|
|
os_printf("dstDelayed (dst) : date %04d-%02d-%02d time %02d:%02d:%02d\n", |
|
|
|
|
tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This gets called a while after initializing SNTP. |
|
|
|
|
* The assumption is we will now know the date/time so we can determine whether we're in |
|
|
|
|
* a Daylight Savings Time period. |
|
|
|
|
* And then set the time offset accordingly. |
|
|
|
|
*/ |
|
|
|
|
static void ICACHE_FLASH_ATTR dstDelayed() { |
|
|
|
|
time_t ts = sntp_get_current_timestamp(); |
|
|
|
|
if (ts < 10000) |
|
|
|
|
return; // FIX ME failed to obtain time. Now what ?
|
|
|
|
|
|
|
|
|
|
struct tm *tp = gmtime(&ts); |
|
|
|
|
|
|
|
|
|
bool dst = isDST(tp); |
|
|
|
|
|
|
|
|
|
os_printf("dstDelayed : date %04d-%02d-%02d time %02d:%02d:%02d, wday = %d, DST = %s (%s)\n", |
|
|
|
|
tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec, |
|
|
|
|
tp->tm_wday, dst ? "true" : "false", dstMode2text(flashConfig.dst_mode)); |
|
|
|
|
|
|
|
|
|
old_dst = dst; |
|
|
|
|
|
|
|
|
|
// Only change the timezone offset if we're in DST
|
|
|
|
|
if (dst) { |
|
|
|
|
// Changing timezone offset requires a SNTP stop/start.
|
|
|
|
|
sntp_stop(); |
|
|
|
|
if (! sntp_set_timezone(flashConfig.timezone_offset + 1)) |
|
|
|
|
os_printf("sntp_set_timezone(%d) failed\n", flashConfig.timezone_offset + 1); |
|
|
|
|
sntp_init(); |
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
|
|
// FIX ME for debugging only
|
|
|
|
|
os_timer_disarm(&dstTimer); |
|
|
|
|
os_timer_setfn(&dstTimer, dstDelayed2, NULL); |
|
|
|
|
os_timer_arm(&dstTimer, 5000, 0); // wait 5 seconds
|
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ICACHE_FLASH_ATTR cgiServicesSNTPInit() { |
|
|
|
|
if (flashConfig.sntp_server[0] != '\0') { |
|
|
|
|
sntp_stop(); |
|
|
|
@ -103,7 +247,58 @@ void ICACHE_FLASH_ATTR cgiServicesSNTPInit() { |
|
|
|
|
sntp_setservername(0, flashConfig.sntp_server); |
|
|
|
|
sntp_init(); |
|
|
|
|
} |
|
|
|
|
DBG("SNTP timesource set to %s with offset %d\n", flashConfig.sntp_server, flashConfig.timezone_offset); |
|
|
|
|
old_dst = false; |
|
|
|
|
|
|
|
|
|
// If we support daylight savings time, delay setting the timezone until we know the date/time
|
|
|
|
|
if (flashConfig.dst_mode != 0) { |
|
|
|
|
os_timer_disarm(&dstTimer); |
|
|
|
|
os_timer_setfn(&dstTimer, dstDelayed, NULL); |
|
|
|
|
os_timer_arm(&dstTimer, 5000, 0); // wait 5 seconds
|
|
|
|
|
|
|
|
|
|
DBG("SNTP timesource set to %s with offset %d, awaiting DST info\n", |
|
|
|
|
flashConfig.sntp_server, flashConfig.timezone_offset); |
|
|
|
|
} else { |
|
|
|
|
DBG("SNTP timesource set to %s with offset %d\n", |
|
|
|
|
flashConfig.sntp_server, flashConfig.timezone_offset); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check whether to change DST, at every CMD_GET_TIME call. |
|
|
|
|
* |
|
|
|
|
* If we need to change, then the next call to sntp_get_current_timestamp() will return 0 |
|
|
|
|
* so a retry will be required. The apps already had to cope with such situations, I believe. |
|
|
|
|
*/ |
|
|
|
|
void ICACHE_FLASH_ATTR cgiServicesCheckDST() { |
|
|
|
|
if (flashConfig.dst_mode == 0) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
time_t ts = sntp_get_current_timestamp(); |
|
|
|
|
if (ts < 10000) |
|
|
|
|
return; // FIX ME failed to obtain time. Now what ?
|
|
|
|
|
|
|
|
|
|
struct tm *tp = gmtime(&ts); |
|
|
|
|
bool dst = isDST(tp); |
|
|
|
|
|
|
|
|
|
if (dst != old_dst) { |
|
|
|
|
// Just calling this would be easy but too slow, we already know the new DST setting.
|
|
|
|
|
// cgiServicesSNTPInit();
|
|
|
|
|
|
|
|
|
|
old_dst = dst; |
|
|
|
|
|
|
|
|
|
int add = dst ? 1 : 0; |
|
|
|
|
sntp_stop(); |
|
|
|
|
if (! sntp_set_timezone(flashConfig.timezone_offset + add)) |
|
|
|
|
os_printf("sntp_set_timezone(%d) failed\n", flashConfig.timezone_offset + add); |
|
|
|
|
sntp_init(); |
|
|
|
|
|
|
|
|
|
#if 1 |
|
|
|
|
// FIX ME for debugging only
|
|
|
|
|
os_timer_disarm(&dstTimer); |
|
|
|
|
os_timer_setfn(&dstTimer, dstDelayed2, NULL); |
|
|
|
|
os_timer_arm(&dstTimer, 5000, 0); // wait 5 seconds
|
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -124,7 +319,8 @@ int ICACHE_FLASH_ATTR cgiServicesInfo(HttpdConnData *connData) { |
|
|
|
|
"\"timezone_offset\": %d, " |
|
|
|
|
"\"sntp_server\": \"%s\", " |
|
|
|
|
"\"mdns_enable\": \"%s\", " |
|
|
|
|
"\"mdns_servername\": \"%s\"" |
|
|
|
|
"\"mdns_servername\": \"%s\", " |
|
|
|
|
"\"dst_mode\": \"%d\" " |
|
|
|
|
" }", |
|
|
|
|
#ifdef SYSLOG |
|
|
|
|
flashConfig.syslog_host, |
|
|
|
@ -136,7 +332,13 @@ int ICACHE_FLASH_ATTR cgiServicesInfo(HttpdConnData *connData) { |
|
|
|
|
flashConfig.timezone_offset, |
|
|
|
|
flashConfig.sntp_server, |
|
|
|
|
flashConfig.mdns_enable ? "enabled" : "disabled", |
|
|
|
|
flashConfig.mdns_servername |
|
|
|
|
flashConfig.mdns_servername, |
|
|
|
|
#if 0 |
|
|
|
|
flashConfig.dst_mode ? |
|
|
|
|
(flashConfig.dst_mode == DST_EUROPE ? "Europe" : "USA") |
|
|
|
|
: "None" |
|
|
|
|
#endif |
|
|
|
|
flashConfig.dst_mode |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
jsonHeader(connData, 200); |
|
|
|
@ -172,6 +374,10 @@ int ICACHE_FLASH_ATTR cgiServicesSet(HttpdConnData *connData) { |
|
|
|
|
sntp |= getStringArg(connData, "sntp_server", flashConfig.sntp_server, sizeof(flashConfig.sntp_server)); |
|
|
|
|
if (sntp < 0) return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
|
|
sntp |= getUInt8Arg(connData, "dst_mode", &flashConfig.dst_mode); |
|
|
|
|
os_printf("DSTMODE %d\n", flashConfig.dst_mode); |
|
|
|
|
if (sntp < 0) return HTTPD_CGI_DONE; |
|
|
|
|
|
|
|
|
|
if (sntp > 0) { |
|
|
|
|
cgiServicesSNTPInit(); |
|
|
|
|
} |
|
|
|
|