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.gzCleanup a bit
client_sensor/client_sensor.ino | 311 +++++++++++++++++++++------------------- 1 file changed, 160 insertions(+), 151 deletions(-) diff --git a/client_sensor/client_sensor.ino b/client_sensor/client_sensor.ino index 6ae5211..37709f7 100644 --- a/client_sensor/client_sensor.ino +++ b/client_sensor/client_sensor.ino @@ -15,6 +15,18 @@ volatile bool send_ack_process_complete = false; const uint32_t min_sleep_time = 60000; + +// ---------------------------------------------------------------------------- +// Helper +// ---------------------------------------------------------------------------- +void print_Mac(const uint8_t* mac) { + for (size_t i = 0; i < 6; i++) { + if (i > 0) DBG_PRINT(":"); + DBG_PRINTF("%02X", mac[i]); + } + DBG_PRINTLN(); +} + // ---------------------------------------------------------------------------- // WiFi handling // ---------------------------------------------------------------------------- @@ -88,6 +100,7 @@ Preferences prefs; bool load_SensorConfigs() { DBG_PRINTLN("Loading sensor configs from NVS..."); + prefs.begin("sensors", true); size_t stored_size = prefs.getBytesLength("configs"); DBG_PRINTF("Stored size: %u bytes\n", (unsigned)stored_size); @@ -96,23 +109,25 @@ bool load_SensorConfigs() { prefs.getBytes("configs", sensor_configs, sizeof(sensor_configs)); ok = true; DBG_PRINTLN("Config read successfully."); - } else { - DBG_PRINTLN("No valid stored config found."); - } + } else DBG_PRINTLN("No valid stored config found."); prefs.end(); + return ok; } void save_SensorConfigs() { DBG_PRINTLN("Saving sensor configs to NVS..."); + prefs.begin("sensors", false); prefs.putBytes("configs", sensor_configs, sizeof(sensor_configs)); prefs.end(); + DBG_PRINTLN("Save complete."); } void restore_SensorConfigs() { - DBG_PRINTLN("Trying to load old config!"); + DBG_PRINTLN("Trying to load old config!"); + bool restored = load_SensorConfigs(); if (restored) { DBG_PRINTLN("Sensor configs restored from flash."); @@ -186,11 +201,10 @@ void on_DataSent(const wifi_tx_info_t* info, esp_now_send_status_t status) { if (i < 5) DBG_PRINT(":"); } - if (status == ESP_NOW_SEND_SUCCESS) { + if (status == ESP_NOW_SEND_SUCCESS) DBG_PRINTLN(" queued successfully (waiting for ACK)"); - } else { + else DBG_PRINTLN(" failed to queue!"); - } } void on_DataRecv(const esp_now_recv_info *info, const uint8_t *data, int len) { @@ -294,14 +308,14 @@ void init_EspNow() { bool send_Message(const uint8_t* peer, const char* message) { if (!esp_now_is_peer_exist(peer)) { - DBG_PRINTLN("ERROR: peer doese not exist!"); - return false; + DBG_PRINTLN("ERROR: peer doese not exist!"); + return false; } esp_err_t result = esp_now_send(peer, (uint8_t*)message, strlen(message)); return result == ESP_OK; } -bool send_And_wait_Ack(const uint8_t* peer, const char* message, uint32_t timeout_ms = 32000) { +bool send_And_wait_Ack(const uint8_t* peer, const char* message, uint32_t timeout_ms = 5000) { send_ack_process_complete = false; ack_received = false; @@ -347,8 +361,8 @@ void sleep_UntilNextSend() { } } else { uint32_t delta_ms = (p.delay_ms > (ms_now - last_sent_array[i])) - ? (p.delay_ms - (ms_now - last_sent_array[i])) - : 0; + ? (p.delay_ms - (ms_now - last_sent_array[i])) + : 0; if (delta_ms < min_delay_ms) min_delay_ms = delta_ms; } } @@ -375,12 +389,10 @@ void sleep_UntilNextSend() { // Request sensor config from server via ESP-NOW // ---------------------------------------------------------------------------- RTC_DATA_ATTR bool all_init_configs_received = false; -RTC_DATA_ATTR bool init_configs_received[num_sensor_configs] = { false }; -volatile bool waiting_for_config = false; volatile bool sensor_config_received = false; char sensor_config_message[256] = {0}; -void on_DataRecvSensorConfig_s(const esp_now_recv_info* info, const uint8_t* data, int len) { +void on_DataRecvSensorConfig(const esp_now_recv_info* info, const uint8_t* data, int len) { if (!info || !data || len <= 0) return; if (memcmp(info->src_addr, PEER_SERVER, 6) != 0) return; @@ -400,7 +412,7 @@ bool request_SensorConfig(const char* sensor_name) { sensor_config_received = false; memset(sensor_config_message, 0, sizeof(sensor_config_message)); - esp_now_register_recv_cb(on_DataRecvSensorConfig_s); + esp_now_register_recv_cb(on_DataRecvSensorConfig); char msg[64]; snprintf(msg, sizeof(msg), "get_config:%s", sensor_name); @@ -446,24 +458,23 @@ bool request_SensorConfig(const char* sensor_name) { if (count_token < 9) { - DBG_PRINTLN("Incomplete config data"); - return false; + DBG_PRINTLN("Incomplete config data"); + return false; } - // find target config by name SensorConfig_s *cfg = NULL; size_t config_id = 0; for (size_t i = 0; i < sizeof(sensor_configs) / sizeof(sensor_configs[0]); i++) { - if (strcmp(sensor_configs[i].sensor_name, tokens[0]) == 0) { - config_id = i; - cfg = &sensor_configs[i]; - break; - } + if (strcmp(sensor_configs[i].sensor_name, tokens[0]) == 0) { + config_id = i; + cfg = &sensor_configs[i]; + break; + } } if (!cfg) { - DBG_PRINTF("Unknown sensor name in config: %s\n", tokens[0]); - return false; + DBG_PRINTF("Unknown sensor name in config: %s\n", tokens[0]); + return false; } // basic fields @@ -483,182 +494,180 @@ bool request_SensorConfig(const char* sensor_name) { // times cfg->time_count = 0; if (cfg->use_time && count_token > 9 && strncmp(tokens[9], "times=", 6) == 0) { - char *time_str = tokens[9] + 6; - char *time_tok = strtok(time_str, "|"); - while (time_tok && cfg->time_count < 8) { - cfg->times[cfg->time_count++] = (uint16_t)atoi(time_tok); - time_tok = strtok(NULL, "|"); - } + char *time_str = tokens[9] + 6; + char *time_tok = strtok(time_str, "|"); + while (time_tok && cfg->time_count < 8) { + cfg->times[cfg->time_count++] = (uint16_t)atoi(time_tok); + time_tok = strtok(NULL, "|"); + } } - init_configs_received[config_id] = true; config_request_attempts = 0; return true; } +void process_PendingSensorConfigs() { + config_request_attempts = 0; + DBG_PRINTF("NEW CONFIGS: %d\n", g_pending_sensor_configs_count); -// ---------------------------------------------------------------------------- -// Helper -// ---------------------------------------------------------------------------- -void print_Mac(const uint8_t* mac) { - for (size_t i = 0; i < 6; i++) { - if (i > 0) DBG_PRINT(":"); - DBG_PRINTF("%02X", mac[i]); + size_t config_id = 0; + bool save_new_configs = false; + while (config_id < g_pending_sensor_configs_count) { + DBG_PRINTF("SENSOR: %s\n", g_pending_sensor_configs[config_id]); + + bool success = false; + for (config_request_attempts = 0; + config_request_attempts < config_request_attempts_max; + config_request_attempts++) { + + DBG_PRINTF("Requesting config attempt %u...\n", config_request_attempts + 1); + if (request_SensorConfig(g_pending_sensor_configs[config_id])) { + success = true; + break; + } + delay(2000); + } + + if (success) { + DBG_PRINTF("Config %s processed successfully, removing.\n", + g_pending_sensor_configs[config_id]); + if (config_id >= g_pending_sensor_configs_count) return; + for (size_t i = config_id; i < g_pending_sensor_configs_count - 1; i++) + strcpy(g_pending_sensor_configs[i], g_pending_sensor_configs[i + 1]); + g_pending_sensor_configs_count--; + save_new_configs = true; + } else { + DBG_PRINTLN("Config request failed repeatedly, aborting loop."); + break; + } } - DBG_PRINTLN(); -} -// ---------------------------------------------------------------------------- -// Setup -// ---------------------------------------------------------------------------- -void setup() { - DBG_BEGIN(); - setup_Timezone(); - init_WiFi(); - init_EspNow(); + if (save_new_configs) save_SensorConfigs(); +} - DBG_PRINTLN("Requesting time sync..."); - if (request_TimeSync()) DBG_PRINTLN("done"); - else DBG_PRINTLN("failed (timeout)"); +void get_AllSensorConfigs() { + g_pending_sensor_configs_count = 0; - restore_SensorConfigs(); + for (size_t i = 0; i < num_sensor_configs; ++i) { + strncpy( + g_pending_sensor_configs[g_pending_sensor_configs_count], + sensor_configs[i].sensor_name, + sizeof(g_pending_sensor_configs[0]) - 1 + ); - //all_init_configs_received = false; - //waiting_for_config = false; - DBG_PRINTF("----------------------\n"); + g_pending_sensor_configs[g_pending_sensor_configs_count][sizeof(g_pending_sensor_configs[0]) - 1] = '\0'; - config_request_attempts = 0; + ++g_pending_sensor_configs_count; + } - if (!all_init_configs_received) { - if (!waiting_for_config) { - waiting_for_config = true; - for (size_t config_id = 0; config_id < num_sensor_configs; config_id++) { - DBG_PRINTF("SENSOR: %s\n", sensor_configs[config_id].sensor_name); - if (init_configs_received[config_id]) { - DBG_PRINTLN("INIT CONFIG ALREADY RECEIVED!"); - continue; - } - for (config_request_attempts = 0; - config_request_attempts < config_request_attempts_max; config_request_attempts++) { - DBG_PRINTF("Requesting config attempt %u...\n", config_request_attempts + 1); - if (request_SensorConfig(sensor_configs[config_id].sensor_name)) break; - delay(2000); - } - // no need to go on testing if we already failed 3 times - if (config_request_attempts >= config_request_attempts_max) { - break; - } else config_request_attempts = 0; - } + process_PendingSensorConfigs(); + if (g_pending_sensor_configs_count == 0) all_init_configs_received = true; - waiting_for_config = false; - save_SensorConfigs(); - } - } - DBG_PRINTF("----------------------\n"); } // ---------------------------------------------------------------------------- -// Loop +// Send Data to peers // ---------------------------------------------------------------------------- -void loop() { - ensure_Peers(); - - DBG_PRINTF("## Unix time: %llu\n", (unsigned long long)get_CurrentUnixMs() / 1000); - for (size_t i = 0; i < num_sensor_configs; i++) { - uint64_t ms_now = get_CurrentUnixMs(); +void send_DataToPeer(size_t config_id, uint32_t value) { + uint64_t ms_now = get_CurrentUnixMs(); - SensorConfig_s& p = sensor_configs[i]; + SensorConfig_s& p = sensor_configs[config_id]; - DBG_PRINTF("SENSOR: %s\n", p.sensor_name); - printSensorConfig(p); - if (!p.is_active) { + DBG_PRINTF("SENSOR: %s\n", p.sensor_name); + printSensorConfig(p); + if (!p.is_active) { DBG_PRINTLN("Sensor is inactive!"); - continue; - } + return; + } - bool should_send = false; + bool should_send = false; - if (p.use_time) { + if (p.use_time) { uint16_t min_current = get_CurrentMinutes(); for (size_t j = 0; j < p.time_count; j++) { - if (min_current == p.times[j] && - ms_now - last_sent_array[i] > 60000) { - should_send = true; - break; - } + if (min_current == p.times[j] && + ms_now - last_sent_array[config_id] > 60000) { + should_send = true; + break; + } } - } else { - if (ms_now - last_sent_array[i] >= p.delay_ms) should_send = true; - } + } else { + if (ms_now - last_sent_array[config_id] >= p.delay_ms) should_send = true; + } - if (should_send) { + if (should_send) { char message[32]; - snprintf(message, sizeof(message), "%s:%u", p.sensor_name, value_to_send); + snprintf(message, sizeof(message), "%s:%u", p.sensor_name, value); DBG_PRINT("Sending to peer: "); print_Mac(p.pump_mac); send_ack_process_complete = false; if (!send_And_wait_Ack(p.pump_mac, message)) { - DBG_PRINTLN("Delivery failed or peer offline!"); - send_ack_process_complete = true; + DBG_PRINTLN("Delivery failed or peer offline!"); + send_ack_process_complete = true; } else { - last_sent_array[i] = get_CurrentUnixMs(); - value_to_send++; + last_sent_array[config_id] = get_CurrentUnixMs(); + value++; } - while (!send_ack_process_complete) { - delay(100); - }; + while (!send_ack_process_complete) delay(100); DBG_PRINT("Sending to peer: "); print_Mac(PEER_SERVER); send_ack_process_complete = false; if (!send_And_wait_Ack(PEER_SERVER, message)) { - DBG_PRINTLN("Failed to get ack from server!"); - send_ack_process_complete = true; + DBG_PRINTLN("Failed to get ack from server!"); + send_ack_process_complete = true; } - while (!send_ack_process_complete) { - delay(100); - }; + while (!send_ack_process_complete) delay(100); + delay(5000); - } } +} - config_request_attempts = 0; - DBG_PRINTF("NEW CONFIGS: %d\n", g_pending_sensor_configs_count); +// ---------------------------------------------------------------------------- +// Setup +// ---------------------------------------------------------------------------- +void setup() { + DBG_BEGIN(); + setup_Timezone(); + init_WiFi(); + init_EspNow(); - size_t config_id = 0; - while (config_id < g_pending_sensor_configs_count) { - DBG_PRINTF("SENSOR: %s\n", g_pending_sensor_configs[config_id]); + DBG_PRINTLN("Requesting time sync..."); + if (request_TimeSync()) DBG_PRINTLN("done"); + else DBG_PRINTLN("failed (timeout)"); + + restore_SensorConfigs(); + + //all_init_configs_received = false; + DBG_PRINTF("----------------------\n"); + + // Add all known configs to an array so we can request thoose from server + if (!all_init_configs_received) + get_AllSensorConfigs(); + + DBG_PRINTF("----------------------\n"); +} + +// ---------------------------------------------------------------------------- +// Loop +// ---------------------------------------------------------------------------- + +void loop() { + ensure_Peers(); + + DBG_PRINTF("## Unix time: %llu\n", (unsigned long long)get_CurrentUnixMs() / 1000); + for (size_t config_id = 0; config_id < num_sensor_configs; config_id++) { + send_DataToPeer(config_id, value_to_send); + } + + if (g_pending_sensor_configs_count > 0) + process_PendingSensorConfigs(); - bool success = false; - for (config_request_attempts = 0; - config_request_attempts < config_request_attempts_max; - config_request_attempts++) { - DBG_PRINTF("Requesting config attempt %u...\n", config_request_attempts + 1); - if (request_SensorConfig(g_pending_sensor_configs[config_id])) { - success = true; - break; - } - delay(2000); - } - - if (success) { - DBG_PRINTF("Config %s processed successfully, removing.\n", g_pending_sensor_configs[config_id]); - if (config_id >= g_pending_sensor_configs_count) return; - for (size_t i = config_id; i < g_pending_sensor_configs_count - 1; i++) - strcpy(g_pending_sensor_configs[i], g_pending_sensor_configs[i + 1]); - g_pending_sensor_configs_count--; - } else { - DBG_PRINTLN("Config request failed repeatedly, aborting loop."); - break; - } - } - - /* * Tell server some infos * how long am i gonna sleep, which configurations have i updated