Changes for daylight savings time

pull/329/head
Danny Backx 7 years ago
parent e57f29c019
commit 463aa41ecf
  1. 6
      cmd/handlers.c
  2. 212
      esp-link/cgiservices.c
  3. 7
      esp-link/cgiservices.h
  4. 1
      esp-link/config.c
  5. 1
      esp-link/config.h
  6. 11
      html/services.html

@ -18,9 +18,7 @@
#include <socket.h> #include <socket.h>
#endif #endif
#include <ip_addr.h> #include <ip_addr.h>
#include "esp-link/cgi.h" #include <cgiservices.h>
#include "config.h"
#ifdef CMD_DBG #ifdef CMD_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0) #define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
@ -199,6 +197,8 @@ cmdWifiStatus(CmdPacket *cmd) {
// Command handler for time // Command handler for time
static void ICACHE_FLASH_ATTR static void ICACHE_FLASH_ATTR
cmdGetTime(CmdPacket *cmd) { cmdGetTime(CmdPacket *cmd) {
cgiServicesCheckDST(); // This can cause DST to change, so the sntp call to return 0.
cmdResponseStart(CMD_RESP_V, sntp_get_current_timestamp(), 0); cmdResponseStart(CMD_RESP_V, sntp_get_current_timestamp(), 0);
cmdResponseEnd(); cmdResponseEnd();
return; return;

@ -8,6 +8,8 @@
#ifdef SYSLOG #ifdef SYSLOG
#include "syslog.h" #include "syslog.h"
#endif #endif
#include "time.h"
#include "cgiservices.h"
#ifdef CGISERVICES_DBG #ifdef CGISERVICES_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0) #define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
@ -26,6 +28,10 @@ char* flash_maps[7] = {
static ETSTimer reassTimer; static ETSTimer reassTimer;
// Daylight Savings Time support
static ETSTimer dstTimer;
static bool old_dst;
// Cgi to update system info (name/description) // Cgi to update system info (name/description)
int ICACHE_FLASH_ATTR cgiSystemSet(HttpdConnData *connData) { int ICACHE_FLASH_ATTR cgiSystemSet(HttpdConnData *connData) {
if (connData->conn == NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. 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; 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() { void ICACHE_FLASH_ATTR cgiServicesSNTPInit() {
if (flashConfig.sntp_server[0] != '\0') { if (flashConfig.sntp_server[0] != '\0') {
sntp_stop(); sntp_stop();
@ -103,7 +247,58 @@ void ICACHE_FLASH_ATTR cgiServicesSNTPInit() {
sntp_setservername(0, flashConfig.sntp_server); sntp_setservername(0, flashConfig.sntp_server);
sntp_init(); 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, " "\"timezone_offset\": %d, "
"\"sntp_server\": \"%s\", " "\"sntp_server\": \"%s\", "
"\"mdns_enable\": \"%s\", " "\"mdns_enable\": \"%s\", "
"\"mdns_servername\": \"%s\"" "\"mdns_servername\": \"%s\", "
"\"dst_mode\": \"%d\" "
" }", " }",
#ifdef SYSLOG #ifdef SYSLOG
flashConfig.syslog_host, flashConfig.syslog_host,
@ -136,7 +332,13 @@ int ICACHE_FLASH_ATTR cgiServicesInfo(HttpdConnData *connData) {
flashConfig.timezone_offset, flashConfig.timezone_offset,
flashConfig.sntp_server, flashConfig.sntp_server,
flashConfig.mdns_enable ? "enabled" : "disabled", 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); 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)); sntp |= getStringArg(connData, "sntp_server", flashConfig.sntp_server, sizeof(flashConfig.sntp_server));
if (sntp < 0) return HTTPD_CGI_DONE; 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) { if (sntp > 0) {
cgiServicesSNTPInit(); cgiServicesSNTPInit();
} }

@ -3,10 +3,17 @@
#include "httpd.h" #include "httpd.h"
// Need to be in sync with html/services.html
#define DST_NONE 0
#define DST_EUROPE 1
#define DST_USA 2
int cgiSystemSet(HttpdConnData *connData); int cgiSystemSet(HttpdConnData *connData);
int cgiSystemInfo(HttpdConnData *connData); int cgiSystemInfo(HttpdConnData *connData);
void cgiServicesSNTPInit(); void cgiServicesSNTPInit();
void cgiServicesCheckDST();
int cgiServicesInfo(HttpdConnData *connData); int cgiServicesInfo(HttpdConnData *connData);
int cgiServicesSet(HttpdConnData *connData); int cgiServicesSet(HttpdConnData *connData);

@ -34,6 +34,7 @@ FlashConfig flashDefault = {
.data_bits = EIGHT_BITS, .data_bits = EIGHT_BITS,
.parity = NONE_BITS, .parity = NONE_BITS,
.stop_bits = ONE_STOP_BIT, .stop_bits = ONE_STOP_BIT,
.dst_mode = 0,
}; };
typedef union { typedef union {

@ -41,6 +41,7 @@ typedef struct {
int8_t data_bits; int8_t data_bits;
int8_t parity; int8_t parity;
int8_t stop_bits; int8_t stop_bits;
uint8_t dst_mode;
} FlashConfig; } FlashConfig;
extern FlashConfig flashConfig; extern FlashConfig flashConfig;

@ -94,7 +94,16 @@
<div> <div>
<label>Timezone Offset</label> <label>Timezone Offset</label>
<input type="text" name="timezone_offset" /> <input type="text" name="timezone_offset" />
<div class="popup">Offset hours to apply (no daylight savings support)</div> <div class="popup">Offset hours to apply</div>
</div>
<div>
<label>Daylight Savings Time (DST) mode</label>
<select name="dst_mode" href="#">
<option value="0">None</option>
<option value="1">Europe</option>
<option value="2">USA</option>
</select>
<div class="popup">Region specific DST automation</div>
</div> </div>
</div> </div>
<button id="SNTP-button" type="submit" class="pure-button button-primary"> <button id="SNTP-button" type="submit" class="pure-button button-primary">

Loading…
Cancel
Save