Introduced new TimeManager class with much better offline handling. Refactoring.

This commit is contained in:
2024-04-03 21:49:28 +02:00
parent 0543b9c0c7
commit a4be8f1d9e
6 changed files with 335 additions and 143 deletions

View File

@@ -0,0 +1,166 @@
#include "time_manager.h"
#include <ESP8266TimerInterrupt.h> // https://github.com/khoih-prog/ESP8266TimerInterrupt
#include "wordclock_constants.h"
#include "time.h"
extern UDPLogger logger;
extern ESP8266Timer ITimer; // ESP8266 Timer
extern void IRAM_ATTR TimerHandler(); // ISR function
// ----------------------------------------------------------------------------------
// Class
// ----------------------------------------------------------------------------------
TimeManager::TimeManager(const char *tz,
const char *ntp_server,
uint32 ntp_update_period_s,
uint32 ntp_retry_delay_us,
uint32 ntp_max_offline_time_s,
UDPLogger *logger)
{
_tz = tz;
_ntp_server = ntp_server;
_ntp_max_offline_time_s = ntp_max_offline_time_s;
_ntp_retry_delay_us = ntp_retry_delay_us;
_ntp_update_period_s = ntp_update_period_s;
_logger = logger;
}
struct tm TimeManager::time_info(void)
{
localtime_r(&_time_now_local, &_time_info); // convert time
return _time_info;
}
bool TimeManager::ntp_sync_successful(void) const
{
return (_time_now_ntp > 0);
}
/**
* @brief NTP time update, should be called in loop().
*
* @retval true if last update was successful
*/
bool TimeManager::ntp_time_update(bool init)
{
// Check if minimum update delay has elapsed
if (!init && (((system_get_time() - _ntp_sync_timestamp_us) <= _ntp_retry_delay_us) || ((system_get_time() - _ntp_sync_timestamp_us) <= (_ntp_update_period_s * 1000000))))
{
return false;
}
if (init)
{
set_up_ntp(); // set up NTP server once
}
bool ntp_update_successful = false; // NTP time update
struct tm time_info; // local NTP time info
_ntp_sync_timestamp_us = system_get_time(); // NTP update start time
do
{
time(&_time_now_ntp); // get time from server and save it into _time_now_ntp
localtime_r(&_time_now_ntp, &time_info); // convert time
yield(); // since this loop could take up to NTP_MAX_UPDATE_TIME_US
} while (((system_get_time() - _ntp_sync_timestamp_us) <= NTP_MAX_UPDATE_TIME_US) && (time_info.tm_year < (NTP_MININUM_RX_YEAR - NTP_MININUM_YEAR)));
ntp_update_successful = (time_info.tm_year <= (NTP_MININUM_RX_YEAR - NTP_MININUM_YEAR)) ? false : true; // sanity check
if (ntp_update_successful == true)
{
_ntp_sync_timestamp_us = system_get_time(); // save NTP update timestamp
_time_info = time_info; // take over time_info to member variable
log_time(_time_info); // log current time
if (!init && (abs(_time_now_ntp - _time_now_local) > 10)) // in the case that the local time drifted more than 10s in _ntp_update_period_s
{
_logger->log_string(String("Difference between local and NTP time was more than 10 seconds!\n"));
_logger->log_string("Local time was: " + String(_time_now_local) + ", NTP time is: " + String(_time_now_ntp) + "\n");
}
_time_now_local = _time_now_ntp; // sync local time with NTP time
if (init) // only set up the timer once after NTP update was successful
{
set_up_timer_isr();
}
}
else
{
logger.log_string("NTP-Update was not successful. Retrying in " + String(_ntp_retry_delay_us / 1000) + "ms.\n");
}
return ntp_update_successful;
}
bool TimeManager::ntp_update_failed_prolonged(void) const
{
return _time_now_local >= (_time_now_ntp + (time_t)_ntp_max_offline_time_s);
}
int TimeManager::tm_min(void)
{
localtime_r(&_time_now_local, &_time_info); // convert time
return _time_info.tm_min;
}
int TimeManager::tm_hour(void)
{
localtime_r(&_time_now_local, &_time_info); // convert time
return _time_info.tm_hour;
}
int TimeManager::tm_year(void)
{
localtime_r(&_time_now_local, &_time_info); // convert time
return _time_info.tm_year;
}
bool TimeManager::tm_isdst(void)
{
localtime_r(&_time_now_local, &_time_info); // convert time
return _time_info.tm_isdst > 0;
}
// TODO
void TimeManager::set_up_timer_isr(void) const
{
// set up timer interrupt after NTP update is done
if (ntp_sync_successful())
{
(void)ITimer.attachInterruptInterval(PERIOD_CLOCK_UPDATE_US, TimerHandler);
}
else
{
logger.log_string("WARNING: Timer interrupt was not attached!");
}
}
void TimeManager::set_up_ntp(void) const
{
if ((_tz != nullptr) && (_ntp_server != nullptr))
{
// set up NTP server and timezone at init
configTime(_tz, _ntp_server);
logger.log_string(String("NTP server was initialized!"));
}
else
{
logger.log_string(String("Timezone and/or NTP-Server were not given!"));
}
}
/**
* @brief Log time_info as string.
*
* @param local_time
*/
void TimeManager::log_time(struct tm time_info) const
{
char strftime_buf[64]; // Time string buffer
strftime(strftime_buf, sizeof(strftime_buf), "%c", &time_info);
logger.log_string(String(strftime_buf));
}