diff --git a/components/time/CMakeLists.txt b/components/time/CMakeLists.txt index 4de7d54..48e5ec5 100644 --- a/components/time/CMakeLists.txt +++ b/components/time/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( SRCS "time_manager.c" INCLUDE_DIRS "." - REQUIRES console_wrapper lwip settings + REQUIRES console_wrapper lwip nvs_flash settings ) diff --git a/components/time/time_manager.c b/components/time/time_manager.c index 03d6601..d820769 100644 --- a/components/time/time_manager.c +++ b/components/time/time_manager.c @@ -10,10 +10,15 @@ #include "esp_log.h" #include "esp_sntp.h" +#include "freertos/FreeRTOS.h" +#include "nvs_flash.h" #include #define TAG "Time" +#define NVS_NAMESPACE "time" +#define TIMESTAMP_KEY "timestamp" + static void handle_timezone_update(const char *timezone) { setenv("TZ", timezone, 1); @@ -54,6 +59,29 @@ static const char *sync_status_description(sntp_sync_status_t status) } } +static int store_time(void) +{ + esp_err_t error; + + nvs_handle_t nvs; + error = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs); + if (error != ESP_OK) { + ESP_LOGE(TAG, "Error opening NVS: %04x", error); + return 1; + } + + struct timeval tv; + gettimeofday(&tv, NULL); + error = nvs_set_u64(nvs, TIMESTAMP_KEY, tv.tv_sec); + if (error == ESP_OK) + ESP_LOGI(TAG, "Stored time"); + else + ESP_LOGE(TAG, "Error storing time: %04x", error); + + nvs_close(nvs); + return error == ESP_OK ? 0 : 1; +} + static int command_func(int argc, char **argv) { if (argc == 1) { @@ -65,10 +93,13 @@ static int command_func(int argc, char **argv) const sntp_sync_status_t status = sntp_get_sync_status(); printf("%s\n", sync_status_description(status)); return 0; + } else if (strcmp(argv[1], "store") == 0) { + return store_time(); } else { Time time; - if (sscanf(argv[1], "%02u:%02u", &time.hour, &time.minute) < 2 - || time.hour > 23 || time.minute > 59) { + const int result + = sscanf(argv[1], "%02u:%02u", &time.hour, &time.minute); + if (result < 2 || time.hour > 23 || time.minute > 59) { printf("Invalid time\n"); return 1; } @@ -81,6 +112,16 @@ static int command_func(int argc, char **argv) } } +static void time_saver_func(void *arg) +{ + (void)arg; + const TickType_t delay = CONFIG_TIME_SAVE_PERIOD_MS / portTICK_PERIOD_MS; + while (1) { + (void)store_time(); + vTaskDelay(delay); + } +} + void time_manager_init(void) { char timezone[SETTINGS_MAX_VALUE_SIZE]; @@ -100,6 +141,31 @@ void time_manager_init(void) console_register( "time", "Get / set time and SNTP status", "time OR time OR time sntp-status", command_func); + + // Attempt to load time from storage + esp_err_t error; + nvs_handle_t nvs; + error = nvs_open(NVS_NAMESPACE, NVS_READONLY, &nvs); + if (error == ESP_OK) { + uint64_t timestamp; + error = nvs_get_u64(nvs, TIMESTAMP_KEY, ×tamp); + if (error == ESP_OK) { + struct timeval tv = { .tv_sec = (time_t)timestamp }; + settimeofday(&tv, NULL); + } else { + if (error != ESP_ERR_NVS_NOT_FOUND) + ESP_LOGE(TAG, "Error getting stored time: %04x", error); + } + nvs_close(nvs); + } else { + if (error != ESP_ERR_NVS_NOT_FOUND) + ESP_LOGE(TAG, "Error opening NVS: %04x", error); + } + + // Start task to save time to storage + (void)xTaskCreate( + &time_saver_func, "time saver", CONFIG_DEFAULT_TASK_STACK, NULL, 1, + NULL); } Time get_time(void) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 155bc1c..f0df9b7 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -30,4 +30,10 @@ menu "Bedside clock settings" config WIFI_MAX_RETRIES int "Maximum number of times to retry connecting to WiFi network" default 10 + config TIME_SAVE_PERIOD_MS + int "How often (in ms) to save the time to persistent storage" + default 300000 + config DEFAULT_TASK_STACK + int "Default task stack size (in words)" + default 4096 endmenu