From ef6061fc2144a46dc0ee0e040aa51b249b9e83a5 Mon Sep 17 00:00:00 2001 From: Markus Ransberger Date: Tue, 2 Apr 2024 03:43:42 +0200 Subject: [PATCH] Fix of NTP logic. Minor refactoring. --- include/wordclock_esp8266.h | 12 ++++- src/wordclock_esp8266.cpp | 93 ++++++++++++++++--------------------- 2 files changed, 51 insertions(+), 54 deletions(-) diff --git a/include/wordclock_esp8266.h b/include/wordclock_esp8266.h index f789f70..fec7519 100644 --- a/include/wordclock_esp8266.h +++ b/include/wordclock_esp8266.h @@ -2,6 +2,7 @@ #define WORDCLOCK_ESP8266_H #include +#include #include #include "led_matrix.h" #include "udp_logger.h" @@ -11,6 +12,13 @@ #define EEPROM_SIZE (sizeof(EepromLayout_st) / sizeof(uint8_t)) +#define BUILD_YEAR (__DATE__ + 7) /* Will expand to current year at compile time as string. */ +#define NTP_MININUM_RX_YEAR (atoi(BUILD_YEAR) - 1) /* Will expand to current year at compile time minus one. */ +#define NTP_MININUM_YEAR (1900) // NTP minimum year is 1900 +#define NTP_MAX_UPDATE_TIME_US (500000) // 500ms max update time +#define NTP_NEXT_UPDATE_DELAY_US (10000000) // 10s delay time between updates +#define NTP_WATCHDOG_COUNTER_INIT (30) // Watchdog value, count of retries before restart + typedef struct { int start_hour; @@ -54,6 +62,7 @@ typedef enum NUM_STATES } ClockState_en; +bool get_ntp_time(uint32 usec); String leading_zero2digit(int value); uint8_t calculate_dynamic_brightness(uint8_t min_brightness, uint8_t max_brightness, int hours, int minutes, bool summertime); uint8_t update_brightness(void); @@ -67,8 +76,7 @@ void handle_data_request(void); void handle_led_direct(void); void limit_value_ranges(void); void log_time(tm local_time); -void ntp_time_update(uint32 *last_ntp_update_us); -void ntp_time_update(uint32 *last_ntp_update_us); +void ntp_time_update(uint32 max_update_time); void on_state_entry(uint8_t state); void read_settings_from_EEPROM(void); void reset_wifi_credentials(void); diff --git a/src/wordclock_esp8266.cpp b/src/wordclock_esp8266.cpp index b8e1cfa..67e2291 100644 --- a/src/wordclock_esp8266.cpp +++ b/src/wordclock_esp8266.cpp @@ -48,15 +48,14 @@ // ---------------------------------------------------------------------------------- // GLOBAL VARIABLES // ---------------------------------------------------------------------------------- -UDPLogger logger; // Logger +UDPLogger logger; // Global UDP logger instance Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(MATRIX_WIDTH, MATRIX_HEIGHT + 1, NEOPIXEL_PIN, NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG, NEO_GRB + NEO_KHZ800); // NeoMatrix -char strftime_buf[64]; // Time string buffer ESP8266WebServer webserver(HTTP_PORT); // Webserver LEDMatrix led_matrix = LEDMatrix(&matrix, DEFAULT_BRIGHTNESS, &logger); // NeoMatrix wrapper -struct tm timeinfo; // Structure tm holds time information -time_t now; // Seconds since Epoch (1970) - UTC +struct tm time_info; // Structure tm holds time information +time_t time_now; // Seconds since Epoch (1970) - UTC // ---------------------------------------------------------------------------------- // STATIC VARIABLES @@ -70,19 +69,20 @@ static Pong pong = Pong(&led_matrix, &logger); static Snake snake = Snake(&led_matrix, &logger); static Tetris tetris = Tetris(&led_matrix, &logger); -static uint32 last_ntp_update_us = 0; // time of last NTP update +static uint32 last_ntp_update_us = 0; // Time of last NTP update +static char strftime_buf[64]; // Time string buffer -static bool flg_night_mode = false; // state of nightmode -static bool flg_reset_wifi_creds = false; // used to reset stored wifi credentials +static bool flg_night_mode = false; // State of nightmode +static bool flg_reset_wifi_creds = false; // Used to reset stored wifi credentials static bool spiral_direction = false; -static float filter_factor = DEFAULT_SMOOTHING_FACTOR; // stores smoothing factor for led transition +static float filter_factor = DEFAULT_SMOOTHING_FACTOR; // Stores smoothing factor for led transition, value of 1 represents no smoothing. static int watchdog_counter = 30; // Watchdog counter to trigger restart if NTP update was not possible 30 times in a row (5min) -static uint32 last_led_direct_us = 0; // time of last direct LED command (=> fall back to normal mode after timeout) -static uint32_t heartbeat_counter = 0; // for heartbeat on-time in seconds -static uint32_t main_color_clock = colors_24bit[2]; // color of the clock and digital clock -static uint32_t main_color_snake = colors_24bit[1]; // color of the random snake animation -static uint8_t current_brightness = DEFAULT_BRIGHTNESS; // current brightness of LEDs -static uint8_t current_state = (uint8_t)ST_CLOCK; // stores current state +static uint32 last_led_direct_us = 0; // Time of last direct LED command (=> fall back to normal mode after timeout) +static uint32_t heartbeat_counter = 0; // Heartbeat on-time in seconds +static uint32_t main_color_clock = colors_24bit[2]; // Color of the clock and digital clock +static uint32_t main_color_snake = colors_24bit[1]; // Color of the random snake animation +static uint8_t current_brightness = DEFAULT_BRIGHTNESS; // Current brightness of LEDs +static uint8_t current_state = (uint8_t)ST_CLOCK; // Stores current state static const String state_names[NUM_STATES] = {"Clock", "DiClock", "Spiral", "Tetris", "Snake", "PingPong", "Hearts"}; static const uint32_t period_timings[NUM_STATES] = {PERIOD_CLOCK_UPDATE_US, PERIOD_CLOCK_UPDATE_US, @@ -170,16 +170,12 @@ void setup() // create UDP Logger to send logging messages via UDP multicast logger = UDPLogger(WiFi.localIP(), LOGGER_MULTICAST_IP, LOGGER_MULTICAST_PORT, "Wordclock 2.0"); logger.log_string("Start program\n"); - delay(10); logger.log_string("Sketchname: " + String(__FILE__)); - delay(10); logger.log_string("Build: " + String(__TIMESTAMP__)); - delay(10); logger.log_string("IP: " + WiFi.localIP().toString()); - delay(10); logger.log_string("Reset Reason: " + ESP.getResetReason()); - if (resetInfo->reason != REASON_SOFT_RESTART) + if (resetInfo->reason != REASON_SOFT_RESTART) // only if there was a cold start/hard reset { // quickly test each LED for (int16_t row = 0; row < MATRIX_HEIGHT; row++) @@ -215,12 +211,12 @@ void setup() // setup NTP configTime(MY_TZ, NTP_SERVER_URL); - ntp_time_update(&last_ntp_update_us); // NTP time update + ntp_time_update(NTP_MAX_UPDATE_TIME_US); // NTP time update // show the current time for short time in words - String timeMessage = time_to_string(timeinfo.tm_hour, timeinfo.tm_min); + String timeMessage = time_to_string(time_info.tm_hour, time_info.tm_min); show_string_on_clock(timeMessage, main_color_clock); - draw_minute_indicator(timeinfo.tm_min, main_color_clock); + draw_minute_indicator(time_info.tm_min, main_color_clock); led_matrix.draw_on_matrix_smooth(filter_factor); // init all animation modes @@ -289,7 +285,7 @@ void loop() check_wifi_status(); // check WiFi status before NTP update delay(10); - ntp_time_update(&last_ntp_update_us); // NTP time update + ntp_time_update(NTP_MAX_UPDATE_TIME_US); // NTP time update delay(10); current_brightness = update_brightness(); // update brightness every PERIOD_NTP_UPDATE_US @@ -315,29 +311,22 @@ void loop() * * @return boolean - true if NTP update was successful, false otherwise */ -bool get_ntp_time(uint32 sec) +bool get_ntp_time(uint32 usec) { - uint32 start = system_get_time() / 1000; // ms + uint32 start_time_us = system_get_time(); do { - time(&now); - localtime_r(&now, &timeinfo); + time(&time_now); + localtime_r(&time_now, &time_info); delay(10); - } while (((system_get_time() / 1000 - start) <= (1000 * sec)) && (timeinfo.tm_year < (2023 - 1900))); + } while (((system_get_time() - start_time_us) <= usec) && (time_info.tm_year < (NTP_MININUM_RX_YEAR - NTP_MININUM_YEAR))); - if (timeinfo.tm_year <= (2023 - 1900)) - { - return false; // the NTP call was not successful - } - else - { - return true; - } + return ((time_info.tm_year <= (NTP_MININUM_RX_YEAR - NTP_MININUM_YEAR)) ? false : true); } void log_time(tm local_time) { - strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); + strftime(strftime_buf, sizeof(strftime_buf), "%c", &time_info); logger.log_string(String(strftime_buf)); } @@ -347,13 +336,13 @@ void handle_current_state() { case ST_CLOCK: // state clock { - (void)show_string_on_clock(time_to_string((uint8_t)timeinfo.tm_hour, (uint8_t)timeinfo.tm_min), main_color_clock); - draw_minute_indicator((uint8_t)timeinfo.tm_min, main_color_clock); + (void)show_string_on_clock(time_to_string((uint8_t)time_info.tm_hour, (uint8_t)time_info.tm_min), main_color_clock); + draw_minute_indicator((uint8_t)time_info.tm_min, main_color_clock); break; } case ST_DICLOCK: // state diclock { - show_digital_clock((uint8_t)timeinfo.tm_hour, (uint8_t)timeinfo.tm_min, main_color_clock); + show_digital_clock((uint8_t)time_info.tm_hour, (uint8_t)time_info.tm_min, main_color_clock); break; } case ST_SPIRAL: // state spiral @@ -447,8 +436,8 @@ void check_wifi_status() void check_night_mode() { // check if nightmode need to be activated - int hours = timeinfo.tm_hour; - int minutes = timeinfo.tm_min; + int hours = time_info.tm_hour; + int minutes = time_info.tm_min; if ((hours == night_mode_times_ps->start_hour) && (minutes == night_mode_times_ps->start_min)) { @@ -465,21 +454,21 @@ void check_night_mode() * * @param None */ -void ntp_time_update(uint32 *last_ntp_update_us) +void ntp_time_update(uint32 max_update_time) { // NTP time update - bool ntp_retval = get_ntp_time(*last_ntp_update_us / 10000000); + bool ntp_retval = get_ntp_time(max_update_time); if (ntp_retval == true) { - log_time(timeinfo); - *last_ntp_update_us = system_get_time(); - watchdog_counter = 30; + log_time(time_info); + last_ntp_update_us = system_get_time(); + watchdog_counter = NTP_WATCHDOG_COUNTER_INIT; } else { logger.log_string("NTP-Update was not successful."); - *last_ntp_update_us += 10000000; + last_ntp_update_us += NTP_NEXT_UPDATE_DELAY_US; watchdog_counter--; } @@ -499,7 +488,7 @@ void ntp_time_update(uint32 *last_ntp_update_us) */ void on_state_entry(uint8_t state) { - filter_factor = 0.5f; + filter_factor = DEFAULT_SMOOTHING_FACTOR; switch (state) { case ST_SPIRAL: @@ -1030,9 +1019,9 @@ uint8_t update_brightness() { new_brightness = calculate_dynamic_brightness(brightness_ps->dyn_brightness_min, brightness_ps->dyn_brightness_max, - timeinfo.tm_hour, - timeinfo.tm_min, - timeinfo.tm_isdst); + time_info.tm_hour, + time_info.tm_min, + time_info.tm_isdst); } else // use static brightness {