From b3ab0f9ee8ea1024394a6086e6a86c36b7dd6b1c Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 10:05:39 +0100 Subject: [PATCH 01/19] Add private and arch specific functions to init/get/set RTC --- src/utility/time/TimeService.cpp | 167 +++++++++++++++++++++++++++++++ src/utility/time/TimeService.h | 3 + 2 files changed, 170 insertions(+) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index dc90048ad..9bb5811ac 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -39,6 +39,36 @@ RTCZero rtc; time_t cvt_time(char const * time); +#ifdef ARDUINO_ARCH_SAMD +void samd_initRTC(); +void samd_setRTC(unsigned long time); +unsigned long samd_getRTC(); +#endif + +#ifdef ARDUINO_NANO_RP2040_CONNECT +void rp2040_connect_initRTC(); +void rp2040_connect_setRTC(unsigned long time); +unsigned long rp2040_connect_getRTC(); +#endif + +#ifdef BOARD_STM32H7 +void stm32h7_initRTC(); +void stm32h7_setRTC(unsigned long time); +unsigned long stm32h7_getRTC(); +#endif + +#ifdef ARDUINO_ARCH_ESP32 +void esp32_initRTC(); +void esp32_setRTC(unsigned long time); +unsigned long esp32_getRTC(); +#endif + +#ifdef ARDUINO_ARCH_ESP8266 +void esp8266_initRTC(); +void esp8266_setRTC(unsigned long time); +unsigned long esp8266_getRTC(); +#endif + /************************************************************************************** * CONSTANTS **************************************************************************************/ @@ -277,6 +307,57 @@ bool TimeService::isTimeValid(unsigned long const time) return (time >= EPOCH_AT_COMPILE_TIME); } +void TimeService::initRTC() +{ +#if defined (ARDUINO_ARCH_SAMD) + samd_initRTC(); +#elif defined (ARDUINO_NANO_RP2040_CONNECT) + rp2040_connect_initRTC(); +#elif defined (BOARD_STM32H7) + stm32h7_initRTC(); +#elif defined (ARDUINO_ARCH_ESP32) + esp32_initRTC(); +#elif ARDUINO_ARCH_ESP8266 + esp8266_initRTC(); +#else + #error "RTC not available for this architecture" +#endif +} + +void TimeService::setRTC(unsigned long time) +{ +#if defined (ARDUINO_ARCH_SAMD) + samd_setRTC(time); +#elif defined (ARDUINO_NANO_RP2040_CONNECT) + rp2040_connect_setRTC(time); +#elif defined (BOARD_STM32H7) + stm32h7_setRTC(time); +#elif defined (ARDUINO_ARCH_ESP32) + esp32_setRTC(time); +#elif ARDUINO_ARCH_ESP8266 + esp8266_setRTC(time); +#else + #error "RTC not available for this architecture" +#endif +} + +unsigned long TimeService::getRTC() +{ +#if defined (ARDUINO_ARCH_SAMD) + return samd_getRTC(); +#elif defined (ARDUINO_NANO_RP2040_CONNECT) + return rp2040_connect_getRTC(); +#elif defined (BOARD_STM32H7) + return stm32h7_getRTC(); +#elif defined (ARDUINO_ARCH_ESP32) + return esp32_getRTC(); +#elif ARDUINO_ARCH_ESP8266 + return esp8266_getRTC(); +#else + #error "RTC not available for this architecture" +#endif +} + /************************************************************************************** * INTERNAL FUNCTION DEFINITION **************************************************************************************/ @@ -311,6 +392,92 @@ time_t cvt_time(char const * time) return mktime(&t); } +#ifdef ARDUINO_ARCH_SAMD +void samd_initRTC() +{ + rtc.begin(); +} + +void samd_setRTC(unsigned long time) +{ + rtc.setEpoch(time); +} + +unsigned long samd_getRTC() +{ + return rtc.getEpoch(); +} +#endif + +#ifdef ARDUINO_NANO_RP2040_CONNECT +void rp2040_connect_initRTC() +{ + /* Nothing to do */ +} + +void rp2040_connect_setRTC(unsigned long time) +{ + set_time(time); +} + +unsigned long rp2040_connect_getRTC() +{ + return time(NULL); +} +#endif + +#ifdef BOARD_STM32H7 +void stm32h7_initRTC() +{ + /* Nothing to do */ +} + +void stm32h7_setRTC(unsigned long time) +{ + set_time(time); +} + +unsigned long stm32h7_getRTC() +{ + return time(NULL); +} +#endif + +#ifdef ARDUINO_ARCH_ESP32 +void esp32_initRTC() +{ + //configTime(0, 0, "time.arduino.cc", "pool.ntp.org", "time.nist.gov"); +} + +void esp32_setRTC(unsigned long time) +{ + const timeval epoch = {(time_t)time, 0}; + settimeofday(&epoch, 0); +} + +unsigned long esp32_getRTC() +{ + return time(NULL); +} +#endif + +#ifdef ARDUINO_ARCH_ESP8266 +void esp8266_initRTC() +{ + /* Nothing to do */ +} + +void esp8266_setRTC(unsigned long time) +{ + /* TODO */ +} + +unsigned long esp8266_getRTC() +{ + /* TODO */ +} +#endif + TimeService & ArduinoIoTCloudTimeService() { static TimeService _timeService_instance; return _timeService_instance; diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index bf8eef1a1..04d62ffc3 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -69,6 +69,9 @@ class TimeService unsigned long getRemoteTime(); bool connected(); static bool isTimeValid(unsigned long const time); + void initRTC(); + void setRTC(unsigned long time); + unsigned long getRTC(); }; From ec338dd77ce4a9356585aa070417c61f37ebc875 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 15:15:31 +0100 Subject: [PATCH 02/19] Add RTC implementation based on millis for ESP8266 --- src/utility/time/RTCMillis.cpp | 63 ++++++++++++++++++++++++++++++++++ src/utility/time/RTCMillis.h | 50 +++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 src/utility/time/RTCMillis.cpp create mode 100644 src/utility/time/RTCMillis.h diff --git a/src/utility/time/RTCMillis.cpp b/src/utility/time/RTCMillis.cpp new file mode 100644 index 000000000..ae17487ef --- /dev/null +++ b/src/utility/time/RTCMillis.cpp @@ -0,0 +1,63 @@ +/* + This file is part of ArduinoIoTCloud. + + Copyright 2020 ARDUINO SA (http://www.arduino.cc/) + + This software is released under the GNU General Public License version 3, + which covers the main part of arduino-cli. + The terms of this license can be found at: + https://www.gnu.org/licenses/gpl-3.0.en.html + + You can be released from the requirements of the above licenses by purchasing + a commercial license. Buying such a license is mandatory if you want to modify or + otherwise use the software for commercial activities involving the Arduino + software without disclosing the source code of your own applications. To purchase + a commercial license, send an email to license@arduino.cc. +*/ + +#ifdef ARDUINO_ARCH_ESP8266 + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +#include +#include "RTCMillis.h" + +/************************************************************************************** + * CTOR/DTOR + **************************************************************************************/ + +RTCMillis::RTCMillis() +: _last_rtc_update_tick(0) +, _last_rtc_update_value(0) +{ + +} + +/************************************************************************************** + * PUBLIC MEMBER FUNCTIONS + **************************************************************************************/ + +void RTCMillis::begin() +{ + +} + +void RTCMillis::set(unsigned long time) +{ + _last_rtc_update_tick = millis(); + _last_rtc_update_value = time; +} + +unsigned long RTCMillis::get() +{ + unsigned long current_tick = millis(); + unsigned long const elapsed_s = (current_tick - _last_rtc_update_tick) / 1000; + if(elapsed_s) { + set(_last_rtc_update_value + elapsed_s); + } + return _last_rtc_update_value; +} + +#endif /* ARDUINO_ARCH_ESP8266 */ diff --git a/src/utility/time/RTCMillis.h b/src/utility/time/RTCMillis.h new file mode 100644 index 000000000..1fa7e0f4a --- /dev/null +++ b/src/utility/time/RTCMillis.h @@ -0,0 +1,50 @@ +/* + This file is part of ArduinoIoTCloud. + + Copyright 2020 ARDUINO SA (http://www.arduino.cc/) + + This software is released under the GNU General Public License version 3, + which covers the main part of arduino-cli. + The terms of this license can be found at: + https://www.gnu.org/licenses/gpl-3.0.en.html + + You can be released from the requirements of the above licenses by purchasing + a commercial license. Buying such a license is mandatory if you want to modify or + otherwise use the software for commercial activities involving the Arduino + software without disclosing the source code of your own applications. To purchase + a commercial license, send an email to license@arduino.cc. +*/ + +#ifndef ARDUINO_IOT_CLOUD_RTC_MILLIS_H_ +#define ARDUINO_IOT_CLOUD_RTC_MILLIS_H_ + +#ifdef ARDUINO_ARCH_ESP8266 + +/************************************************************************************** + * INCLUDE + **************************************************************************************/ + +/************************************************************************************** + * CLASS DECLARATION + **************************************************************************************/ + +class RTCMillis +{ + +public: + + RTCMillis(); + + void begin(); + void set(unsigned long time); + unsigned long get(); + +private: + unsigned long _last_rtc_update_tick; + unsigned long _last_rtc_update_value; + +}; + +#endif /* ARDUINO_ARCH_ESP8266 */ + +#endif /* ARDUINO_IOT_CLOUD_RTC_MILLIS_H_ */ From bfde58c5ff440ecd7d3ddc67e0e924c079fe433b Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 15:21:53 +0100 Subject: [PATCH 03/19] getTimeFromSting cosmetic changes --- src/utility/time/TimeService.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 9bb5811ac..e8eac6887 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -214,16 +214,14 @@ unsigned long TimeService::getTimeFromString(const String& input) static const int expected_length = 20; static const int expected_parameters = 6; - if(input == nullptr || input.length() != expected_length) - { + if(input == nullptr || input.length() != expected_length) { DEBUG_ERROR("ArduinoIoTCloudTCP::%s invalid input length", __FUNCTION__); return 0; } int scanned_parameters = sscanf(input.c_str(), "%d %s %d %d:%d:%d", &year, s_month, &day, &hour, &min, &sec); - if(scanned_parameters != expected_parameters) - { + if(scanned_parameters != expected_parameters) { DEBUG_ERROR("ArduinoIoTCloudTCP::%s invalid input parameters number", __FUNCTION__); return 0; } From 01cc7773c0aff2d0936858518cd780c3f8d93212 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 15:25:29 +0100 Subject: [PATCH 04/19] Avoid to store EPOCH_AT_COMPILE_TIME inside RTC register --- src/utility/time/TimeService.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index e8eac6887..816b115c7 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -302,7 +302,7 @@ unsigned long TimeService::getRemoteTime() bool TimeService::isTimeValid(unsigned long const time) { - return (time >= EPOCH_AT_COMPILE_TIME); + return (time > EPOCH_AT_COMPILE_TIME); } void TimeService::initRTC() From e7120b4ddfc4ea4a22c54558272bf13ce8102ec6 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 15:26:23 +0100 Subject: [PATCH 05/19] Add sync method --- src/utility/time/TimeService.cpp | 14 ++++++++++++++ src/utility/time/TimeService.h | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 816b115c7..f8b4ba369 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -170,6 +170,20 @@ unsigned long TimeService::getTime() #endif } +bool TimeService::sync() +{ + _is_rtc_configured = false; + unsigned long utc = getRemoteTime(); + + if(isTimeValid(utc)) { + DEBUG_DEBUG("TimeServiceClass::%s Drift: %d RTC value: %u", __FUNCTION__, getRTC() - utc, utc); + setRTC(utc); + _last_ntp_sync_tick = millis(); + _is_rtc_configured = true; + } + return _is_rtc_configured; +} + void TimeService::setTimeZoneData(long offset, unsigned long dst_until) { if(_timezone_offset != offset) diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 04d62ffc3..c41523e07 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -43,11 +43,11 @@ class TimeService TimeService(); - void begin (ConnectionHandler * con_hdl); unsigned long getTime(); unsigned long getLocalTime(); void setTimeZoneData(long offset, unsigned long valid_until); + bool sync(); /* Helper function to convert an input String into a UNIX timestamp. * The input String format must be as follow "2021 Nov 01 17:00:00" */ From c862434964d0bba947e4c494a7b6ade74b421569 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 16 Feb 2023 10:13:29 +0100 Subject: [PATCH 06/19] Declare and use RTC for ESP8266 --- src/utility/time/TimeService.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index f8b4ba369..4029af5c9 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -25,6 +25,10 @@ #include "NTPUtils.h" +#ifdef ARDUINO_ARCH_ESP8266 + #include "RTCMillis.h" +#endif + /************************************************************************************** * GLOBAL VARIABLES **************************************************************************************/ @@ -33,6 +37,10 @@ RTCZero rtc; #endif +#ifdef ARDUINO_ARCH_ESP8266 +RTCMillis rtc; +#endif + /************************************************************************************** * INTERNAL FUNCTION DECLARATION **************************************************************************************/ @@ -476,17 +484,17 @@ unsigned long esp32_getRTC() #ifdef ARDUINO_ARCH_ESP8266 void esp8266_initRTC() { - /* Nothing to do */ + rtc.begin(); } void esp8266_setRTC(unsigned long time) { - /* TODO */ + rtc.set(time); } unsigned long esp8266_getRTC() { - /* TODO */ + return rtc.get(); } #endif From 2e48a0e0810866e76ef4666f9547dea64d91f9f5 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 16 Feb 2023 10:19:00 +0100 Subject: [PATCH 07/19] Move includes on top of file --- src/utility/time/TimeService.cpp | 14 ++++++++++---- src/utility/time/TimeService.h | 8 -------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 4029af5c9..7346ca5f9 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -19,12 +19,20 @@ * INCLUDE **************************************************************************************/ -#include "TimeService.h" +#include #include - +#include "TimeService.h" #include "NTPUtils.h" +#ifdef ARDUINO_ARCH_SAMD + #include +#endif + +#ifdef ARDUINO_ARCH_MBED + #include +#endif + #ifdef ARDUINO_ARCH_ESP8266 #include "RTCMillis.h" #endif @@ -288,9 +296,7 @@ bool TimeService::connected() unsigned long TimeService::getRemoteTime() { -#include "../../AIoTC_Config.h" #ifndef HAS_LORA - if(connected()) { /* At first try to see if a valid time can be obtained * using the network time available via the connection diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index c41523e07..593669702 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -24,14 +24,6 @@ #include -#ifdef ARDUINO_ARCH_SAMD - #include -#endif - -#ifdef ARDUINO_ARCH_MBED - #include -#endif - /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ From 82699bbd8941b337957a131ce94ae3c032749352 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 16 Feb 2023 10:21:32 +0100 Subject: [PATCH 08/19] Extend NTP synch to all platforms --- src/utility/time/TimeService.cpp | 10 +++------- src/utility/time/TimeService.h | 4 ---- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 7346ca5f9..9c3fe8ec9 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -89,9 +89,9 @@ unsigned long esp8266_getRTC(); * CONSTANTS **************************************************************************************/ -#ifdef ARDUINO_ARCH_ESP8266 -static unsigned long const AIOT_TIMESERVICE_ESP8266_NTP_SYNC_TIMEOUT_ms = 86400000; -#endif +/* Default NTP synch is scheduled each 24 hours from startup */ +static unsigned long const AIOT_TIMESERVICE_NTP_SYNC_TIMEOUT_ms = 86400000; + static time_t const EPOCH_AT_COMPILE_TIME = cvt_time(__DATE__); static time_t const EPOCH = 0; @@ -105,11 +105,7 @@ TimeService::TimeService() , _is_tz_configured(false) , _timezone_offset(0) , _timezone_dst_until(0) -#ifdef ARDUINO_ARCH_ESP8266 , _last_ntp_sync_tick(0) -, _last_rtc_update_tick(0) -, _rtc(0) -#endif { } diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 593669702..70ca0ea73 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -52,11 +52,7 @@ class TimeService bool _is_tz_configured; long _timezone_offset; unsigned long _timezone_dst_until; -#ifdef ARDUINO_ARCH_ESP8266 unsigned long _last_ntp_sync_tick; - unsigned long _last_rtc_update_tick; - unsigned long _rtc; -#endif unsigned long getRemoteTime(); bool connected(); From 9471ee0d2cac38ee175755bc1f46c0d83d3b39a8 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 16 Feb 2023 10:23:17 +0100 Subject: [PATCH 09/19] Make use of initRTC and sync functions --- src/utility/time/TimeService.cpp | 68 +++++--------------------------- 1 file changed, 10 insertions(+), 58 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 9c3fe8ec9..75d994091 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -117,69 +117,21 @@ TimeService::TimeService() void TimeService::begin(ConnectionHandler * con_hdl) { _con_hdl = con_hdl; -#ifdef ARDUINO_ARCH_SAMD - rtc.begin(); -#endif + initRTC(); } unsigned long TimeService::getTime() { -#ifdef ARDUINO_ARCH_SAMD - if(!_is_rtc_configured) - { - unsigned long utc = getRemoteTime(); - if(EPOCH_AT_COMPILE_TIME != utc) - { - rtc.setEpoch(utc); - _is_rtc_configured = true; - } - return utc; + /* Check if it's time to sync */ + unsigned long const current_tick = millis(); + bool const is_ntp_sync_timeout = (current_tick - _last_ntp_sync_tick) > AIOT_TIMESERVICE_NTP_SYNC_TIMEOUT_ms; + if(!_is_rtc_configured || is_ntp_sync_timeout) { + sync(); } - return rtc.getEpoch(); -#elif ARDUINO_ARCH_MBED - if(!_is_rtc_configured) - { - unsigned long utc = getRemoteTime(); - if(EPOCH_AT_COMPILE_TIME != utc) - { - set_time(utc); - _is_rtc_configured = true; - } - return utc; - } - return time(NULL); -#elif ARDUINO_ARCH_ESP32 - if(!_is_rtc_configured) - { - configTime(0, 0, "time.arduino.cc", "pool.ntp.org", "time.nist.gov"); - _is_rtc_configured = true; - } - return time(NULL); -#elif ARDUINO_ARCH_ESP8266 - unsigned long const now = millis(); - bool const is_ntp_sync_timeout = (now - _last_ntp_sync_tick) > AIOT_TIMESERVICE_ESP8266_NTP_SYNC_TIMEOUT_ms; - if(!_is_rtc_configured || is_ntp_sync_timeout) - { - _is_rtc_configured = false; - unsigned long utc = getRemoteTime(); - if(EPOCH_AT_COMPILE_TIME != utc) - { - _rtc = utc; - _last_ntp_sync_tick = now; - _last_rtc_update_tick = now; - _is_rtc_configured = true; - } - return utc; - } - unsigned long const elapsed_s = (now - _last_rtc_update_tick) / 1000; - if(elapsed_s) { - _rtc += elapsed_s; - _last_rtc_update_tick = now; - } - return _rtc; -#else - return getRemoteTime(); -#endif + + /* Read time from RTC */ + unsigned long utc = getRTC(); + return isTimeValid(utc) ? utc : EPOCH_AT_COMPILE_TIME; } bool TimeService::sync() From ada180c0c628b9459033494e229810d108aa5ab7 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 16:19:12 +0100 Subject: [PATCH 10/19] Make sync interval configurable --- src/utility/time/TimeService.cpp | 12 +++++++++--- src/utility/time/TimeService.h | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 75d994091..d0153c262 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -24,6 +24,7 @@ #include #include "TimeService.h" #include "NTPUtils.h" +#include "AIoTC_Const.h" #ifdef ARDUINO_ARCH_SAMD #include @@ -90,8 +91,7 @@ unsigned long esp8266_getRTC(); **************************************************************************************/ /* Default NTP synch is scheduled each 24 hours from startup */ -static unsigned long const AIOT_TIMESERVICE_NTP_SYNC_TIMEOUT_ms = 86400000; - +static time_t const TIMESERVICE_NTP_SYNC_TIMEOUT_ms = DAYS * 1000; static time_t const EPOCH_AT_COMPILE_TIME = cvt_time(__DATE__); static time_t const EPOCH = 0; @@ -106,6 +106,7 @@ TimeService::TimeService() , _timezone_offset(0) , _timezone_dst_until(0) , _last_ntp_sync_tick(0) +, _ntp_sync_interval_ms(TIMESERVICE_NTP_SYNC_TIMEOUT_ms) { } @@ -124,7 +125,7 @@ unsigned long TimeService::getTime() { /* Check if it's time to sync */ unsigned long const current_tick = millis(); - bool const is_ntp_sync_timeout = (current_tick - _last_ntp_sync_tick) > AIOT_TIMESERVICE_NTP_SYNC_TIMEOUT_ms; + bool const is_ntp_sync_timeout = (current_tick - _last_ntp_sync_tick) > _ntp_sync_interval_ms; if(!_is_rtc_configured || is_ntp_sync_timeout) { sync(); } @@ -148,6 +149,11 @@ bool TimeService::sync() return _is_rtc_configured; } +void TimeService::setSyncInterval(unsigned long seconds) +{ + _ntp_sync_interval_ms = seconds * 1000; +} + void TimeService::setTimeZoneData(long offset, unsigned long dst_until) { if(_timezone_offset != offset) diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 70ca0ea73..43fa2d4a8 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -40,6 +40,8 @@ class TimeService unsigned long getLocalTime(); void setTimeZoneData(long offset, unsigned long valid_until); bool sync(); + void setSyncInterval(unsigned long seconds); + /* Helper function to convert an input String into a UNIX timestamp. * The input String format must be as follow "2021 Nov 01 17:00:00" */ @@ -53,6 +55,7 @@ class TimeService long _timezone_offset; unsigned long _timezone_dst_until; unsigned long _last_ntp_sync_tick; + unsigned long _ntp_sync_interval_ms; unsigned long getRemoteTime(); bool connected(); From 8439b010658dd86efe7b4280bade2a1f3816e5b7 Mon Sep 17 00:00:00 2001 From: pennam Date: Thu, 3 Feb 2022 16:02:29 +0100 Subject: [PATCH 11/19] setTimeZoneData cosmetic changes --- src/utility/time/TimeService.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index d0153c262..4e6647582 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -156,15 +156,12 @@ void TimeService::setSyncInterval(unsigned long seconds) void TimeService::setTimeZoneData(long offset, unsigned long dst_until) { - if(_timezone_offset != offset) - DEBUG_DEBUG("ArduinoIoTCloudTCP::%s tz_offset: [%d]", __FUNCTION__, offset); - _timezone_offset = offset; - - if(_timezone_dst_until != dst_until) - DEBUG_DEBUG("ArduinoIoTCloudTCP::%s tz_dst_unitl: [%ul]", __FUNCTION__, dst_until); - _timezone_dst_until = dst_until; - - _is_tz_configured = true; + if(_timezone_offset != offset || _timezone_dst_until != dst_until) { + DEBUG_DEBUG("ArduinoIoTCloudTCP::%s offset: %d dst_unitl %ul", __FUNCTION__, offset, dst_until); + _timezone_offset = offset; + _timezone_dst_until = dst_until; + _is_tz_configured = true; + } } unsigned long TimeService::getLocalTime() From 1836f23342bf01aa2a5d6dcfeb31cd2611e757c6 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 16:38:51 +0100 Subject: [PATCH 12/19] Fix debug prints reporting the wrong class name --- src/utility/time/TimeService.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 4e6647582..8341b09ee 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -157,7 +157,7 @@ void TimeService::setSyncInterval(unsigned long seconds) void TimeService::setTimeZoneData(long offset, unsigned long dst_until) { if(_timezone_offset != offset || _timezone_dst_until != dst_until) { - DEBUG_DEBUG("ArduinoIoTCloudTCP::%s offset: %d dst_unitl %ul", __FUNCTION__, offset, dst_until); + DEBUG_DEBUG("TimeService::%s offset: %d dst_unitl %ul", __FUNCTION__, offset, dst_until); _timezone_offset = offset; _timezone_dst_until = dst_until; _is_tz_configured = true; @@ -196,21 +196,21 @@ unsigned long TimeService::getTimeFromString(const String& input) static const int expected_parameters = 6; if(input == nullptr || input.length() != expected_length) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s invalid input length", __FUNCTION__); + DEBUG_ERROR("TimeService::%s invalid input length", __FUNCTION__); return 0; } int scanned_parameters = sscanf(input.c_str(), "%d %s %d %d:%d:%d", &year, s_month, &day, &hour, &min, &sec); if(scanned_parameters != expected_parameters) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s invalid input parameters number", __FUNCTION__); + DEBUG_ERROR("TimeService::%s invalid input parameters number", __FUNCTION__); return 0; } char * s_month_position = strstr(month_names, s_month); if(s_month_position == nullptr || strlen(s_month) != 3) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s invalid month name, use %s", __FUNCTION__, month_names); + DEBUG_ERROR("TimeService::%s invalid month name, use %s", __FUNCTION__, month_names); return 0; } @@ -218,7 +218,7 @@ unsigned long TimeService::getTimeFromString(const String& input) if(month < 0 || month > 11 || day < 1 || day > 31 || year < 1900 || hour < 0 || hour > 24 || min < 0 || min > 60 || sec < 0 || sec > 60) { - DEBUG_ERROR("ArduinoIoTCloudTCP::%s invalid date values", __FUNCTION__); + DEBUG_ERROR("TimeService::%s invalid date values", __FUNCTION__); return 0; } From 56de2c15f0f39ec467a98e17c34db9ba6bdeebe4 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 17:15:58 +0100 Subject: [PATCH 13/19] Do not build code not compatible with LORA devices --- src/utility/time/TimeService.cpp | 14 +++++++++++--- src/utility/time/TimeService.h | 8 +++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 8341b09ee..ea9bc8275 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -105,8 +105,10 @@ TimeService::TimeService() , _is_tz_configured(false) , _timezone_offset(0) , _timezone_dst_until(0) +#ifdef HAS_TCP , _last_ntp_sync_tick(0) , _ntp_sync_interval_ms(TIMESERVICE_NTP_SYNC_TIMEOUT_ms) +#endif { } @@ -123,6 +125,7 @@ void TimeService::begin(ConnectionHandler * con_hdl) unsigned long TimeService::getTime() { +#ifdef HAS_TCP /* Check if it's time to sync */ unsigned long const current_tick = millis(); bool const is_ntp_sync_timeout = (current_tick - _last_ntp_sync_tick) > _ntp_sync_interval_ms; @@ -133,8 +136,12 @@ unsigned long TimeService::getTime() /* Read time from RTC */ unsigned long utc = getRTC(); return isTimeValid(utc) ? utc : EPOCH_AT_COMPILE_TIME; +#else + return EPOCH_AT_COMPILE_TIME; +#endif } +#ifdef HAS_TCP bool TimeService::sync() { _is_rtc_configured = false; @@ -153,6 +160,7 @@ void TimeService::setSyncInterval(unsigned long seconds) { _ntp_sync_interval_ms = seconds * 1000; } +#endif void TimeService::setTimeZoneData(long offset, unsigned long dst_until) { @@ -236,6 +244,7 @@ unsigned long TimeService::getTimeFromString(const String& input) * PRIVATE MEMBER FUNCTIONS **************************************************************************************/ +#ifdef HAS_TCP bool TimeService::connected() { if(_con_hdl == nullptr) { @@ -247,7 +256,6 @@ bool TimeService::connected() unsigned long TimeService::getRemoteTime() { -#ifndef HAS_LORA if(connected()) { /* At first try to see if a valid time can be obtained * using the network time available via the connection @@ -269,8 +277,6 @@ unsigned long TimeService::getRemoteTime() #endif } -#endif /* ifndef HAS_LORA */ - /* Return the epoch timestamp at compile time as a last * line of defense. Otherwise the certificate expiration * date is wrong and we'll be unable to establish a connection @@ -279,6 +285,8 @@ unsigned long TimeService::getRemoteTime() return EPOCH_AT_COMPILE_TIME; } +#endif /* HAS_TCP */ + bool TimeService::isTimeValid(unsigned long const time) { return (time > EPOCH_AT_COMPILE_TIME); diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 43fa2d4a8..149ff1c83 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -22,6 +22,7 @@ * INCLUDE **************************************************************************************/ +#include #include /************************************************************************************** @@ -39,7 +40,9 @@ class TimeService unsigned long getTime(); unsigned long getLocalTime(); void setTimeZoneData(long offset, unsigned long valid_until); +#ifdef HAS_TCP bool sync(); +#endif void setSyncInterval(unsigned long seconds); /* Helper function to convert an input String into a UNIX timestamp. @@ -54,12 +57,15 @@ class TimeService bool _is_tz_configured; long _timezone_offset; unsigned long _timezone_dst_until; +#ifdef HAS_TCP unsigned long _last_ntp_sync_tick; unsigned long _ntp_sync_interval_ms; +#endif +#ifdef HAS_TCP unsigned long getRemoteTime(); bool connected(); - static bool isTimeValid(unsigned long const time); +#endif void initRTC(); void setRTC(unsigned long time); unsigned long getRTC(); From 7cd0f63a58081447ff9d331c0fce9481a9f0ac11 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 17:20:31 +0100 Subject: [PATCH 14/19] Config RTC for LoRa devices using EPOCH_AT_COMPILE_TIME --- src/utility/time/TimeService.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index ea9bc8275..a0784e785 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -121,11 +121,13 @@ void TimeService::begin(ConnectionHandler * con_hdl) { _con_hdl = con_hdl; initRTC(); +#ifdef HAS_LORA + setRTC(EPOCH_AT_COMPILE_TIME); +#endif } unsigned long TimeService::getTime() { -#ifdef HAS_TCP /* Check if it's time to sync */ unsigned long const current_tick = millis(); bool const is_ntp_sync_timeout = (current_tick - _last_ntp_sync_tick) > _ntp_sync_interval_ms; @@ -136,16 +138,25 @@ unsigned long TimeService::getTime() /* Read time from RTC */ unsigned long utc = getRTC(); return isTimeValid(utc) ? utc : EPOCH_AT_COMPILE_TIME; -#else - return EPOCH_AT_COMPILE_TIME; -#endif } #ifdef HAS_TCP bool TimeService::sync() { _is_rtc_configured = false; - unsigned long utc = getRemoteTime(); + + unsigned long utc = EPOCH_AT_COMPILE_TIME; + if(_sync_func) { + utc = _sync_func(); + } else { +#ifdef HAS_TCP + utc = getRemoteTime(); +#endif +#ifdef HAS_LORA + /* Just keep incrementing stored RTC value*/ + utc = getRTC(); +#endif + } if(isTimeValid(utc)) { DEBUG_DEBUG("TimeServiceClass::%s Drift: %d RTC value: %u", __FUNCTION__, getRTC() - utc, utc); From a51b2d5c6a252d2a6111c96a39f3ee232044b5b0 Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 17:22:32 +0100 Subject: [PATCH 15/19] Add function to set internal time --- src/utility/time/TimeService.cpp | 5 +++++ src/utility/time/TimeService.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index a0784e785..26920d458 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -140,6 +140,11 @@ unsigned long TimeService::getTime() return isTimeValid(utc) ? utc : EPOCH_AT_COMPILE_TIME; } +void TimeService::setTime(unsigned long time) +{ + setRTC(time); +} + #ifdef HAS_TCP bool TimeService::sync() { diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 149ff1c83..743500ac2 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -38,6 +38,7 @@ class TimeService void begin (ConnectionHandler * con_hdl); unsigned long getTime(); + void setTime(unsigned long time); unsigned long getLocalTime(); void setTimeZoneData(long offset, unsigned long valid_until); #ifdef HAS_TCP From c9cfdbe79907f9903bdb83586f41db351504278e Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 20 Jan 2023 17:45:24 +0100 Subject: [PATCH 16/19] Add possibility to configure a custom time sync function --- src/utility/time/TimeService.cpp | 22 +++++++++++++--------- src/utility/time/TimeService.h | 16 ++++++++++------ 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 26920d458..c54a14d31 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -105,10 +105,9 @@ TimeService::TimeService() , _is_tz_configured(false) , _timezone_offset(0) , _timezone_dst_until(0) -#ifdef HAS_TCP -, _last_ntp_sync_tick(0) -, _ntp_sync_interval_ms(TIMESERVICE_NTP_SYNC_TIMEOUT_ms) -#endif +, _last_sync_tick(0) +, _sync_interval_ms(TIMESERVICE_NTP_SYNC_TIMEOUT_ms) +, _sync_func(nullptr) { } @@ -130,7 +129,7 @@ unsigned long TimeService::getTime() { /* Check if it's time to sync */ unsigned long const current_tick = millis(); - bool const is_ntp_sync_timeout = (current_tick - _last_ntp_sync_tick) > _ntp_sync_interval_ms; + bool const is_ntp_sync_timeout = (current_tick - _last_sync_tick) > _sync_interval_ms; if(!_is_rtc_configured || is_ntp_sync_timeout) { sync(); } @@ -145,7 +144,6 @@ void TimeService::setTime(unsigned long time) setRTC(time); } -#ifdef HAS_TCP bool TimeService::sync() { _is_rtc_configured = false; @@ -166,7 +164,7 @@ bool TimeService::sync() if(isTimeValid(utc)) { DEBUG_DEBUG("TimeServiceClass::%s Drift: %d RTC value: %u", __FUNCTION__, getRTC() - utc, utc); setRTC(utc); - _last_ntp_sync_tick = millis(); + _last_sync_tick = millis(); _is_rtc_configured = true; } return _is_rtc_configured; @@ -174,9 +172,15 @@ bool TimeService::sync() void TimeService::setSyncInterval(unsigned long seconds) { - _ntp_sync_interval_ms = seconds * 1000; + _sync_interval_ms = seconds * 1000; +} + +void TimeService::setSyncFunction(syncTimeFunctionPtr sync_func) +{ + if(sync_func) { + _sync_func = sync_func; + } } -#endif void TimeService::setTimeZoneData(long offset, unsigned long dst_until) { diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 743500ac2..b48019a6e 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -25,6 +25,12 @@ #include #include +/****************************************************************************** + * TYPEDEF + ******************************************************************************/ + +typedef unsigned long(*syncTimeFunctionPtr)(void); + /************************************************************************************** * CLASS DECLARATION **************************************************************************************/ @@ -41,10 +47,9 @@ class TimeService void setTime(unsigned long time); unsigned long getLocalTime(); void setTimeZoneData(long offset, unsigned long valid_until); -#ifdef HAS_TCP bool sync(); -#endif void setSyncInterval(unsigned long seconds); + void setSyncFunction(syncTimeFunctionPtr sync_func); /* Helper function to convert an input String into a UNIX timestamp. * The input String format must be as follow "2021 Nov 01 17:00:00" @@ -58,10 +63,9 @@ class TimeService bool _is_tz_configured; long _timezone_offset; unsigned long _timezone_dst_until; -#ifdef HAS_TCP - unsigned long _last_ntp_sync_tick; - unsigned long _ntp_sync_interval_ms; -#endif + unsigned long _last_sync_tick; + unsigned long _sync_interval_ms; + syncTimeFunctionPtr _sync_func; #ifdef HAS_TCP unsigned long getRemoteTime(); From fa22ff8372440f078361730664e0dab4be1060b5 Mon Sep 17 00:00:00 2001 From: pennam Date: Tue, 7 Feb 2023 17:06:32 +0100 Subject: [PATCH 17/19] Switch to TimeServiceClass Rename TimeService into TimeServiceClass and use a more standard way to instantiate it. --- extras/test/src/test_CloudSchedule.cpp | 14 +++++-- extras/test/src/util/PropertyTestUtil.cpp | 5 --- src/ArduinoIoTCloud.cpp | 2 +- src/ArduinoIoTCloud.h | 2 +- src/property/types/CloudSchedule.h | 3 +- src/utility/time/TimeService.cpp | 51 ++++++++++++----------- src/utility/time/TimeService.h | 10 +++-- 7 files changed, 46 insertions(+), 41 deletions(-) diff --git a/extras/test/src/test_CloudSchedule.cpp b/extras/test/src/test_CloudSchedule.cpp index 88acad6ab..b8c3c0999 100644 --- a/extras/test/src/test_CloudSchedule.cpp +++ b/extras/test/src/test_CloudSchedule.cpp @@ -13,16 +13,22 @@ unsigned long time_now = 1; /************************************************************************************** - * TimeService Fake CTOR/DTOR + * TimeServiceClass Fake CTOR **************************************************************************************/ -TimeService::TimeService() {} +TimeServiceClass::TimeServiceClass() {} /************************************************************************************** - * TimeService Fake Methods + * TimeServiceClass Fake Methods **************************************************************************************/ -unsigned long TimeService::getLocalTime() {return time_now;} +unsigned long TimeServiceClass::getLocalTime() {return time_now;} + +/************************************************************************************** + * TimeService Fake local instance + **************************************************************************************/ + +TimeServiceClass TimeService; /************************************************************************************** TEST CODE diff --git a/extras/test/src/util/PropertyTestUtil.cpp b/extras/test/src/util/PropertyTestUtil.cpp index ca71cd765..1bf41c437 100644 --- a/extras/test/src/util/PropertyTestUtil.cpp +++ b/extras/test/src/util/PropertyTestUtil.cpp @@ -18,8 +18,3 @@ unsigned long getTime() { return 0; } - -TimeService & ArduinoIoTCloudTimeService() { - static TimeService _timeService_instance; - return _timeService_instance; -} diff --git a/src/ArduinoIoTCloud.cpp b/src/ArduinoIoTCloud.cpp index 7763dd1f5..4997ec9b3 100644 --- a/src/ArduinoIoTCloud.cpp +++ b/src/ArduinoIoTCloud.cpp @@ -28,7 +28,7 @@ ArduinoIoTCloudClass::ArduinoIoTCloudClass() : _connection{nullptr} , _last_checked_property_index{0} -, _time_service(ArduinoIoTCloudTimeService()) +, _time_service(TimeService) , _tz_offset{0} , _tz_dst_until{0} , _thing_id{""} diff --git a/src/ArduinoIoTCloud.h b/src/ArduinoIoTCloud.h index 717bce0fa..bce662eb6 100644 --- a/src/ArduinoIoTCloud.h +++ b/src/ArduinoIoTCloud.h @@ -156,7 +156,7 @@ class ArduinoIoTCloudClass PropertyContainer _device_property_container; PropertyContainer _thing_property_container; unsigned int _last_checked_property_index; - TimeService & _time_service; + TimeServiceClass & _time_service; int _tz_offset; unsigned int _tz_dst_until; String _thing_id; diff --git a/src/property/types/CloudSchedule.h b/src/property/types/CloudSchedule.h index ecf6345ec..9a9222968 100644 --- a/src/property/types/CloudSchedule.h +++ b/src/property/types/CloudSchedule.h @@ -115,7 +115,7 @@ class Schedule { bool isActive() { - ScheduleTimeType now = _schedule_time_service.getLocalTime(); + ScheduleTimeType now = TimeService.getLocalTime(); if(checkTimeValid(now)) { /* We have to wait RTC configuration and Timezone setting from the cloud */ @@ -201,7 +201,6 @@ class Schedule { return !(operator==(aSchedule)); } private: - TimeService & _schedule_time_service = ArduinoIoTCloudTimeService(); ScheduleUnit getScheduleUnit(ScheduleConfigurationType msk) { return static_cast((msk & SCHEDULE_UNIT_MASK) >> SCHEDULE_UNIT_SHIFT); diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index c54a14d31..24856c14f 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -99,7 +99,7 @@ static time_t const EPOCH = 0; * CTOR/DTOR **************************************************************************************/ -TimeService::TimeService() +TimeServiceClass::TimeServiceClass() : _con_hdl(nullptr) , _is_rtc_configured(false) , _is_tz_configured(false) @@ -116,7 +116,7 @@ TimeService::TimeService() * PUBLIC MEMBER FUNCTIONS **************************************************************************************/ -void TimeService::begin(ConnectionHandler * con_hdl) +void TimeServiceClass::begin(ConnectionHandler * con_hdl) { _con_hdl = con_hdl; initRTC(); @@ -125,7 +125,7 @@ void TimeService::begin(ConnectionHandler * con_hdl) #endif } -unsigned long TimeService::getTime() +unsigned long TimeServiceClass::getTime() { /* Check if it's time to sync */ unsigned long const current_tick = millis(); @@ -139,12 +139,12 @@ unsigned long TimeService::getTime() return isTimeValid(utc) ? utc : EPOCH_AT_COMPILE_TIME; } -void TimeService::setTime(unsigned long time) +void TimeServiceClass::setTime(unsigned long time) { setRTC(time); } -bool TimeService::sync() +bool TimeServiceClass::sync() { _is_rtc_configured = false; @@ -170,29 +170,29 @@ bool TimeService::sync() return _is_rtc_configured; } -void TimeService::setSyncInterval(unsigned long seconds) +void TimeServiceClass::setSyncInterval(unsigned long seconds) { _sync_interval_ms = seconds * 1000; } -void TimeService::setSyncFunction(syncTimeFunctionPtr sync_func) +void TimeServiceClass::setSyncFunction(syncTimeFunctionPtr sync_func) { if(sync_func) { _sync_func = sync_func; } } -void TimeService::setTimeZoneData(long offset, unsigned long dst_until) +void TimeServiceClass::setTimeZoneData(long offset, unsigned long dst_until) { if(_timezone_offset != offset || _timezone_dst_until != dst_until) { - DEBUG_DEBUG("TimeService::%s offset: %d dst_unitl %ul", __FUNCTION__, offset, dst_until); + DEBUG_DEBUG("TimeServiceClass::%s offset: %d dst_unitl %ul", __FUNCTION__, offset, dst_until); _timezone_offset = offset; _timezone_dst_until = dst_until; _is_tz_configured = true; } } -unsigned long TimeService::getLocalTime() +unsigned long TimeServiceClass::getLocalTime() { unsigned long utc = getTime(); if(_is_tz_configured) { @@ -202,7 +202,7 @@ unsigned long TimeService::getLocalTime() } } -unsigned long TimeService::getTimeFromString(const String& input) +unsigned long TimeServiceClass::getTimeFromString(const String& input) { struct tm t = { @@ -224,21 +224,21 @@ unsigned long TimeService::getTimeFromString(const String& input) static const int expected_parameters = 6; if(input == nullptr || input.length() != expected_length) { - DEBUG_ERROR("TimeService::%s invalid input length", __FUNCTION__); + DEBUG_ERROR("TimeServiceClass::%s invalid input length", __FUNCTION__); return 0; } int scanned_parameters = sscanf(input.c_str(), "%d %s %d %d:%d:%d", &year, s_month, &day, &hour, &min, &sec); if(scanned_parameters != expected_parameters) { - DEBUG_ERROR("TimeService::%s invalid input parameters number", __FUNCTION__); + DEBUG_ERROR("TimeServiceClass::%s invalid input parameters number", __FUNCTION__); return 0; } char * s_month_position = strstr(month_names, s_month); if(s_month_position == nullptr || strlen(s_month) != 3) { - DEBUG_ERROR("TimeService::%s invalid month name, use %s", __FUNCTION__, month_names); + DEBUG_ERROR("TimeServiceClass::%s invalid month name, use %s", __FUNCTION__, month_names); return 0; } @@ -246,7 +246,7 @@ unsigned long TimeService::getTimeFromString(const String& input) if(month < 0 || month > 11 || day < 1 || day > 31 || year < 1900 || hour < 0 || hour > 24 || min < 0 || min > 60 || sec < 0 || sec > 60) { - DEBUG_ERROR("TimeService::%s invalid date values", __FUNCTION__); + DEBUG_ERROR("TimeServiceClass::%s invalid date values", __FUNCTION__); return 0; } @@ -265,7 +265,7 @@ unsigned long TimeService::getTimeFromString(const String& input) **************************************************************************************/ #ifdef HAS_TCP -bool TimeService::connected() +bool TimeServiceClass::connected() { if(_con_hdl == nullptr) { return false; @@ -274,7 +274,7 @@ bool TimeService::connected() } } -unsigned long TimeService::getRemoteTime() +unsigned long TimeServiceClass::getRemoteTime() { if(connected()) { /* At first try to see if a valid time can be obtained @@ -307,12 +307,12 @@ unsigned long TimeService::getRemoteTime() #endif /* HAS_TCP */ -bool TimeService::isTimeValid(unsigned long const time) +bool TimeServiceClass::isTimeValid(unsigned long const time) { return (time > EPOCH_AT_COMPILE_TIME); } -void TimeService::initRTC() +void TimeServiceClass::initRTC() { #if defined (ARDUINO_ARCH_SAMD) samd_initRTC(); @@ -329,7 +329,7 @@ void TimeService::initRTC() #endif } -void TimeService::setRTC(unsigned long time) +void TimeServiceClass::setRTC(unsigned long time) { #if defined (ARDUINO_ARCH_SAMD) samd_setRTC(time); @@ -346,7 +346,7 @@ void TimeService::setRTC(unsigned long time) #endif } -unsigned long TimeService::getRTC() +unsigned long TimeServiceClass::getRTC() { #if defined (ARDUINO_ARCH_SAMD) return samd_getRTC(); @@ -483,7 +483,8 @@ unsigned long esp8266_getRTC() } #endif -TimeService & ArduinoIoTCloudTimeService() { - static TimeService _timeService_instance; - return _timeService_instance; -} +/****************************************************************************** + * EXTERN DEFINITION + ******************************************************************************/ + +TimeServiceClass TimeService; diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index b48019a6e..7f6529ecf 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -35,12 +35,12 @@ typedef unsigned long(*syncTimeFunctionPtr)(void); * CLASS DECLARATION **************************************************************************************/ -class TimeService +class TimeServiceClass { public: - TimeService(); + TimeServiceClass(); void begin (ConnectionHandler * con_hdl); unsigned long getTime(); @@ -77,6 +77,10 @@ class TimeService }; -TimeService & ArduinoIoTCloudTimeService(); +/****************************************************************************** + * EXTERN DECLARATION + ******************************************************************************/ + +extern TimeServiceClass TimeService; #endif /* ARDUINO_IOT_CLOUD_TIME_SERVICE_H_ */ From 3c069770354fe3d737174bc9b54b875668580d2e Mon Sep 17 00:00:00 2001 From: pennam Date: Wed, 8 Feb 2023 14:29:13 +0100 Subject: [PATCH 18/19] Check Timezone offset boundaries --- src/utility/time/TimeService.cpp | 20 ++++++++++++++------ src/utility/time/TimeService.h | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/utility/time/TimeService.cpp b/src/utility/time/TimeService.cpp index 24856c14f..0b0b982fc 100644 --- a/src/utility/time/TimeService.cpp +++ b/src/utility/time/TimeService.cpp @@ -103,7 +103,7 @@ TimeServiceClass::TimeServiceClass() : _con_hdl(nullptr) , _is_rtc_configured(false) , _is_tz_configured(false) -, _timezone_offset(0) +, _timezone_offset(24 * 60 * 60) , _timezone_dst_until(0) , _last_sync_tick(0) , _sync_interval_ms(TIMESERVICE_NTP_SYNC_TIMEOUT_ms) @@ -184,11 +184,13 @@ void TimeServiceClass::setSyncFunction(syncTimeFunctionPtr sync_func) void TimeServiceClass::setTimeZoneData(long offset, unsigned long dst_until) { - if(_timezone_offset != offset || _timezone_dst_until != dst_until) { - DEBUG_DEBUG("TimeServiceClass::%s offset: %d dst_unitl %ul", __FUNCTION__, offset, dst_until); - _timezone_offset = offset; - _timezone_dst_until = dst_until; - _is_tz_configured = true; + if(isTimeZoneOffsetValid(offset) && isTimeValid(dst_until)) { + if(_timezone_offset != offset || _timezone_dst_until != dst_until) { + DEBUG_DEBUG("TimeServiceClass::%s offset: %d dst_unitl %u", __FUNCTION__, offset, dst_until); + _timezone_offset = offset; + _timezone_dst_until = dst_until; + _is_tz_configured = true; + } } } @@ -312,6 +314,12 @@ bool TimeServiceClass::isTimeValid(unsigned long const time) return (time > EPOCH_AT_COMPILE_TIME); } +bool TimeServiceClass::isTimeZoneOffsetValid(long const offset) +{ + /* UTC offset can go from +14 to -12 hours */ + return ((offset < (14 * 60 * 60)) && (offset > (-12 * 60 * 60))); +} + void TimeServiceClass::initRTC() { #if defined (ARDUINO_ARCH_SAMD) diff --git a/src/utility/time/TimeService.h b/src/utility/time/TimeService.h index 7f6529ecf..6e6af6bb5 100644 --- a/src/utility/time/TimeService.h +++ b/src/utility/time/TimeService.h @@ -74,6 +74,8 @@ class TimeServiceClass void initRTC(); void setRTC(unsigned long time); unsigned long getRTC(); + static bool isTimeValid(unsigned long const time); + static bool isTimeZoneOffsetValid(long const offset); }; From 77ea16daf1a7152ba07d73f51be79856f8b483ba Mon Sep 17 00:00:00 2001 From: pennam Date: Fri, 17 Feb 2023 10:49:03 +0100 Subject: [PATCH 19/19] NTPUtils use hardware random number generator for ESP boards --- src/utility/time/NTPUtils.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/utility/time/NTPUtils.cpp b/src/utility/time/NTPUtils.cpp index 9ce276c8c..24c626a73 100644 --- a/src/utility/time/NTPUtils.cpp +++ b/src/utility/time/NTPUtils.cpp @@ -92,8 +92,11 @@ void NTPUtils::sendNTPpacket(UDP & udp) int NTPUtils::getRandomPort(int const min_port, int const max_port) { -#ifdef BOARD_HAS_ECCX08 +#if defined (BOARD_HAS_ECCX08) return ECCX08.random(min_port, max_port); +#elif defined (ARDUINO_ARCH_ESP8266) || (ARDUINO_ARCH_ESP32) + /* Uses HW Random Number Generator */ + return random(min_port, max_port); #else randomSeed(analogRead(0)); return random(min_port, max_port);