From 34c8bea77f12928b2182fff93fce68b1dd7228b7 Mon Sep 17 00:00:00 2001 From: agessaman Date: Mon, 8 Dec 2025 19:49:19 -0800 Subject: [PATCH] Add WiFi power save mode configuration to CommonCLI and MQTTBridge. Update preferences structure to include power save settings and implement command handling for adjusting power save modes (none, min, max). Enhance MQTTBridge to apply power save settings on WiFi connection and enable auto-reconnect functionality. --- src/helpers/CommonCLI.cpp | 56 +++++++++++++++++++++++++++++- src/helpers/CommonCLI.h | 2 ++ src/helpers/bridges/MQTTBridge.cpp | 47 ++++++++++++++++++++----- 3 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index ea82b4ff..fb8412f7 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -3,6 +3,10 @@ #include "TxtDataHelpers.h" #include "AdvertDataHelpers.h" #include +#ifdef ESP_PLATFORM +#include +#include +#endif #ifdef WITH_MQTT_BRIDGE #include "bridges/MQTTBridge.h" @@ -252,6 +256,7 @@ static void setMQTTPrefsDefaults(MQTTPrefs* prefs) { prefs->mqtt_status_interval = 300000; // 5 minutes default prefs->mqtt_analyzer_us_enabled = 1; // enabled by default prefs->mqtt_analyzer_eu_enabled = 1; // enabled by default + prefs->wifi_power_save = 0; // Default to WIFI_PS_MIN_MODEM (0=min) // String fields are already zero-initialized by memset } @@ -259,7 +264,8 @@ void CommonCLI::loadMQTTPrefs(FILESYSTEM* fs) { // Initialize with defaults first setMQTTPrefsDefaults(&_mqtt_prefs); - if (fs->exists("/mqtt_prefs")) { + bool file_existed = fs->exists("/mqtt_prefs"); + if (file_existed) { // Load from separate MQTT prefs file #if defined(RP2040_PLATFORM) File file = fs->open("/mqtt_prefs", "r"); @@ -359,6 +365,7 @@ void CommonCLI::syncMQTTPrefsToNodePrefs() { _prefs->mqtt_status_interval = _mqtt_prefs.mqtt_status_interval; StrHelper::strncpy(_prefs->wifi_ssid, _mqtt_prefs.wifi_ssid, sizeof(_prefs->wifi_ssid)); StrHelper::strncpy(_prefs->wifi_password, _mqtt_prefs.wifi_password, sizeof(_prefs->wifi_password)); + _prefs->wifi_power_save = _mqtt_prefs.wifi_power_save; StrHelper::strncpy(_prefs->timezone_string, _mqtt_prefs.timezone_string, sizeof(_prefs->timezone_string)); _prefs->timezone_offset = _mqtt_prefs.timezone_offset; StrHelper::strncpy(_prefs->mqtt_server, _mqtt_prefs.mqtt_server, sizeof(_prefs->mqtt_server)); @@ -383,6 +390,7 @@ void CommonCLI::syncNodePrefsToMQTTPrefs() { _mqtt_prefs.mqtt_status_interval = _prefs->mqtt_status_interval; StrHelper::strncpy(_mqtt_prefs.wifi_ssid, _prefs->wifi_ssid, sizeof(_mqtt_prefs.wifi_ssid)); StrHelper::strncpy(_mqtt_prefs.wifi_password, _prefs->wifi_password, sizeof(_mqtt_prefs.wifi_password)); + _mqtt_prefs.wifi_power_save = _prefs->wifi_power_save; StrHelper::strncpy(_mqtt_prefs.timezone_string, _prefs->timezone_string, sizeof(_mqtt_prefs.timezone_string)); _mqtt_prefs.timezone_offset = _prefs->timezone_offset; StrHelper::strncpy(_mqtt_prefs.mqtt_server, _prefs->mqtt_server, sizeof(_mqtt_prefs.mqtt_server)); @@ -606,6 +614,10 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch sprintf(reply, "> %s", _prefs->wifi_ssid); } else if (memcmp(config, "wifi.pwd", 8) == 0) { sprintf(reply, "> %s", _prefs->wifi_password); + } else if (memcmp(config, "wifi.powersave", 14) == 0) { + uint8_t ps = _prefs->wifi_power_save; + const char* ps_name = (ps == 1) ? "none" : (ps == 2) ? "max" : "min"; + sprintf(reply, "> %s", ps_name); } else if (memcmp(config, "timezone", 8) == 0) { sprintf(reply, "> %s", _prefs->timezone_string); } else if (memcmp(config, "timezone.offset", 15) == 0) { @@ -870,6 +882,48 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch StrHelper::strncpy(_prefs->wifi_password, &config[9], sizeof(_prefs->wifi_password)); savePrefs(); strcpy(reply, "OK"); + } else if (memcmp(config, "wifi.powersave ", 15) == 0) { + const char* value = &config[15]; + uint8_t ps_value; + bool valid = false; + if (memcmp(value, "min", 3) == 0 && (value[3] == 0 || value[3] == ' ')) { + ps_value = 0; + valid = true; + } else if (memcmp(value, "none", 4) == 0 && (value[4] == 0 || value[4] == ' ')) { + ps_value = 1; + valid = true; + } else if (memcmp(value, "max", 3) == 0 && (value[3] == 0 || value[3] == ' ')) { + ps_value = 2; + valid = true; + } + + if (!valid) { + strcpy(reply, "Error: must be none, min, or max"); + } else { + _prefs->wifi_power_save = ps_value; + savePrefs(); + + // Apply immediately if WiFi is connected + #ifdef ESP_PLATFORM + if (WiFi.status() == WL_CONNECTED) { + wifi_ps_type_t ps_mode = (ps_value == 1) ? WIFI_PS_NONE : + (ps_value == 2) ? WIFI_PS_MAX_MODEM : WIFI_PS_MIN_MODEM; + esp_err_t ps_result = esp_wifi_set_ps(ps_mode); + if (ps_result == ESP_OK) { + const char* ps_name = (ps_value == 1) ? "none" : (ps_value == 2) ? "max" : "min"; + sprintf(reply, "OK - power save set to %s", ps_name); + } else { + sprintf(reply, "OK - saved, but failed to apply: %d", ps_result); + } + } else { + const char* ps_name = (ps_value == 1) ? "none" : (ps_value == 2) ? "max" : "min"; + sprintf(reply, "OK - saved as %s (will apply on next WiFi connection)", ps_name); + } + #else + const char* ps_name = (ps_value == 1) ? "none" : (ps_value == 2) ? "max" : "min"; + sprintf(reply, "OK - saved as %s", ps_name); + #endif + } } else if (memcmp(config, "timezone ", 9) == 0) { StrHelper::strncpy(_prefs->timezone_string, &config[9], sizeof(_prefs->timezone_string)); savePrefs(); diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 6bf452c3..c8fbc83b 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -62,6 +62,7 @@ struct NodePrefs { // persisted to file // WiFi settings char wifi_ssid[32]; // WiFi SSID char wifi_password[64]; // WiFi password + uint8_t wifi_power_save; // WiFi power save mode: 0=min, 1=none, 2=max (default: 0=min) // Timezone settings char timezone_string[32]; // Timezone string (e.g., "America/Los_Angeles") @@ -95,6 +96,7 @@ struct MQTTPrefs { // WiFi settings char wifi_ssid[32]; // WiFi SSID char wifi_password[64]; // WiFi password + uint8_t wifi_power_save; // WiFi power save mode: 0=min, 1=none, 2=max (default: 0=min) // Timezone settings char timezone_string[32]; // Timezone string (e.g., "America/Los_Angeles") diff --git a/src/helpers/bridges/MQTTBridge.cpp b/src/helpers/bridges/MQTTBridge.cpp index cf9b1625..7d6d5da0 100644 --- a/src/helpers/bridges/MQTTBridge.cpp +++ b/src/helpers/bridges/MQTTBridge.cpp @@ -176,6 +176,11 @@ void MQTTBridge::begin() { // Initialize WiFi MQTT_DEBUG_PRINTLN("Starting WiFi..."); WiFi.mode(WIFI_STA); + + // Enable automatic reconnection - ESP32 will handle reconnection automatically + WiFi.setAutoReconnect(true); + WiFi.setAutoConnect(true); + WiFi.begin(_prefs->wifi_ssid, _prefs->wifi_password); // Wait for WiFi connection @@ -191,12 +196,24 @@ void MQTTBridge::begin() { // Configure WiFi power management for efficient operation #ifdef ESP_PLATFORM - // Enable WiFi power save mode to reduce power consumption - esp_err_t ps_result = esp_wifi_set_ps(WIFI_PS_MIN_MODEM); - if (ps_result == ESP_OK) { - MQTT_DEBUG_PRINTLN("WiFi power save mode enabled"); + // Set WiFi power save mode from preferences (0=min, 1=none, 2=max) + wifi_ps_type_t ps_mode; + uint8_t ps_pref = _prefs->wifi_power_save; + if (ps_pref == 1) { + ps_mode = WIFI_PS_NONE; + } else if (ps_pref == 2) { + ps_mode = WIFI_PS_MAX_MODEM; } else { - MQTT_DEBUG_PRINTLN("Failed to enable WiFi power save mode: %d", ps_result); + ps_mode = WIFI_PS_MIN_MODEM; // Default to min (0) if invalid or unset + } + + esp_err_t ps_result = esp_wifi_set_ps(ps_mode); + if (ps_result == ESP_OK) { + const char* ps_name = (ps_mode == WIFI_PS_NONE) ? "none" : + (ps_mode == WIFI_PS_MAX_MODEM) ? "max" : "min"; + MQTT_DEBUG_PRINTLN("WiFi power save mode set to: %s", ps_name); + } else { + MQTT_DEBUG_PRINTLN("Failed to set WiFi power save mode: %d", ps_result); } // Set WiFi TX power - use build flag if defined, otherwise default to 11dBm @@ -212,8 +229,9 @@ void MQTTBridge::begin() { // Sync time with NTP syncTimeWithNTP(); } else { - MQTT_DEBUG_PRINTLN("WiFi connection failed!"); - return; + MQTT_DEBUG_PRINTLN("WiFi connection failed! Auto-reconnect enabled, will retry automatically"); + // Don't return here - allow MQTT bridge to initialize even if WiFi isn't connected yet + // Auto-reconnect will handle reconnection in the background } // Initialize PsychicMqttClient @@ -374,6 +392,19 @@ bool MQTTBridge::isReady() const { void MQTTBridge::loop() { if (!_initialized) return; + // WiFi auto-reconnect is handled by ESP32, just check status periodically + // If WiFi reconnects, MQTT clients will automatically reconnect via their own logic + static unsigned long last_wifi_check = 0; + if (millis() - last_wifi_check > 30000) { // Check every 30 seconds + if (WiFi.status() == WL_CONNECTED) { + // WiFi is connected - MQTT reconnection logic will handle broker connections + } else { + // WiFi disconnected - auto-reconnect is enabled, will reconnect automatically + // No action needed, ESP32 handles it + } + last_wifi_check = millis(); + } + // Maintain broker connections connectToBrokers(); @@ -386,7 +417,7 @@ void MQTTBridge::loop() { // Periodic configuration check (throttled to avoid spam) checkConfigurationMismatch(); - // Periodic NTP sync (every hour) + // Periodic NTP sync (every hour) - only when connected if (WiFi.status() == WL_CONNECTED && millis() - _last_ntp_sync > 3600000) { syncTimeWithNTP(); }