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(); }