#include "time_manager.h" #include // 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)); }