esp_garden git · master
Distributed ESP sensor and actuator system (garden)
C++ 70.7% Markdown 18% C 10.7%git clone https://git.christianimmanuel.de/embedded/esp_garden.gitwget https://git.christianimmanuel.de/embedded/esp_garden/archive/esp_garden.tar.gzFix broken time after power loss
client_sensor/main/ClientSensor.cpp | 61 ++++++++++++++++++++++++++++++++++--- client_sensor/main/ClientSensor.h | 3 +- client_sensor/main/main.cpp | 10 ++++++ 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/client_sensor/main/ClientSensor.cpp b/client_sensor/main/ClientSensor.cpp index 77d656a..8b16ef9 100644 --- a/client_sensor/main/ClientSensor.cpp +++ b/client_sensor/main/ClientSensor.cpp @@ -14,12 +14,16 @@ #include <sys/time.h> volatile bool rtc_synced_with_server = false; -volatile bool response_received = false; -volatile bool send_process_complete = false; +volatile bool response_received = false; +volatile bool send_process_complete = false; volatile bool send_response_process_complete = false; uint8_t config_request_attempts = 0; +// save time over power loss +extern int64_t stored_epoch_ref; +extern int64_t stored_uptime_ref; + // ---------------------------------------------------------------------------- // Helper // ---------------------------------------------------------------------------- @@ -235,8 +239,14 @@ void on_DataRecv(const esp_now_recv_info *info, const uint8_t *data, int len) { settimeofday(&tv, nullptr); rtc_synced_with_server = true; ESP_LOGI(TAG, "System time updated from server."); + + // Save epoch + uptime to NVS + stored_epoch_ref = server_unix; + stored_uptime_ref = esp_timer_get_time() / 1000000LL; + save_time_reference(stored_epoch_ref, stored_uptime_ref); // persist to flash } + ESP_LOGI(TAG, "Setting send_process_complete to TRUE"); send_process_complete = true; } @@ -455,8 +465,49 @@ bool send_AndWaitResponse(const uint8_t* peer, const char* message, uint32_t tim // Time handling // ---------------------------------------------------------------------------- +#define TIME_NAMESPACE "time_ref" + +void save_time_reference(int64_t epoch, int64_t uptime) { + nvs_handle_t nvs; + if (nvs_open(TIME_NAMESPACE, NVS_READWRITE, &nvs) == ESP_OK) { + nvs_set_i64(nvs, "epoch", epoch); + nvs_set_i64(nvs, "uptime", uptime); + nvs_commit(nvs); + nvs_close(nvs); + } +} + +void load_time_reference(int64_t *epoch, int64_t *uptime) { + nvs_handle_t nvs; + int64_t e = 0, u = 0; + if (nvs_open(TIME_NAMESPACE, NVS_READONLY, &nvs) == ESP_OK) { + nvs_get_i64(nvs, "epoch", &e); + nvs_get_i64(nvs, "uptime", &u); + nvs_close(nvs); + } + if (epoch) *epoch = e; + if (uptime) *uptime = u; +} + int64_t get_CurrentUnix() { - return (int64_t)time(nullptr); + struct timeval tv; + gettimeofday(&tv, NULL); + + if (tv.tv_sec > 100000) + return tv.tv_sec; + + // time not set + // Try to reconstruct approximate epoch from stored reference + extern int64_t stored_epoch_ref; // last known good epoch + extern int64_t stored_uptime_ref; // esp_timer_get_time() at that epoch + + int64_t now_uptime = esp_timer_get_time() / 1000000LL; + + if (stored_epoch_ref > 100000 && stored_uptime_ref > 0) { + return stored_epoch_ref + (now_uptime - stored_uptime_ref); + } + + return now_uptime; // absolute fallback } int64_t get_CurrentUnixMs() { @@ -504,13 +555,13 @@ bool is_TimeToReadSensor(size_t config_id) { SensorConfig_s& p = sensor_configs[config_id]; - ESP_LOGI(TAG, "check is_TimeToReadSensor: %s", p.sensor_name); + ESP_LOGI(TAG, "check %s", p.sensor_name); if (!p.is_active) { ESP_LOGE(TAG, "Sensor is inactive!"); return false; } - + ESP_LOGI(TAG, " %lld <= %lld ", p.next_sensor_read, get_CurrentUnix()); return (p.next_sensor_read <= get_CurrentUnix()); } diff --git a/client_sensor/main/ClientSensor.h b/client_sensor/main/ClientSensor.h index 4a03fa1..9c2ae78 100644 --- a/client_sensor/main/ClientSensor.h +++ b/client_sensor/main/ClientSensor.h @@ -34,7 +34,8 @@ void init_EspNow(); // ---------------------------------------------------------------------------- // Time handling // ---------------------------------------------------------------------------- - +void save_time_reference(int64_t epoch, int64_t uptime); +void load_time_reference(int64_t *epoch, int64_t *uptime); int64_t get_CurrentUnix(); int64_t get_CurrentUnixMs(); bool request_TimeSync(uint32_t timeout_ms = 3000); diff --git a/client_sensor/main/main.cpp b/client_sensor/main/main.cpp index 937362a..ab8b530 100644 --- a/client_sensor/main/main.cpp +++ b/client_sensor/main/main.cpp @@ -14,6 +14,10 @@ extern "C" esp_err_t esp_base_mac_addr_set(const uint8_t mac[6]); RTC_DATA_ATTR uint32_t fake_value_to_send = 0; +// save time over power loss +int64_t stored_epoch_ref = 0; +int64_t stored_uptime_ref = 0; + // ---------------------------------------------------------------------------- // Sensor task loop // ---------------------------------------------------------------------------- @@ -53,6 +57,8 @@ void sensor_loop(void*) { // allow other tasks to run vTaskDelay(pdMS_TO_TICKS(100)); + + ESP_LOGI(TAG, "\n\n"); } } @@ -69,6 +75,10 @@ extern "C" void app_main(void) { init_WiFi(); init_EspNow(); + // load persisted values from NVS + load_time_reference(&stored_epoch_ref, &stored_uptime_ref); + + ESP_LOGI(TAG, "Requesting time sync..."); if (request_TimeSync()) ESP_LOGI(TAG, "done"); else ESP_LOGE(TAG, "failed (timeout)");