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 time after power loss
client_sensor/main/ClientSensor.cpp | 116 ++++++++++++++++++++---------------- client_sensor/main/ClientSensor.h | 3 +- client_sensor/main/main.cpp | 44 +++++++++----- globals.cpp | 10 ++-- server/main/Server.cpp | 2 +- 5 files changed, 101 insertions(+), 74 deletions(-) diff --git a/client_sensor/main/ClientSensor.cpp b/client_sensor/main/ClientSensor.cpp index 8b16ef9..f342292 100644 --- a/client_sensor/main/ClientSensor.cpp +++ b/client_sensor/main/ClientSensor.cpp @@ -20,9 +20,6 @@ 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 @@ -241,6 +238,8 @@ void on_DataRecv(const esp_now_recv_info *info, const uint8_t *data, int len) { ESP_LOGI(TAG, "System time updated from server."); // Save epoch + uptime to NVS + int64_t stored_epoch_ref = 0; + int64_t stored_uptime_ref = 0; 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 @@ -493,21 +492,7 @@ int64_t get_CurrentUnix() { 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 + return tv.tv_sec; } int64_t get_CurrentUnixMs() { @@ -550,19 +535,17 @@ uint16_t get_CurrentMinutes() { // ---------------------------------------------------------------------------- -bool is_TimeToReadSensor(size_t config_id) { +bool is_TimeToReadSensor(const SensorConfig_s& cfg) { static const char *TAG = "is_TimeToReadSensor"; - SensorConfig_s& p = sensor_configs[config_id]; - - ESP_LOGI(TAG, "check %s", p.sensor_name); + ESP_LOGI(TAG, "check %s", cfg.sensor_name); - if (!p.is_active) { - ESP_LOGE(TAG, "Sensor is inactive!"); + if (!cfg.is_active) { + ESP_LOGW(TAG, "Sensor is inactive!"); return false; } - ESP_LOGI(TAG, " %lld <= %lld ", p.next_sensor_read, get_CurrentUnix()); - return (p.next_sensor_read <= get_CurrentUnix()); + ESP_LOGI(TAG, " %lld <= %lld ", cfg.next_sensor_read, get_CurrentUnix()); + return (cfg.next_sensor_read <= get_CurrentUnix()); } int64_t get_NextSensorReadFor(const char* sensor_name) { @@ -570,28 +553,28 @@ int64_t get_NextSensorReadFor(const char* sensor_name) { uint16_t min_current = get_CurrentMinutes(); for (size_t i = 0; i < SENSOR_CONFIG_COUNT; i++) { - SensorConfig_s &p = sensor_configs[i]; + SensorConfig_s &cfg = sensor_configs[i]; - if (!p.is_active) continue; - if (strcmp(p.sensor_name, sensor_name) != 0) continue; + if (!cfg.is_active) continue; + if (strcmp(cfg.sensor_name, sensor_name) != 0) continue; - int64_t last_read = p.last_sensor_read > 0 && p.last_sensor_read < unix_now - ? p.last_sensor_read + int64_t last_read = cfg.last_sensor_read > 0 && cfg.last_sensor_read < unix_now + ? cfg.last_sensor_read : unix_now; int64_t next_time = INT64_MAX; - if (p.use_time && p.time_count > 0) { + if (cfg.use_time && cfg.time_count > 0) { uint32_t best_delta_min = 24 * 60; - for (size_t j = 0; j < p.time_count; j++) { - int16_t delta = (int16_t)p.times[j] - (int16_t)min_current; + for (size_t j = 0; j < cfg.time_count; j++) { + int16_t delta = (int16_t)cfg.times[j] - (int16_t)min_current; if (delta <= 0) delta += 24 * 60; if ((uint32_t)delta < best_delta_min) best_delta_min = delta; } next_time = (unix_now - (unix_now % 60)) + (int64_t)best_delta_min * 60; - } else if (p.delay_ms > 0) { - next_time = last_read + (p.delay_ms / 1000); + } else if (cfg.delay_ms > 0) { + next_time = last_read + (cfg.delay_ms / 1000); } if (next_time != INT64_MAX) { @@ -606,12 +589,12 @@ int64_t get_NextSensorReadsUnixTime(const uint8_t* mac) { int64_t unix_next = INT64_MAX; for (size_t i = 0; i < SENSOR_CONFIG_COUNT; i++) { - SensorConfig_s &p = sensor_configs[i]; - if (!p.is_active) continue; - if (mac != nullptr && memcmp(mac, p.pump_mac, 6) != 0) continue; + SensorConfig_s &cfg = sensor_configs[i]; + if (!cfg.is_active) continue; + if (mac != nullptr && memcmp(mac, cfg.pump_mac, 6) != 0) continue; - int64_t next_time = get_NextSensorReadFor(p.sensor_name); + int64_t next_time = get_NextSensorReadFor(cfg.sensor_name); if (next_time > 0 && next_time < unix_next) unix_next = next_time; @@ -620,6 +603,17 @@ int64_t get_NextSensorReadsUnixTime(const uint8_t* mac) { return (unix_next == INT64_MAX) ? -1 : unix_next; } +void set_AllNextSensorReads() { + for (size_t i = 0; i < SENSOR_CONFIG_COUNT; i++) { + SensorConfig_s &cfg = sensor_configs[i]; + if (!cfg.is_active) continue; + cfg.next_sensor_read = get_NextSensorReadFor(cfg.sensor_name); + + ESP_LOGI("set_AllNextSensorReads", "next read updated: %lld", cfg.next_sensor_read); + } +} + + void sleep_UntilNextSend(int64_t next_read) { static const char *TAG = "sleep_UntilNextSend"; @@ -867,39 +861,55 @@ void get_AllSensorConfigs() { void send_DataToPumpAndServer(size_t config_id, uint32_t value, bool shall_pump) { static const char *TAG = "send_DataToPumpAndServer"; - SensorConfig_s& p = sensor_configs[config_id]; - ESP_LOGI(TAG, "%s", p.sensor_name); + SensorConfig_s& cfg = sensor_configs[config_id]; + ESP_LOGI(TAG, "%s", cfg.sensor_name); - int pumping_duration = shall_pump ? p.pumping_duration : 0; + int pumping_duration = shall_pump ? cfg.pumping_duration : 0; char message[64]; - ESP_LOGI(TAG, "Sending to Pump: "); printMac(TAG, p.pump_mac); + ESP_LOGI(TAG, "Sending to Pump: "); printMac(TAG, cfg.pump_mac); snprintf(message, sizeof(message), "p:%lld:%s:%d:%d:%lld", get_CurrentUnix(), - p.notification_name, - p.pumping_delay_sec, + cfg.notification_name, + cfg.pumping_delay_sec, pumping_duration, - get_NextSensorReadsUnixTime(p.pump_mac)); + get_NextSensorReadsUnixTime(cfg.pump_mac)); + // START MESSAGE PUMP bool reached_pump = false; - if (!send_AndWaitResponse(p.pump_mac, message)) { - ESP_LOGE(TAG, "Delivery failed or peer offline!"); + + // try three times.. + for (int attempt = 1; attempt <= 3; attempt++) { + if (send_AndWaitResponse(cfg.pump_mac, message)) { + reached_pump = true; + break; + } + + ESP_LOGW(TAG, "No response from Pump (attempt %d/3)", attempt); + + if (attempt < 3) + vTaskDelay(pdMS_TO_TICKS(5000)); + } + + if (!reached_pump) { + ESP_LOGE(TAG, "Pump did not respond after 3 attempts!"); send_response_process_complete = true; - } else reached_pump = true; + } + // END MESSAGE PUMP while (!send_response_process_complete) vTaskDelay(pdMS_TO_TICKS(100)); ESP_LOGI(TAG, "Sending to Server: "); printMac(TAG, PEER_SERVER); snprintf(message, sizeof(message), "%s:%lu:%lld:%d", - p.sensor_name, + cfg.sensor_name, value, - p.last_sensor_read, + cfg.last_sensor_read, reached_pump); send_response_process_complete = false; if (!send_AndWaitResponse(PEER_SERVER, message)) { - ESP_LOGE(TAG, "Failed to get response from server!"); + ESP_LOGE(TAG, "No response from server!"); send_response_process_complete = true; } while (!send_response_process_complete) diff --git a/client_sensor/main/ClientSensor.h b/client_sensor/main/ClientSensor.h index 9c2ae78..3df5116 100644 --- a/client_sensor/main/ClientSensor.h +++ b/client_sensor/main/ClientSensor.h @@ -47,6 +47,7 @@ void setup_Timezone(); int64_t get_NextSensorReadFor(const char* sensor_name); int64_t get_NextSensorReadsUnixTime(const uint8_t* mac = nullptr); void sleep_UntilNextSend(int64_t next_read); +void set_AllNextSensorReads(); // ---------------------------------------------------------------------------- // Request sensor config from server via ESP-NOW @@ -59,7 +60,7 @@ void process_PendingSensorConfigs(); // Send Data to peers // ---------------------------------------------------------------------------- -bool is_TimeToReadSensor(size_t config_id); +bool is_TimeToReadSensor(const SensorConfig_s& cfg); void send_DataToPumpAndServer(size_t config_id, uint32_t value, bool shall_pump); void send_NextSensorReadToPeer(const uint8_t* mac, int64_t unix_time); diff --git a/client_sensor/main/main.cpp b/client_sensor/main/main.cpp index ab8b530..208b98b 100644 --- a/client_sensor/main/main.cpp +++ b/client_sensor/main/main.cpp @@ -4,6 +4,8 @@ #include "freertos/task.h" #include "esp_log.h" #include "esp_timer.h" +#include <sys/time.h> + extern "C" esp_err_t esp_base_mac_addr_set(const uint8_t mac[6]); @@ -14,10 +16,6 @@ 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 // ---------------------------------------------------------------------------- @@ -27,17 +25,17 @@ void sensor_loop(void*) { while (true) { ESP_LOGI(TAG, "## Unix time: %lld", get_CurrentUnix()); for (size_t config_id = 0; config_id < SENSOR_CONFIG_COUNT; config_id++) { - SensorConfig_s& peer = sensor_configs[config_id]; - ESP_LOGI(TAG, "LOOP checking config: %s", peer.sensor_name); - print_SensorConfig(peer); + SensorConfig_s& cfg = sensor_configs[config_id]; + ESP_LOGI(TAG, "LOOP checking config: %s", cfg.sensor_name); + print_SensorConfig(cfg); - if (is_TimeToReadSensor(config_id)) { + if (is_TimeToReadSensor(cfg)) { ESP_LOGI(TAG, "ITS TIME FOR THIS SENSOR!"); uint32_t value_to_send = fake_value_to_send; // set last and next read times - peer.last_sensor_read = get_CurrentUnix(); - peer.next_sensor_read = get_NextSensorReadFor(peer.sensor_name); + cfg.last_sensor_read = get_CurrentUnix(); + cfg.next_sensor_read = get_NextSensorReadFor(cfg.sensor_name); // decide if pump should run bool shall_pump = fake_value_to_send % 2; @@ -62,6 +60,26 @@ void sensor_loop(void*) { } } +void restore_TimeBackup() { + // save time over power loss + int64_t stored_epoch_ref = 0; + int64_t stored_uptime_ref = 0; + // load persisted values from NVS + load_time_reference(&stored_epoch_ref, &stored_uptime_ref); + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t now_unix = tv.tv_sec; + int64_t now_uptime = esp_timer_get_time() / 1000000LL; + if (now_unix < stored_epoch_ref && stored_epoch_ref > 100000 && stored_uptime_ref > 0) { + int64_t reconstructed = stored_epoch_ref + (now_uptime - stored_uptime_ref); + struct timeval new_tv = { .tv_sec = reconstructed, .tv_usec = 0 }; + settimeofday(&new_tv, NULL); + ESP_LOGW("restore_TimeBackup", "System time restored from reference: %lld", get_CurrentUnix()); + ESP_LOGW("restore_TimeBackup", "Resetting next sensor reads!"); + set_AllNextSensorReads(); + } +} + // ---------------------------------------------------------------------------- // ESP-IDF entry point // ---------------------------------------------------------------------------- @@ -75,16 +93,14 @@ extern "C" void app_main(void) { init_WiFi(); init_EspNow(); - // load persisted values from NVS - load_time_reference(&stored_epoch_ref, &stored_uptime_ref); + restore_SensorConfigs(); + restore_TimeBackup(); ESP_LOGI(TAG, "Requesting time sync..."); if (request_TimeSync()) ESP_LOGI(TAG, "done"); else ESP_LOGE(TAG, "failed (timeout)"); - restore_SensorConfigs(); - ESP_LOGI(TAG, "----------------------"); if (!all_init_configs_received) diff --git a/globals.cpp b/globals.cpp index 59da482..7f44454 100644 --- a/globals.cpp +++ b/globals.cpp @@ -2,13 +2,13 @@ uint32_t g_setup_duration = 0; uint32_t g_wakeup_earlier_server = 20000; -uint32_t g_wakeup_earlier_sensor = 2000; -uint32_t g_wakeup_earlier_pump = 2000; +uint32_t g_wakeup_earlier_sensor = 2000; +uint32_t g_wakeup_earlier_pump = 8000; -SensorEntry_s g_buffer[BUFFER_SIZE]; +SensorEntry_s g_buffer[BUFFER_SIZE]; uint8_t g_buffer_count = 0; -char g_pending_sensor_configs[4][32] = {}; -uint8_t g_pending_sensor_configs_count = 0; +char g_pending_sensor_configs[4][32] = {}; +uint8_t g_pending_sensor_configs_count = 0; bool g_received_ok_from_server = false; diff --git a/server/main/Server.cpp b/server/main/Server.cpp index 7c7ca83..a9b5075 100644 --- a/server/main/Server.cpp +++ b/server/main/Server.cpp @@ -296,7 +296,7 @@ void sleep_UntilNextReceive() { if (next_connection_unix < now_sec) return; - ESP_LOGI(TAG, "Nex: %lld\nNow: %lld", next_connection_unix, now_sec); + ESP_LOGI(TAG, "Nex: %lld\tNow: %lld", next_connection_unix, now_sec); next_connection_unix = 0;