mirror of https://github.com/arendst/Tasmota.git
Fixed NTP fallback server functionality
Fixed NTP fallback server functionality (#9739)
This commit is contained in:
parent
9026455891
commit
488a360d5b
|
@ -5,7 +5,11 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
## [9.1.0.1]
|
||||
### Changed
|
||||
- platformio compiler option `no target align` enabled for stage
|
||||
- Core library from v2.7.4.5 to v2.7.4.7
|
||||
- Platformio compiler option `no target align` enabled (#9749)
|
||||
|
||||
### Fixed
|
||||
- NTP fallback server functionality (#9739)
|
||||
|
||||
## [Released]
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ While fallback or downgrading is common practice it was never supported due to S
|
|||
|
||||
## Supported Core versions
|
||||
|
||||
This release will be supported from ESP8266/Arduino library Core version **2.7.4.5** due to reported security and stability issues on previous Core version. This will also support gzipped binaries.
|
||||
This release will be supported from ESP8266/Arduino library Core version **2.7.4.7** due to reported security and stability issues on previous Core version. This will also support gzipped binaries.
|
||||
|
||||
Support of Core versions before 2.7.1 has been removed.
|
||||
|
||||
|
@ -39,7 +39,7 @@ For initial configuration this release supports Webserver based **WifiManager**
|
|||
|
||||
## Provided Binary Downloads
|
||||
|
||||
The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.4.5**.
|
||||
The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.4.7**.
|
||||
|
||||
- **tasmota.bin** = The Tasmota version with most drivers. **RECOMMENDED RELEASE BINARY**
|
||||
- **tasmota-BG.bin** to **tasmota-TW.bin** = The Tasmota version in different languages.
|
||||
|
@ -58,4 +58,9 @@ The attached binaries can also be downloaded from http://ota.tasmota.com/tasmota
|
|||
[Complete list](BUILDS.md) of available feature and sensors.
|
||||
|
||||
## Changelog v9.1.0.1
|
||||
- platformio compiler option `no target align` enabled for stage
|
||||
### Changed
|
||||
- Core library from v2.7.4.5 to v2.7.4.7
|
||||
- Platformio compiler option `no target align` enabled (#9749)
|
||||
|
||||
### Fixed
|
||||
- NTP fallback server functionality (#9739)
|
||||
|
|
|
@ -2076,6 +2076,10 @@ void PrepLog_P2(uint32_t loglevel, PGM_P formatP, ...)
|
|||
|
||||
void AddLog_P2(uint32_t loglevel, PGM_P formatP, ...)
|
||||
{
|
||||
if (TasmotaGlobal.prepped_loglevel) {
|
||||
AddLog(TasmotaGlobal.prepped_loglevel);
|
||||
}
|
||||
|
||||
va_list arg;
|
||||
va_start(arg, formatP);
|
||||
vsnprintf_P(TasmotaGlobal.log_data, sizeof(TasmotaGlobal.log_data), formatP, arg);
|
||||
|
|
|
@ -157,29 +157,6 @@ void ZigbeeWrite(const void *pSettings, unsigned nSettingsLen) {
|
|||
NvmSave("zb", "zigbee", pSettings, nSettingsLen);
|
||||
}
|
||||
|
||||
//
|
||||
// sntp emulation
|
||||
//
|
||||
static bool bNetIsTimeSync = false;
|
||||
//
|
||||
void SntpInit() {
|
||||
bNetIsTimeSync = true;
|
||||
}
|
||||
|
||||
uint32_t SntpGetCurrentTimestamp(void) {
|
||||
time_t now = 0;
|
||||
if (bNetIsTimeSync || TasmotaGlobal.ntp_force_sync)
|
||||
{
|
||||
//Serial_DebugX(("timesync configTime %d\n", TasmotaGlobal.ntp_force_sync, bNetIsTimeSync));
|
||||
// init to UTC Time
|
||||
configTime(0, 0, SettingsText(SET_NTPSERVER1), SettingsText(SET_NTPSERVER2), SettingsText(SET_NTPSERVER3));
|
||||
bNetIsTimeSync = false;
|
||||
TasmotaGlobal.ntp_force_sync = false;
|
||||
}
|
||||
time(&now);
|
||||
return now;
|
||||
}
|
||||
|
||||
//
|
||||
// Crash stuff
|
||||
//
|
||||
|
|
|
@ -29,9 +29,6 @@ const uint32_t MINS_PER_HOUR = 60UL;
|
|||
|
||||
#define LEAP_YEAR(Y) (((1970+Y)>0) && !((1970+Y)%4) && (((1970+Y)%100) || !((1970+Y)%400)))
|
||||
|
||||
extern "C" {
|
||||
#include "sntp.h"
|
||||
}
|
||||
#include <Ticker.h>
|
||||
|
||||
Ticker TickerRtc;
|
||||
|
@ -44,13 +41,12 @@ struct RTC {
|
|||
uint32_t local_time = 0;
|
||||
uint32_t daylight_saving_time = 0;
|
||||
uint32_t standard_time = 0;
|
||||
uint32_t ntp_time = 0;
|
||||
uint32_t midnight = 0;
|
||||
uint32_t restart_time = 0;
|
||||
uint32_t millis = 0;
|
||||
uint32_t last_sync = 0;
|
||||
// uint32_t last_sync = 0;
|
||||
int32_t time_timezone = 0;
|
||||
uint8_t ntp_sync_minute = 0;
|
||||
bool time_synced = false;
|
||||
bool midnight_now = false;
|
||||
bool user_time_entry = false; // Override NTP by user setting
|
||||
} Rtc;
|
||||
|
@ -374,52 +370,39 @@ uint32_t RuleToTime(TimeRule r, int yr)
|
|||
|
||||
void RtcSecond(void)
|
||||
{
|
||||
TIME_T tmpTime;
|
||||
static uint32_t last_sync = 0;
|
||||
|
||||
Rtc.millis = millis();
|
||||
|
||||
if (!Rtc.user_time_entry) {
|
||||
if (!TasmotaGlobal.global_state.network_down) {
|
||||
uint8_t uptime_minute = (TasmotaGlobal.uptime / 60) % 60; // 0 .. 59
|
||||
if ((Rtc.ntp_sync_minute > 59) && (uptime_minute > 2)) {
|
||||
Rtc.ntp_sync_minute = 1; // If sync prepare for a new cycle
|
||||
if (Rtc.time_synced) {
|
||||
Rtc.time_synced = false;
|
||||
last_sync = Rtc.utc_time;
|
||||
|
||||
if (Rtc.restart_time == 0) {
|
||||
Rtc.restart_time = Rtc.utc_time - TasmotaGlobal.uptime; // save first synced time as restart time
|
||||
}
|
||||
uint8_t offset = (TasmotaGlobal.uptime < 30) ? RtcTime.second : (((ESP_getChipId() & 0xF) * 3) + 3) ; // First try ASAP to sync. If fails try once every 60 seconds based on chip id
|
||||
if ( (((offset == RtcTime.second) && ( (RtcTime.year < 2016) || // Never synced
|
||||
(Rtc.ntp_sync_minute == uptime_minute))) || // Re-sync every hour
|
||||
TasmotaGlobal.ntp_force_sync ) ) { // Forced sync
|
||||
Rtc.ntp_time = sntp_get_current_timestamp();
|
||||
if (Rtc.ntp_time > START_VALID_TIME) { // Fix NTP bug in core 2.4.1/SDK 2.2.1 (returns Thu Jan 01 08:00:10 1970 after power on)
|
||||
TasmotaGlobal.ntp_force_sync = false;
|
||||
Rtc.utc_time = Rtc.ntp_time;
|
||||
Rtc.last_sync = Rtc.ntp_time;
|
||||
Rtc.ntp_sync_minute = 60; // Sync so block further requests
|
||||
if (Rtc.restart_time == 0) {
|
||||
Rtc.restart_time = Rtc.utc_time - TasmotaGlobal.uptime; // save first ntp time as restart time
|
||||
}
|
||||
BreakTime(Rtc.utc_time, tmpTime);
|
||||
RtcTime.year = tmpTime.year + 1970;
|
||||
Rtc.daylight_saving_time = RuleToTime(Settings.tflag[1], RtcTime.year);
|
||||
Rtc.standard_time = RuleToTime(Settings.tflag[0], RtcTime.year);
|
||||
|
||||
// Do not use AddLog_P2 here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
|
||||
PrepLog_P2(LOG_LEVEL_DEBUG, PSTR("NTP: " D_UTC_TIME " %s, " D_DST_TIME " %s, " D_STD_TIME " %s"),
|
||||
GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_DST).c_str(), GetDateAndTime(DT_STD).c_str());
|
||||
TIME_T tmpTime;
|
||||
BreakTime(Rtc.utc_time, tmpTime);
|
||||
RtcTime.year = tmpTime.year + 1970;
|
||||
Rtc.daylight_saving_time = RuleToTime(Settings.tflag[1], RtcTime.year);
|
||||
Rtc.standard_time = RuleToTime(Settings.tflag[0], RtcTime.year);
|
||||
|
||||
if (Rtc.local_time < START_VALID_TIME) { // 2016-01-01
|
||||
TasmotaGlobal.rules_flag.time_init = 1;
|
||||
} else {
|
||||
TasmotaGlobal.rules_flag.time_set = 1;
|
||||
}
|
||||
} else {
|
||||
Rtc.ntp_sync_minute++; // Try again in next minute
|
||||
}
|
||||
// Do not use AddLog_P2 here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
|
||||
PrepLog_P2(LOG_LEVEL_DEBUG, PSTR("RTC: " D_UTC_TIME " %s, " D_DST_TIME " %s, " D_STD_TIME " %s"),
|
||||
GetDateAndTime(DT_UTC).c_str(), GetDateAndTime(DT_DST).c_str(), GetDateAndTime(DT_STD).c_str());
|
||||
|
||||
if (Rtc.local_time < START_VALID_TIME) { // 2016-01-01
|
||||
TasmotaGlobal.rules_flag.time_init = 1;
|
||||
} else {
|
||||
TasmotaGlobal.rules_flag.time_set = 1;
|
||||
}
|
||||
}
|
||||
if ((Rtc.utc_time > (2 * 60 * 60)) && (Rtc.last_sync < Rtc.utc_time - (2 * 60 * 60))) { // Every two hours a warning
|
||||
if ((Rtc.utc_time > (2 * 60 * 60)) && (last_sync < Rtc.utc_time - (2 * 60 * 60))) { // Every two hours a warning
|
||||
// Do not use AddLog_P2 here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9
|
||||
PrepLog_P2(LOG_LEVEL_DEBUG, PSTR("NTP: Not synced"));
|
||||
Rtc.last_sync = Rtc.utc_time;
|
||||
PrepLog_P2(LOG_LEVEL_DEBUG, PSTR("RTC: Not synced"));
|
||||
last_sync = Rtc.utc_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -477,9 +460,7 @@ void RtcSetTime(uint32_t epoch)
|
|||
if (epoch < START_VALID_TIME) { // 2016-01-01
|
||||
Rtc.user_time_entry = false;
|
||||
TasmotaGlobal.ntp_force_sync = true;
|
||||
sntp_init();
|
||||
} else {
|
||||
sntp_stop();
|
||||
Rtc.user_time_entry = true;
|
||||
Rtc.utc_time = epoch -1; // Will be corrected by RtcSecond
|
||||
}
|
||||
|
@ -487,12 +468,6 @@ void RtcSetTime(uint32_t epoch)
|
|||
|
||||
void RtcInit(void)
|
||||
{
|
||||
sntp_setservername(0, SettingsText(SET_NTPSERVER1));
|
||||
sntp_setservername(1, SettingsText(SET_NTPSERVER2));
|
||||
sntp_setservername(2, SettingsText(SET_NTPSERVER3));
|
||||
sntp_stop();
|
||||
sntp_set_timezone(0); // UTC time
|
||||
sntp_init();
|
||||
Rtc.utc_time = 0;
|
||||
BreakTime(Rtc.utc_time, RtcTime);
|
||||
TickerRtc.attach(1, RtcSecond);
|
||||
|
|
|
@ -876,6 +876,8 @@ void PerformEverySecond(void)
|
|||
// Wifi keep alive to send Gratuitous ARP
|
||||
wifiKeepAlive();
|
||||
|
||||
WifiPollNtp();
|
||||
|
||||
#ifdef ESP32
|
||||
if (11 == TasmotaGlobal.uptime) { // Perform one-time ESP32 houskeeping
|
||||
ESP_getSketchSize(); // Init sketchsize as it can take up to 2 seconds
|
||||
|
|
|
@ -701,3 +701,131 @@ void wifiKeepAlive(void) {
|
|||
SetNextTimeInterval(wifi_timer, wifiTimerSec * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void WifiPollNtp() {
|
||||
static uint8_t ntp_sync_minute = 0;
|
||||
|
||||
if (TasmotaGlobal.global_state.network_down) { return; }
|
||||
|
||||
uint8_t uptime_minute = (TasmotaGlobal.uptime / 60) % 60; // 0 .. 59
|
||||
if ((ntp_sync_minute > 59) && (uptime_minute > 2)) {
|
||||
ntp_sync_minute = 1; // If sync prepare for a new cycle
|
||||
}
|
||||
// First try ASAP to sync. If fails try once every 60 seconds based on chip id
|
||||
uint8_t offset = (TasmotaGlobal.uptime < 30) ? RtcTime.second : (((ESP_getChipId() & 0xF) * 3) + 3) ;
|
||||
if ( (((offset == RtcTime.second) && ( (RtcTime.year < 2016) || // Never synced
|
||||
(ntp_sync_minute == uptime_minute))) || // Re-sync every hour
|
||||
TasmotaGlobal.ntp_force_sync ) ) { // Forced sync
|
||||
|
||||
TasmotaGlobal.ntp_force_sync = false;
|
||||
uint32_t ntp_time = WifiGetNtp();
|
||||
if (ntp_time > START_VALID_TIME) {
|
||||
Rtc.utc_time = ntp_time;
|
||||
ntp_sync_minute = 60; // Sync so block further requests
|
||||
Rtc.time_synced = true;
|
||||
RtcSecond();
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NTP: Synced"));
|
||||
} else {
|
||||
ntp_sync_minute++; // Try again in next minute
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t WifiGetNtp(void) {
|
||||
static uint8_t ntp_server_id = 0;
|
||||
|
||||
IPAddress time_server_ip;
|
||||
|
||||
char* ntp_server;
|
||||
bool resolved_ip = false;
|
||||
for (uint32_t i = 0; i < MAX_NTP_SERVERS; i++) {
|
||||
ntp_server = SettingsText(SET_NTPSERVER1 + ntp_server_id);
|
||||
if (strlen(ntp_server)) {
|
||||
resolved_ip = (WiFi.hostByName(ntp_server, time_server_ip) == 1);
|
||||
if (255 == time_server_ip[0]) { resolved_ip = false; }
|
||||
yield();
|
||||
if (resolved_ip) { break; }
|
||||
}
|
||||
ntp_server_id++;
|
||||
if (ntp_server_id > 2) { ntp_server_id = 0; }
|
||||
}
|
||||
if (!resolved_ip) {
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NTP: No server found"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NTP: Name %s, IP %s"), ntp_server, time_server_ip.toString().c_str());
|
||||
|
||||
WiFiUDP udp;
|
||||
|
||||
uint32_t attempts = 3;
|
||||
while (attempts > 0) {
|
||||
uint32_t port = random(1025, 65535); // Create a random port for the UDP connection.
|
||||
if (udp.begin(port) != 0) {
|
||||
break;
|
||||
}
|
||||
attempts--;
|
||||
}
|
||||
if (0 == attempts) { return 0; }
|
||||
|
||||
while (udp.parsePacket() > 0) { // Discard any previously received packets
|
||||
yield();
|
||||
}
|
||||
|
||||
const uint32_t NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
|
||||
uint8_t packet_buffer[NTP_PACKET_SIZE]; // Buffer to hold incoming & outgoing packets
|
||||
memset(packet_buffer, 0, NTP_PACKET_SIZE);
|
||||
packet_buffer[0] = 0b11100011; // LI, Version, Mode
|
||||
packet_buffer[1] = 0; // Stratum, or type of clock
|
||||
packet_buffer[2] = 6; // Polling Interval
|
||||
packet_buffer[3] = 0xEC; // Peer Clock Precision
|
||||
packet_buffer[12] = 49;
|
||||
packet_buffer[13] = 0x4E;
|
||||
packet_buffer[14] = 49;
|
||||
packet_buffer[15] = 52;
|
||||
|
||||
if (udp.beginPacket(time_server_ip, 123) == 0) { // NTP requests are to port 123
|
||||
ntp_server_id++;
|
||||
if (ntp_server_id > 2) { ntp_server_id = 0; } // Next server next time
|
||||
udp.stop();
|
||||
return 0;
|
||||
}
|
||||
udp.write(packet_buffer, NTP_PACKET_SIZE);
|
||||
udp.endPacket();
|
||||
|
||||
uint32_t begin_wait = millis();
|
||||
while (!TimeReached(begin_wait + 1000)) { // Wait up to one second
|
||||
uint32_t size = udp.parsePacket();
|
||||
uint32_t remote_port = udp.remotePort();
|
||||
|
||||
if ((size >= NTP_PACKET_SIZE) && (remote_port == 123)) {
|
||||
udp.read(packet_buffer, NTP_PACKET_SIZE); // Read packet into the buffer
|
||||
udp.stop();
|
||||
|
||||
if ((packet_buffer[0] & 0b11000000) == 0b11000000) {
|
||||
// Leap-Indicator: unknown (clock unsynchronized)
|
||||
// See: https://github.com/letscontrolit/ESPEasy/issues/2886#issuecomment-586656384
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NTP: IP %s unsynched"), time_server_ip.toString().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// convert four bytes starting at location 40 to a long integer
|
||||
// TX time is used here.
|
||||
uint32_t secs_since_1900 = (uint32_t)packet_buffer[40] << 24;
|
||||
secs_since_1900 |= (uint32_t)packet_buffer[41] << 16;
|
||||
secs_since_1900 |= (uint32_t)packet_buffer[42] << 8;
|
||||
secs_since_1900 |= (uint32_t)packet_buffer[43];
|
||||
if (0 == secs_since_1900) { // No time stamp received
|
||||
return 0;
|
||||
}
|
||||
return secs_since_1900 - 2208988800UL;
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
// Timeout.
|
||||
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NTP: No reply"));
|
||||
udp.stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue