timezone support

This commit is contained in:
Paul
2019-11-01 15:04:17 +01:00
parent 905ae885f7
commit 6275245b03
14 changed files with 642 additions and 136 deletions

View File

@@ -97,8 +97,9 @@ MyESP::MyESP() {
// ntp
_ntp_server = strdup(MYESP_NTP_SERVER);
_ntp_interval = 60;
_ntp_interval = NTP_INTERVAL_DEFAULT;
_ntp_enabled = false;
_ntp_timezone = NTP_TIMEZONE_DEFAULT;
// get the build time
_buildTime = _getBuildTime();
@@ -251,8 +252,8 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) {
// NTP now that we have a WiFi connection
if (_ntp_enabled) {
NTP.Ntp(_ntp_server, _ntp_interval); // set up NTP server
myDebug_P(PSTR("[NTP] NTP internet time enabled via server %s"), _ntp_server);
NTP.Ntp(_ntp_server, _ntp_interval, _ntp_timezone); // set up NTP server
myDebug_P(PSTR("[NTP] NTP internet time enabled via server %s with timezone %d"), _ntp_server, _ntp_timezone);
}
// call any final custom stuff
@@ -632,6 +633,27 @@ void MyESP::_telnet_setup() {
memset(_command, 0, TELNET_MAX_COMMAND_LENGTH);
}
// restart some services like web, mqtt, ntp etc...
void MyESP::_kick() {
myDebug_P(PSTR("Kicking services..."));
// NTP - fetch new time
if (_ntp_enabled) {
myDebug_P(PSTR(" - Requesting NTP time"));
NTP.getNtpTime();
}
// kick web
myDebug_P(PSTR(" - Restart web server and web sockets"));
_ws->enable(false);
//_webServer->reset();
_ws->enable(true);
// kick mqtt
myDebug_P(PSTR(" - Restart MQTT"));
mqttClient.disconnect();
}
// Show help of commands
void MyESP::_consoleShowHelp() {
myDebug_P(PSTR(""));
@@ -652,7 +674,7 @@ void MyESP::_consoleShowHelp() {
myDebug_P(PSTR("*"));
myDebug_P(PSTR("* Commands:"));
myDebug_P(PSTR("* ?/help=show commands, CTRL-D/quit=close telnet session"));
myDebug_P(PSTR("* set, system, restart, mqttlog"));
myDebug_P(PSTR("* set, system, restart, mqttlog, kick"));
#ifdef CRASH
myDebug_P(PSTR("* crash <dump | clear | test [n]>"));
@@ -696,6 +718,8 @@ void MyESP::_printSetCommands() {
myDebug_P(PSTR(" set mqtt_keepalive [seconds]"));
myDebug_P(PSTR(" set mqtt_retain [on | off]"));
myDebug_P(PSTR(" set ntp_enabled <on | off>"));
myDebug_P(PSTR(" set ntp_interval [n]"));
myDebug_P(PSTR(" set ntp_timezone [n]"));
myDebug_P(PSTR(" set serial <on | off>"));
myDebug_P(PSTR(" set log_events <on | off>"));
@@ -760,6 +784,9 @@ void MyESP::_printSetCommands() {
#endif
myDebug_P(PSTR(" ntp_enabled=%s"), (_ntp_enabled) ? "on" : "off");
myDebug_P(PSTR(" ntp_interval=%d"), _ntp_interval);
myDebug_P(PSTR(" ntp_timezone=%d"), _ntp_timezone);
myDebug_P(PSTR(" log_events=%s"), (_general_log_events) ? "on" : "off");
// print any custom settings
@@ -849,6 +876,10 @@ bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value)
save_config = fs_setSettingValue(&_mqtt_heartbeat, value, false);
} else if (strcmp(setting, "ntp_enabled") == 0) {
save_config = fs_setSettingValue(&_ntp_enabled, value, false);
} else if (strcmp(setting, "ntp_interval") == 0) {
save_config = fs_setSettingValue(&_ntp_interval, value, NTP_INTERVAL_DEFAULT);
} else if (strcmp(setting, "ntp_timezone") == 0) {
save_config = fs_setSettingValue(&_ntp_timezone, value, NTP_TIMEZONE_DEFAULT);
} else if (strcmp(setting, "log_events") == 0) {
save_config = fs_setSettingValue(&_general_log_events, value, false);
} else {
@@ -946,6 +977,12 @@ void MyESP::_telnetCommand(char * commandLine) {
return;
}
// kick command
if ((strcmp(ptrToCommandName, "kick") == 0) && (wc == 1)) {
_kick();
return;
}
// restart command
if (((strcmp(ptrToCommandName, "restart") == 0) || (strcmp(ptrToCommandName, "reboot") == 0)) && (wc == 1)) {
resetESP();
@@ -1282,8 +1319,9 @@ void MyESP::showSystemStats() {
myDebug_P(PSTR(" [MQTT] is disconnected"));
}
if (_ntp_enabled) {
myDebug_P(PSTR(" [NTP] Time in UTC is %02d:%02d:%02d"), to_hour(now()), to_minute(now()), to_second(now()));
if (_have_ntp_time) {
uint32_t real_time = getSystemTime();
myDebug_P(PSTR(" [NTP] Local Time is %02d:%02d:%02d %s (%d)"), to_hour(real_time), to_minute(real_time), to_second(real_time), NTP.tcr->abbrev, real_time);
}
#ifdef CRASH
@@ -1540,18 +1578,18 @@ char * MyESP::_mqttTopic(const char * topic) {
// validates a file in SPIFFS, loads it into the json buffer and returns true if ok
size_t MyESP::_fs_validateConfigFile(const char * filename, size_t maxsize, JsonDocument & doc) {
// myDebug_P(PSTR("[FS] Checking file %s"), filename); // remove for debugging
// see if we can open it
File file = SPIFFS.open(filename, "r");
if (!file) {
myDebug_P(PSTR("[FS] File %s not found"), filename);
myDebug_P(PSTR("[FS] Cannot open config file %s for reading"), filename);
return 0;
}
// check size
size_t size = file.size();
// myDebug_P(PSTR("[FS] Checking file %s (%d bytes)"), filename, size); // remove for debugging
if (size > maxsize) {
file.close();
myDebug_P(PSTR("[FS] Error. File %s size %d is too large (max %d)"), filename, size, maxsize);
@@ -1752,8 +1790,9 @@ bool MyESP::_fs_loadConfig() {
_ntp_server = strdup(ntp["server"] | "");
_ntp_interval = ntp["interval"] | 60;
if (_ntp_interval < 2)
_ntp_interval = 60;
_ntp_enabled = ntp["enabled"];
_ntp_interval = NTP_INTERVAL_DEFAULT;
_ntp_enabled = ntp["enabled"];
_ntp_timezone = ntp["timezone"] | NTP_TIMEZONE_DEFAULT;
myDebug_P(PSTR("[FS] System config loaded (%d bytes)"), size);
@@ -1800,6 +1839,18 @@ bool MyESP::fs_setSettingValue(uint8_t * setting, const char * value, uint8_t va
return true;
}
// saves a signed 8-bit integer into a config setting, using default value if non set
// returns true if successful
bool MyESP::fs_setSettingValue(int8_t * setting, const char * value, int8_t value_default) {
if (_hasValue(value)) {
*setting = (int8_t)atoi(value);
} else {
*setting = value_default; // use the default value
}
return true;
}
// saves a bool into a config setting, using default value if non set
// returns true if successful
bool MyESP::fs_setSettingValue(bool * setting, const char * value, bool value_default) {
@@ -1830,6 +1881,7 @@ bool MyESP::_fs_loadCustomConfig() {
if (_fs_loadsave_callback_f) {
const JsonObject & json = doc["settings"];
if (!(_fs_loadsave_callback_f)(MYESP_FSACTION_LOAD, json)) {
myDebug_P(PSTR("[FS] Error reading custom config"));
return false;
@@ -1852,6 +1904,7 @@ bool MyESP::fs_saveCustomConfig(JsonObject root) {
// open for writing
File configFile = SPIFFS.open(MYESP_CUSTOMCONFIG_FILE, "w");
if (!configFile) {
myDebug_P(PSTR("[FS] Failed to open custom config for writing"));
ok = false;
@@ -1888,15 +1941,16 @@ bool MyESP::fs_saveCustomConfig(JsonObject root) {
// save system config to spiffs
bool MyESP::fs_saveConfig(JsonObject root) {
bool ok = false;
// call any custom functions before handling SPIFFS
if (_ota_pre_callback_f) {
(_ota_pre_callback_f)();
}
bool ok = false;
// open for writing
File configFile = SPIFFS.open(MYESP_CONFIG_FILE, "w");
if (!configFile) {
myDebug_P(PSTR("[FS] Failed to open system config for writing"));
ok = false;
@@ -1940,6 +1994,7 @@ bool MyESP::_fs_writeConfig() {
general["serial"] = _general_serial;
general["hostname"] = _general_hostname;
general["log_events"] = _general_log_events;
general["version"] = _app_version;
JsonObject mqtt = doc.createNestedObject("mqtt");
mqtt["enabled"] = _mqtt_enabled;
@@ -1950,14 +2005,14 @@ bool MyESP::_fs_writeConfig() {
mqtt["qos"] = _mqtt_qos;
mqtt["keepalive"] = _mqtt_keepalive;
mqtt["retain"] = _mqtt_retain;
mqtt["password"] = _mqtt_password;
mqtt["base"] = _mqtt_base;
mqtt["password"] = _mqtt_password;
mqtt["base"] = _mqtt_base;
JsonObject ntp = doc.createNestedObject("ntp");
ntp["server"] = _ntp_server;
ntp["interval"] = _ntp_interval;
ntp["enabled"] = _ntp_enabled;
ntp["timezone"] = _ntp_timezone;
bool ok = fs_saveConfig(root); // save it
@@ -1993,28 +2048,15 @@ void MyESP::_fs_setup() {
(_ota_pre_callback_f)(); // call custom function
}
// check SPIFFS is OK
if (!SPIFFS.begin()) {
myDebug_P(PSTR("[FS] Formatting filesystem..."));
if (SPIFFS.format()) {
if (_general_log_events) {
_writeEvent("WARN", "system", "File system formatted", "");
}
myDebug_P(PSTR("[FS] File system formatted"));
} else {
myDebug_P(PSTR("[FS] Failed to format file system"));
}
}
// load the main system config file if we can. Otherwise create it and expect user to configure in web interface
if (!_fs_loadConfig()) {
myDebug_P(PSTR("[FS] Creating a new system config"));
_fs_writeConfig(); // create the initial config file
}
// load system and custom config
if (!_fs_loadCustomConfig()) {
_fs_createCustomConfig(); // create the initial config file
}
/*
// fill event log with tests
SPIFFS.remove(MYESP_EVENTLOG_FILE);
@@ -2039,6 +2081,17 @@ void MyESP::_fs_setup() {
}
}
// load the main system config file if we can. Otherwise create it and expect user to configure in web interface
if (!_fs_loadConfig()) {
myDebug_P(PSTR("[FS] Creating a new system config"));
_fs_writeConfig(); // create the initial config file
}
// load system and custom config
if (!_fs_loadCustomConfig()) {
_fs_createCustomConfig(); // create the initial config file
}
if (_ota_post_callback_f) {
(_ota_post_callback_f)(); // call custom function
}
@@ -2266,7 +2319,7 @@ void MyESP::_writeEvent(const char * type, const char * src, const char * desc,
// this will also create the file if its doesn't exist
File eventlog = SPIFFS.open(MYESP_EVENTLOG_FILE, "a");
if (!eventlog) {
//Serial.println("[SYSTEM] Error opening event log for writing"); // for debugging
// Serial.println("[SYSTEM] Error opening event log for writing"); // for debugging
eventlog.close();
return;
}
@@ -2279,12 +2332,9 @@ void MyESP::_writeEvent(const char * type, const char * src, const char * desc,
root["time"] = now(); // is relative if we're not using NTP
// Serialize JSON to file
size_t n = serializeJson(root, eventlog);
eventlog.print("\n"); // this indicates end of the entry
(void)serializeJson(root, eventlog);
if (!n) {
//Serial.println("[SYSTEM] Error writing to event log"); // for debugging
}
eventlog.print("\n"); // this indicates end of the entry
eventlog.close();
}
@@ -2453,17 +2503,7 @@ void MyESP::_procMsg(AsyncWebSocketClient * client, size_t sz) {
uint8_t page = doc["page"];
_sendEventLog(page);
} else if (strcmp(command, "clearevent") == 0) {
if (_ota_pre_callback_f) {
(_ota_pre_callback_f)(); // call custom function
}
if (SPIFFS.remove(MYESP_EVENTLOG_FILE)) {
_writeEvent("WARN", "system", "Event log cleared", "");
} else {
myDebug_P(PSTR("[WEB] Could not clear event log"));
}
if (_ota_post_callback_f) {
(_ota_post_callback_f)(); // call custom function
}
_emptyEventLog();
} else if (strcmp(command, "scan") == 0) {
WiFi.scanNetworksAsync(std::bind(&MyESP::_printScanResult, this, std::placeholders::_1), true);
} else if (strcmp(command, "gettime") == 0) {
@@ -2480,6 +2520,22 @@ void MyESP::_procMsg(AsyncWebSocketClient * client, size_t sz) {
client->_tempObject = NULL;
}
// delete the event log
void MyESP::_emptyEventLog() {
if (_ota_pre_callback_f) {
(_ota_pre_callback_f)(); // call custom function
}
if (SPIFFS.remove(MYESP_EVENTLOG_FILE)) {
_writeEvent("WARN", "system", "Event log cleared", "");
myDebug_P(PSTR("[WEB] Event log cleared"));
} else {
myDebug_P(PSTR("[WEB] Could not clear event log"));
}
if (_ota_post_callback_f) {
(_ota_post_callback_f)(); // call custom function
}
}
// read both system config and the custom config and send as json to web socket
bool MyESP::_fs_sendConfig() {
File configFile;
@@ -2866,6 +2922,16 @@ void MyESP::_sendTime() {
_ws->textAll(buffer, len);
}
// returns real time from the internet/NTP if availble
// otherwise elapsed system time
unsigned long MyESP::getSystemTime() {
if (_have_ntp_time) {
return now();
}
return millis(); // elapsed time
}
// bootup sequence
// quickly flash LED until we get a Wifi connection, or AP established
void MyESP::_bootupSequence() {
@@ -2964,7 +3030,8 @@ void MyESP::loop() {
_heartbeatCheck();
_bootupSequence(); // see if a reset was pressed during bootup
jw.loop(); // WiFi
jw.loop(); // WiFi
ArduinoOTA.handle(); // OTA
ESP.wdtFeed(); // feed the watchdog...