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.gzinit
client_pump/ClientPump.cpp | 168 +++++++++++++++++++++++++++++++++++++++++++++ client_pump/ClientPump.h | 61 ++++++++++++++++ client_pump/globals.cpp | 1 + client_pump/globals.h | 1 + 4 files changed, 231 insertions(+) diff --git a/client_pump/ClientPump.cpp b/client_pump/ClientPump.cpp new file mode 100644 index 0000000..81307f9 --- /dev/null +++ b/client_pump/ClientPump.cpp @@ -0,0 +1,168 @@ +#include "ClientPump.h" + +#include <WiFi.h> +#include <esp_wifi.h> +#include <esp_now.h> +#include <esp_sleep.h> +#include <sys/time.h> + + + +// ---------------------------------------------------------------------------- +// Time handling +// ---------------------------------------------------------------------------- + +int64_t get_CurrentUnix() { + return (int64_t)time(nullptr); +} + +void setup_Timezone() { + setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1); + tzset(); +} + +void set_LocalTime(long long unix_now) { + struct timeval tv; + tv.tv_sec = unix_now; + tv.tv_usec = 0; + + settimeofday(&tv, nullptr); +} + +// ---------------------------------------------------------------------------- +// WiFi handling +// ---------------------------------------------------------------------------- +int32_t get_WiFiChannel() { + DBG_PRINTLN(ssid); + int32_t n = WiFi.scanNetworks(); + if (n <= 0) return 0; + for (uint8_t i = 0; i < n; i++) { + if (!strcmp(ssid, WiFi.SSID(i).c_str())) return WiFi.channel(i); + } + return 0; +} + +void init_WiFi() { + WiFi.mode(WIFI_MODE_STA); + int32_t channel = get_WiFiChannel(); + if (channel > 0) { + esp_wifi_set_promiscuous(true); + esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE); + esp_wifi_set_promiscuous(false); + } +} + + +// ---------------------------------------------------------------------------- +// ESP-NOW handling +// ---------------------------------------------------------------------------- + +void on_DataRecv(const esp_now_recv_info *info, const uint8_t *data, int len) { + if (!info || !data || len <= 0) return; + if (memcmp(info->src_addr, PEER_SENSOR, 6) != 0) return; + + received_starting_message = true; + + PumpConfig_s pump_config; + char msg[64]; + long long unix_now = 0; + memcpy(msg, data, len); + msg[len] = '\0'; + + DBG_PRINTF("Received from server: %s\n", msg); + + if (strncmp(msg, "p:", 2) == 0) { + + int n = sscanf(msg, "p:%lld:%31[^:]:%d:%d:%lld", + &unix_now, + pump_config.pump_name, + &pump_config.pumping_delay_sec, + &pump_config.pumping_duration, + &pump_config.next_message_unix); + + if (n == 5) { + for (size_t i = 0; i < PUMP_COUNT; i++) { + if (strcmp(pump_configs[i].pump_name, pump_config.pump_name) != 0) + continue; + + // make sure we keep old data before memcpy + pump_config.pumping_started_at_unix = pump_configs[i].pumping_started_at_unix; + pump_config.pumping_status = pump_configs[i].pumping_status; + + + memcpy(&pump_configs[i], &pump_config, sizeof(PumpConfig_s)); + next_message_unix = pump_config.next_message_unix; + + DBG_PRINTF("unix_now: %lld\n", unix_now); + DBG_PRINTF("pump_name: %s\n", pump_configs[i].pump_name); + DBG_PRINTF("pumping_delay_sec: %d\n", pump_configs[i].pumping_delay_sec); + DBG_PRINTF("pumping_duration: %d\n", pump_configs[i].pumping_duration); + DBG_PRINTF("next_message_unix: %lld\n", pump_configs[i].next_message_unix); + + if (pump_configs[i].pumping_duration > 0) + pump_configs[i].pumping_status = START; + else + received_starting_message = false; + + set_LocalTime(unix_now); + return; + } + } else { + DBG_PRINTLN("Failed to parse message"); + } + } + received_starting_message = false; +} + + +void init_EspNow() { + if (esp_now_init() != ESP_OK) { + DBG_PRINTLN("ESP NOW init failed"); + while (true); + } + esp_now_register_recv_cb(on_DataRecv); +} + + +// ---------------------------------------------------------------------------- +// Deep sleep scheduler +// ---------------------------------------------------------------------------- + +void sleep_UntilNextSend(int64_t next_read) { + + DBG_PRINTF("Next read: %lld\n", next_read); + + int64_t now_sec = get_CurrentUnix(); + + int64_t delta_sec = next_read - now_sec; + if (delta_sec <= 0) delta_sec = 0; + + uint32_t min_delay_ms = delta_sec > UINT32_MAX / 1000 + ? UINT32_MAX + : (uint32_t)(delta_sec * 1000); + + + // Prevent sleeping if next send is within g_min_sleep_time + if (min_delay_ms < g_min_sleep_time) { + DBG_PRINTF("Delaying for %u ms (no deep sleep)\n", min_delay_ms); + DBG_PRINTF("######################\n\n"); + if (!received_starting_message) + delay(min_delay_ms); + return; + } + + uint32_t prep_time_ms = g_setup_duration + g_wakeup_earlier_pump; + uint32_t sleep_time_ms = (min_delay_ms > prep_time_ms) + ? (min_delay_ms - prep_time_ms) + : 0; + + + esp_sleep_enable_timer_wakeup((uint64_t)sleep_time_ms * 1000ULL); + if (!received_starting_message) { + DBG_PRINTF("Sleeping for %u ms (setup margin: %u ms)\n", + sleep_time_ms, prep_time_ms); + DBG_PRINTF("######################\n\n"); + esp_deep_sleep_start(); + } +} + diff --git a/client_pump/ClientPump.h b/client_pump/ClientPump.h new file mode 100644 index 0000000..4482929 --- /dev/null +++ b/client_pump/ClientPump.h @@ -0,0 +1,61 @@ +#ifndef CLIENTPUMP_H +#define CLIENTPUMP_H + + +#include "globals.h" +#include "secrets.h" + +#include <Arduino.h> + + +extern long long next_message_unix; +extern bool received_starting_message; + +enum PumpSatatus_e { + INACTIVE, + START, + RUNNING, + FINISHED +}; + +struct PumpConfig_s { + char pump_name[32]; + int pumping_delay_sec; + int pumping_duration; + long long next_message_unix; + long long pumping_started_at_unix; + PumpSatatus_e pumping_status; +}; + +#define PUMP_COUNT 2 +extern PumpConfig_s pump_configs[PUMP_COUNT]; + +// ---------------------------------------------------------------------------- +// Time handling +// ---------------------------------------------------------------------------- + +int64_t get_CurrentUnix(); +void setup_Timezone(); + +// ---------------------------------------------------------------------------- +// WiFi handling +// ---------------------------------------------------------------------------- + +void init_WiFi(); + + +// ---------------------------------------------------------------------------- +// ESP-NOW handling +// ---------------------------------------------------------------------------- + +void init_EspNow(); + + +// ---------------------------------------------------------------------------- +// Deep sleep scheduler +// ---------------------------------------------------------------------------- + +void sleep_UntilNextSend(int64_t next_read); + + +#endif diff --git a/client_pump/globals.cpp b/client_pump/globals.cpp new file mode 120000 index 0000000..3fef46a --- /dev/null +++ b/client_pump/globals.cpp @@ -0,0 +1 @@ +../globals.cpp \ No newline at end of file diff --git a/client_pump/globals.h b/client_pump/globals.h new file mode 120000 index 0000000..caa372d --- /dev/null +++ b/client_pump/globals.h @@ -0,0 +1 @@ +../globals.h \ No newline at end of file