From cf8ddebcc667138800bafc65239be49ec3222141 Mon Sep 17 00:00:00 2001 From: "RZ_MINIX\\rober" Date: Fri, 25 Jul 2025 20:09:39 -0700 Subject: [PATCH] Added WIFI auto-tune for EMP prevention --- main/App.cpp | 293 +++++++++++++++++++++------------------ main/Wifi.cpp | 375 ++++++++++++++++++++++++++++++++++++++------------ main/Wifi.h | 16 ++- 3 files changed, 462 insertions(+), 222 deletions(-) diff --git a/main/App.cpp b/main/App.cpp index 3f0861a..a117555 100644 --- a/main/App.cpp +++ b/main/App.cpp @@ -36,153 +36,176 @@ CommandProcessor * App::getCommandProcessor() void App::init() { - #pragma message(WH_VERSION) - ESP_LOGW(TAG, "Starting the app..."); - uint8_t mac[8]; - esp_read_mac(mac, ESP_MAC_WIFI_STA); - //Lets report all programmed parameters - ESP_LOGI(TAG, "mqtt_id: %s, wifi mac: %02x:%02x:%02x:%02x:%02x:%02x well_id: %u, group_id: %u", SETTINGS.mqtt.device_id, - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], SETTINGS.device.tata_id, SETTINGS.device.group_id); + #pragma message(WH_VERSION) + ESP_LOGW(TAG, "Starting the app..."); + uint8_t mac[8]; + esp_read_mac(mac, ESP_MAC_WIFI_STA); + //Lets report all programmed parameters + ESP_LOGI(TAG, "mqtt_id: %s, wifi mac: %02x:%02x:%02x:%02x:%02x:%02x well_id: %u, group_id: %u", SETTINGS.mqtt.device_id, + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], SETTINGS.device.tata_id, SETTINGS.device.group_id); - m_led = new Led(LED_PIN); - m_wifi = new Wifi(); + m_led = new Led(LED_PIN); + m_wifi = new Wifi(); + m_commandProcessor = new CommandProcessor(*this); + m_ble_service = new BleService(*this); + m_ble_service->start(); - m_commandProcessor = new CommandProcessor(*this); + bool needs_provision = true; + bool first_attempt = true; + bool connected = false; - m_ble_service = new BleService(*this); - m_ble_service->start(); + #if 0 + ESP_LOGI(TAG, "Scanning wifi networks..."); + int num_networks = WiFi.scanNetworks(false, false, false, 0); + for(int n = 0; n < num_networks; n++) + { + ESP_LOGI(TAG, "%s, %d", WiFi.SSID(n).c_str(), WiFi.RSSI(n)); + } + #endif - bool needs_provision = true; + // Main connection/provisioning cycle + while(!connected) + { + needs_provision = true; -#if 0 - ESP_LOGI(TAG, "Scanning wifi networks..."); + // Try WiFi connections (provisioned networks + fallback) + if(SETTINGS.wifi.num > 0 || !first_attempt) + { + if(!first_attempt) + { + ESP_LOGI(TAG, "Retrying WiFi connections after provisioning timeout..."); + m_wifi->pause(false); // Resume WiFi task + } + else + { + ESP_LOGI(TAG, "Trying provisioned networks..."); + m_wifi->start(); + } - int num_networks = WiFi.scanNetworks(false, false, false, 0); + m_led->setColor(0, 255, 0); + Wifi::WIFI_STATUS wifi_status = m_wifi->waitForConnection(); + ESP_LOGI(TAG, "WiFi final status: %d", (int)wifi_status); - for(int n = 0; n < num_networks; n++) - { - ESP_LOGI(TAG, "%s, %d", WiFi.SSID(n).c_str(), WiFi.RSSI(n)); - } -#endif + if(wifi_status == Wifi::WIFI_STATUS::CONNECTED) + { + ESP_LOGI(TAG, "Connected to WiFi successfully"); + + // Sync time + ESP_LOGI(TAG, "Getting local time..."); + struct tm timeinfo; + int tries = 5; + while (tries--) + { + configTime(0, 0, "pool.ntp.org"); + if(getLocalTime(&timeinfo)) + { + ESP_LOGI(TAG, "pool.ntp.org ok"); + break; + } + else + ESP_LOGE(TAG, "pool.ntp.org Failed"); + } + + needs_provision = false; + connected = true; + } + else + { + ESP_LOGI(TAG, "All WiFi connections failed, will enter provisioning mode"); + m_wifi->pause(true); + } + } + else if(first_attempt) + { + // No provisioned networks - try fallback directly + ESP_LOGI(TAG, "No provisioned networks, trying fallback..."); + m_led->setColor(0, 255, 0); + m_wifi->start(); + Wifi::WIFI_STATUS wifi_status = m_wifi->waitForConnection(); + + if(wifi_status == Wifi::WIFI_STATUS::CONNECTED) + { + ESP_LOGI(TAG, "Connected to fallback network"); + + // Sync time + ESP_LOGI(TAG, "Getting local time..."); + struct tm timeinfo; + int tries = 5; + while (tries--) + { + configTime(0, 0, "pool.ntp.org"); + if(getLocalTime(&timeinfo)) + { + ESP_LOGI(TAG, "pool.ntp.org ok"); + break; + } + else + ESP_LOGE(TAG, "pool.ntp.org Failed"); + } + + needs_provision = false; + connected = true; + } + else + { + ESP_LOGI(TAG, "Fallback connection failed"); + m_wifi->pause(true); + } + } - if(SETTINGS.wifi.num > 0) - { - // try connecting - m_led->setColor(0, 255, 0); - m_wifi->start(); + // Enter provisioning mode if needed + if(needs_provision && !connected) + { + ESP_LOGI(TAG, "Entering provisioning mode for 10 minutes..."); + m_led->setPulse(0, 0, 255); + + // Start provisioning mode in WiFi + m_wifi->startProvisioning(); + + // Start the provision server + ProvisionSoftAP provision(80); + provision.start(); + + // Wait for either successful provisioning or timeout + ESP_LOGI(TAG, "Waiting for provisioning (10 minute timeout)..."); + while(m_wifi->status() == Wifi::WIFI_STATUS::PROVISIONING) + { + if(m_wifi->isProvisioningTimedOut()) + { + ESP_LOGW(TAG, "Provisioning timeout reached (10 minutes)"); + break; + } + + // You could add logic here to check if new credentials were received + // and attempt immediate connection if so + + delay(1000); + } + + // Stop provisioning + ESP_LOGI(TAG, "Stopping provisioning mode..."); + // provision.stop(); // Add this method to ProvisionSoftAP if available + m_wifi->stopProvisioning(); + + ESP_LOGI(TAG, "Provisioning period ended, will retry connections in 5 seconds..."); + delay(5000); + } + + first_attempt = false; + } - Wifi::WIFI_STATUS wifi_status = m_wifi->waitForConnection(); + ESP_LOGI(TAG, "WiFi connection established, continuing with app initialization..."); - if(wifi_status == Wifi::WIFI_STATUS::CONNECTED) - { - ESP_LOGI(TAG, "Getting local time..."); - struct tm timeinfo; + otaCheck(); + + // m_led->setPulse(255, 0, 255); + m_led->allOff(); - int tries = 5; - while (tries--) - { - configTime(0, 0, "pool.ntp.org"); // needed? + m_mqtt_service = new MqttService(*this); + m_mqtt_service->start(); - if(getLocalTime(&timeinfo)) - { - ESP_LOGI(TAG, "pool.ntp.org ok"); - break; - } - else - ESP_LOGE(TAG, "pool.ntp.org Failed"); - } - - needs_provision = false; - } - else - { - ESP_LOGI(TAG, "Provisioned networks failed, trying fallback..."); - // Don't pause yet - let it try the fallback - // The modified startConnecting() will attempt CBX_IoT fallback - // Wait a bit more for the fallback attempt - delay(5000); - wifi_status = m_wifi->status(); - - if(wifi_status == Wifi::WIFI_STATUS::CONNECTED) - { - ESP_LOGI(TAG, "Connected via fallback network"); - ESP_LOGI(TAG, "Getting local time..."); - struct tm timeinfo; - - int tries = 5; - while (tries--) - { - configTime(0, 0, "pool.ntp.org"); // needed? - - if(getLocalTime(&timeinfo)) - { - ESP_LOGI(TAG, "pool.ntp.org ok"); - break; - } - else - ESP_LOGE(TAG, "pool.ntp.org Failed"); - } - needs_provision = false; - } - else - { - ESP_LOGI(TAG, "Fallback also failed, entering provisioning mode"); - m_wifi->pause(true); - } - } - } - else - { - // No provisioned networks - try fallback directly - ESP_LOGI(TAG, "No provisioned networks, trying fallback..."); - m_led->setColor(0, 255, 0); - m_wifi->start(); - Wifi::WIFI_STATUS wifi_status = m_wifi->waitForConnection(); - - if(wifi_status == Wifi::WIFI_STATUS::CONNECTED) - { - ESP_LOGI(TAG, "Connected to fallback network"); - ESP_LOGI(TAG, "Getting local time..."); - struct tm timeinfo; - - int tries = 5; - while (tries--) - { - configTime(0, 0, "pool.ntp.org"); // needed? - - if(getLocalTime(&timeinfo)) - { - ESP_LOGI(TAG, "pool.ntp.org ok"); - break; - } - else - ESP_LOGE(TAG, "pool.ntp.org Failed"); - } - needs_provision = false; - } - else - { - ESP_LOGI(TAG, "Fallback failed, entering provisioning mode"); - m_wifi->pause(true); - } - } - if(needs_provision) - { - m_led->setPulse(0, 0, 255); - ProvisionSoftAP provision(80); - provision.start(); - } - - otaCheck(); - - // m_led->setPulse(255, 0, 255); - m_led->allOff(); - - m_mqtt_service = new MqttService(*this); - m_mqtt_service->start(); - - m_sensor_service = new SensorService(*this); - m_sensor_service->start(); + m_sensor_service = new SensorService(*this); + m_sensor_service->start(); } void App::otaCheck() diff --git a/main/Wifi.cpp b/main/Wifi.cpp index 7771b44..f641fd2 100644 --- a/main/Wifi.cpp +++ b/main/Wifi.cpp @@ -9,6 +9,7 @@ #include "app_config.h" #include +#include "esp_phy_init.h" static const char *TAG = "Wifi"; #define IGNORE_SSID_MINS 20 @@ -20,6 +21,9 @@ Wifi::Wifi() { esp_log_level_set("wifi", ESP_LOG_WARN); esp_log_level_set("wifi_init", ESP_LOG_INFO); + // Add WiFi configuration here + esp_wifi_set_country_code("US", true); // Or your country code + //WiFi.setSleep(false); // Disable power saving if BT is enabled, do not do this! WiFi.onEvent(std::bind(&Wifi::wifi_event, this, _1, _2)); #ifdef USE_TIMER @@ -48,78 +52,230 @@ void Wifi::timerCallback(void* arg) void Wifi::wifi_event(arduino_event_id_t event, arduino_event_info_t info) { - ESP_LOGI(TAG, "event: %s (%d)", WiFi.eventName(event), (int)event); - if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) - { - wifi_err_reason_t reason = (wifi_err_reason_t)info.wifi_sta_disconnected.reason; - ESP_LOGI(TAG, "reason: %s", WiFi.disconnectReasonName(reason)); - } + ESP_LOGI(TAG, "event: %s (%d)", WiFi.eventName(event), (int)event); + if(event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) + { + wifi_err_reason_t reason = (wifi_err_reason_t)info.wifi_sta_disconnected.reason; + ESP_LOGI(TAG, "reason: %s, rssi: %d", WiFi.disconnectReasonName(reason), WiFi.RSSI()); + ESP_LOGI(TAG, "Local IP: %s", WiFi.localIP().toString().c_str()); + } + if(event == ARDUINO_EVENT_WIFI_STA_CONNECTED) + { + ESP_LOGI(TAG, "Connected - RSSI: %d, Channel: %d", WiFi.RSSI(), WiFi.channel()); + } } void Wifi::task() { while(true) { - if(!WiFi.isConnected()) - { - m_wifi_status = WIFI_STATUS::PENDING; - m_wifi_status = startConnecting(); - - delay(500); - - while(m_pause) - { - delay(100); - } - } + // Check if we're in provisioning mode and handle timeout + if(m_wifi_status == WIFI_STATUS::PROVISIONING) + { + if(isProvisioningTimedOut()) + { + ESP_LOGW(TAG, "Provisioning timeout reached, stopping AP mode"); + stopProvisioning(); + m_wifi_status = WIFI_STATUS::NOT_CONNECTED; + m_provision_timeout = true; + } + delay(1000); // Check every second during provisioning + continue; + } + + // Check pause flag FIRST (but not during provisioning) + while(m_pause && m_wifi_status != WIFI_STATUS::PROVISIONING) + { + delay(100); + } + + if(!WiFi.isConnected()) + { + m_wifi_status = WIFI_STATUS::PENDING; + m_wifi_status = startConnecting(); + + delay(500); + } delay(15000); } } +void Wifi::startProvisioning() +{ + m_wifi_status = WIFI_STATUS::PROVISIONING; + m_provision_start_time = millis(); + m_provision_timeout = false; + ESP_LOGI(TAG, "Starting provisioning mode for %lu minutes", PROVISION_TIMEOUT_MS / 60000); +} + +void Wifi::stopProvisioning() +{ + m_wifi_status = WIFI_STATUS::NOT_CONNECTED; + m_provision_start_time = 0; + WiFi.mode(WIFI_STA); // Stop AP mode +} + +bool Wifi::isProvisioningTimedOut() +{ + if(m_provision_start_time == 0) return false; + return (millis() - m_provision_start_time) > PROVISION_TIMEOUT_MS; +} + +void Wifi::resetProvisioningTimer() +{ + m_provision_start_time = millis(); + m_provision_timeout = false; +} + void Wifi::pause(bool pause) { m_pause = pause; } + +bool Wifi::shouldRecalibrateRadio(int failed_ssid_index) +{ + // Check cooldown period + unsigned long current_time = millis(); + bool cooldown_ok = (m_last_recalibration_time == 0) || + (current_time - m_last_recalibration_time >= RECALIBRATION_COOLDOWN_MS); + + if(!cooldown_ok) + { + unsigned long time_remaining = RECALIBRATION_COOLDOWN_MS - (current_time - m_last_recalibration_time); + ESP_LOGD(TAG, "Recalibration skipped - cooldown period active (%lu ms remaining)", time_remaining); + return false; + } + + // Check if we have credentials for this index + if(failed_ssid_index < 0 || failed_ssid_index >= SETTINGS.wifi.num) + { + ESP_LOGD(TAG, "Recalibration skipped - no valid credentials"); + return false; + } + + // Check if the SSID is visible (network is up) + const char* target_ssid = SETTINGS.wifi.entry[failed_ssid_index].ssid; + if(!isSSIDVisible(target_ssid)) + { + ESP_LOGD(TAG, "Recalibration skipped - SSID '%s' not visible", target_ssid); + return false; + } + + ESP_LOGW(TAG, "Radio recalibration needed - connection failed but SSID '%s' is visible", target_ssid); + ESP_LOGI(TAG, "Current time: %lu, Last recalibration: %lu", current_time, m_last_recalibration_time); + return true; +} + +bool Wifi::isSSIDVisible(const char* ssid) +{ + ESP_LOGI(TAG, "Scanning for SSID '%s' visibility...", ssid); + + int num_networks = WiFi.scanNetworks(false, false, false, 500); + ESP_LOGI(TAG, "Found %d networks during visibility check", num_networks); + + for(int n = 0; n < num_networks; n++) + { + if(strcmp(WiFi.SSID(n).c_str(), ssid) == 0) + { + ESP_LOGI(TAG, "SSID '%s' found with RSSI %d dBm", ssid, WiFi.RSSI(n)); + return true; + } + } + + ESP_LOGI(TAG, "SSID '%s' not found in scan results", ssid); + return false; +} + +void Wifi::performRadioRecalibration() +{ + ESP_LOGW(TAG, "Performing WiFi radio recalibration..."); + + // Disconnect and stop WiFi + WiFi.disconnect(); + WiFi.mode(WIFI_OFF); + delay(1000); + + // Erase calibration data to force fresh calibration + esp_phy_erase_cal_data_in_nvs(); + + // Record recalibration time + m_last_recalibration_time = millis(); + + ESP_LOGW(TAG, "Radio recalibration completed - WiFi will reinitialize on next connection attempt"); + + // Brief delay to let the radio settle + delay(2000); +} + + /// @brief Connect to provisioned wifi /// @param index index of wifi in settings /// @return WIFI_STATUS::CONNECTED/NOT_CONENCTED connected +// Modified connectTo method with smart recalibration Wifi::WIFI_STATUS Wifi::connectTo(int index) { - IPAddress local_IP(0, 0, 0, 0); - IPAddress gateway(0, 0, 0, 0); - IPAddress subnet(SETTINGS.wifi.subnet_mask); - IPAddress primaryDNS(SETTINGS.wifi.dns_primary); - IPAddress secondaryDNS(SETTINGS.wifi.dns_secondary); + IPAddress local_IP(0, 0, 0, 0); + IPAddress gateway(0, 0, 0, 0); + IPAddress subnet(SETTINGS.wifi.subnet_mask); + IPAddress primaryDNS(SETTINGS.wifi.dns_primary); + IPAddress secondaryDNS(SETTINGS.wifi.dns_secondary); - ESP_LOGI(TAG, "Connecting to %s...", SETTINGS.wifi.entry[index].ssid); - - delay(1000); + ESP_LOGI(TAG, "Connecting to %s...", SETTINGS.wifi.entry[index].ssid); + + delay(1000); - // set hostname - uint8_t mac[6]; - WiFi.macAddress(mac); - char buffer[32]; - sprintf(buffer, "wellhub-tag%02x%02x%02x", mac[3], mac[4], mac[5]); - WiFi.hostname(buffer); + // set hostname + uint8_t mac[6]; + WiFi.macAddress(mac); + char buffer[32]; + sprintf(buffer, "wellhub-tag%02x%02x%02x", mac[3], mac[4], mac[5]); + WiFi.hostname(buffer); - WiFi.mode(WIFI_STA); - WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); - - WiFi.begin(SETTINGS.wifi.entry[index].ssid, SETTINGS.wifi.entry[index].pwd); - int status = WiFi.waitForConnectResult(10000); + WiFi.mode(WIFI_STA); + WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); + + WiFi.begin(SETTINGS.wifi.entry[index].ssid, SETTINGS.wifi.entry[index].pwd); + int status = WiFi.waitForConnectResult(10000); - if(status == WL_CONNECTED) - { - ESP_LOGI(TAG, "Connected"); - return WIFI_STATUS::CONNECTED; - } + if(status == WL_CONNECTED) + { + ESP_LOGI(TAG, "Connected"); + return WIFI_STATUS::CONNECTED; + } - delay(1000); - - WiFi.disconnect(); - ESP_LOGW(TAG, "Failed to connect, status: %d", status); - return WIFI_STATUS::NOT_CONNECTED; + delay(1000); + WiFi.disconnect(); + + ESP_LOGW(TAG, "Failed to connect, status: %d", status); + + // Check if we should recalibrate the radio + if(shouldRecalibrateRadio(index)) + { + performRadioRecalibration(); + + // Try connecting one more time after recalibration + ESP_LOGI(TAG, "Retrying connection after recalibration..."); + delay(3000); // Give radio time to reinitialize + + WiFi.mode(WIFI_STA); + WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); + WiFi.begin(SETTINGS.wifi.entry[index].ssid, SETTINGS.wifi.entry[index].pwd); + + status = WiFi.waitForConnectResult(10000); + if(status == WL_CONNECTED) + { + ESP_LOGI(TAG, "Connected after recalibration!"); + return WIFI_STATUS::CONNECTED; + } + else + { + ESP_LOGW(TAG, "Still failed after recalibration, status: %d", status); + WiFi.disconnect(); + } + } + + return WIFI_STATUS::NOT_CONNECTED; } int Wifi::start() @@ -147,44 +303,46 @@ Wifi::WIFI_STATUS Wifi::waitForConnection() /// @brief Connect to default fallback wifi network /// @return WIFI_STATUS::CONNECTED/NOT_CONNECTED +// Also modify startConnecting to handle recalibration for fallback network Wifi::WIFI_STATUS Wifi::connectToDefault() { - const char* default_ssid = "CBX_IoT"; - const char* default_password = "69696969"; - - IPAddress local_IP(0, 0, 0, 0); - IPAddress gateway(0, 0, 0, 0); - IPAddress subnet(SETTINGS.wifi.subnet_mask); - IPAddress primaryDNS(SETTINGS.wifi.dns_primary); - IPAddress secondaryDNS(SETTINGS.wifi.dns_secondary); + const char* default_ssid = "CBX_IoT"; + const char* default_password = "69696969"; + + IPAddress local_IP(0, 0, 0, 0); + IPAddress gateway(0, 0, 0, 0); + IPAddress subnet(SETTINGS.wifi.subnet_mask); + IPAddress primaryDNS(SETTINGS.wifi.dns_primary); + IPAddress secondaryDNS(SETTINGS.wifi.dns_secondary); - ESP_LOGI(TAG, "Connecting to default network %s...", default_ssid); - - delay(1000); + ESP_LOGI(TAG, "Connecting to default network %s...", default_ssid); + + delay(1000); - // set hostname - uint8_t mac[6]; - WiFi.macAddress(mac); - char buffer[32]; - sprintf(buffer, "wellhub-tag%02x%02x%02x", mac[3], mac[4], mac[5]); - WiFi.hostname(buffer); + // set hostname + uint8_t mac[6]; + WiFi.macAddress(mac); + char buffer[32]; + sprintf(buffer, "wellhub-tag%02x%02x%02x", mac[3], mac[4], mac[5]); + WiFi.hostname(buffer); - WiFi.mode(WIFI_STA); - WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); - - WiFi.begin(default_ssid, default_password); - int status = WiFi.waitForConnectResult(10000); + WiFi.mode(WIFI_STA); + WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); + + WiFi.begin(default_ssid, default_password); + int status = WiFi.waitForConnectResult(10000); - if(status == WL_CONNECTED) - { - ESP_LOGI(TAG, "Connected to default network"); - return WIFI_STATUS::CONNECTED; - } + if(status == WL_CONNECTED) + { + ESP_LOGI(TAG, "Connected to default network"); + return WIFI_STATUS::CONNECTED; + } - delay(1000); - WiFi.disconnect(); - ESP_LOGW(TAG, "Failed to connect to default network, status: %d", status); - return WIFI_STATUS::NOT_CONNECTED; + delay(1000); + WiFi.disconnect(); + ESP_LOGW(TAG, "Failed to connect to default network, status: %d", status); + + return WIFI_STATUS::NOT_CONNECTED; } /// @brief Connects to wifi. Returns immediately if already connected. @@ -268,15 +426,60 @@ Wifi::WIFI_STATUS Wifi::startConnecting() // Fallback: Try default WiFi network CBX_IoT ESP_LOGI(TAG, "Attempting fallback connection to default network CBX_IoT..."); - WIFI_STATUS fallback_status = connectToDefault(); - if(fallback_status == WIFI_STATUS::CONNECTED) - { - ESP_LOGI(TAG, "Successfully connected to default network"); - return WIFI_STATUS::CONNECTED; - } + WIFI_STATUS fallback_status = connectToDefault(); + if(fallback_status == WIFI_STATUS::CONNECTED) + { + ESP_LOGI(TAG, "Successfully connected to default network"); + return WIFI_STATUS::CONNECTED; + } - ESP_LOGE(TAG, "Cannot connect to any network including default fallback"); - return WIFI_STATUS::NOT_PROVISIONED; + // Check if we should recalibrate for the fallback network + ESP_LOGW(TAG, "Fallback connection failed, checking if recalibration needed..."); + + const char* default_ssid = "CBX_IoT"; + if(isSSIDVisible(default_ssid)) + { + unsigned long current_time = millis(); + + // Allow recalibration if: + // 1. Never recalibrated before (m_last_recalibration_time == 0) + // 2. Or enough time has passed since last recalibration + bool cooldown_ok = (m_last_recalibration_time == 0) || + (current_time - m_last_recalibration_time >= RECALIBRATION_COOLDOWN_MS); + + if(cooldown_ok) + { + ESP_LOGW(TAG, "Fallback network '%s' visible but connection failed - performing recalibration", default_ssid); + ESP_LOGI(TAG, "Current time: %lu, Last recalibration: %lu", current_time, m_last_recalibration_time); + + performRadioRecalibration(); + + // Retry fallback connection after recalibration + ESP_LOGI(TAG, "Retrying fallback connection after recalibration..."); + fallback_status = connectToDefault(); + if(fallback_status == WIFI_STATUS::CONNECTED) + { + ESP_LOGI(TAG, "Successfully connected to fallback after recalibration!"); + return WIFI_STATUS::CONNECTED; + } + else + { + ESP_LOGW(TAG, "Fallback still failed after recalibration"); + } + } + else + { + unsigned long time_remaining = RECALIBRATION_COOLDOWN_MS - (current_time - m_last_recalibration_time); + ESP_LOGD(TAG, "Recalibration skipped - cooldown period active (%lu ms remaining)", time_remaining); + } + } + else + { + ESP_LOGI(TAG, "Fallback network not visible - network may be down"); + } + + ESP_LOGE(TAG, "Cannot connect to any network including default fallback"); + return WIFI_STATUS::NOT_PROVISIONED; } /// @brief Scans all visible ssid's and picks known ssid with highest rssi that is not ignored. diff --git a/main/Wifi.h b/main/Wifi.h index f813b42..77c960f 100644 --- a/main/Wifi.h +++ b/main/Wifi.h @@ -18,7 +18,8 @@ public: NOT_CONNECTED, PENDING, NOT_PROVISIONED, - CONNECTED + CONNECTED, + PROVISIONING } WIFI_STATUS; protected: @@ -40,9 +41,16 @@ protected: public: Wifi(); + void startProvisioning(); + void stopProvisioning(); + bool isProvisioningTimedOut(); + void resetProvisioningTimer(); protected: void wifi_event(arduino_event_id_t event, arduino_event_info_t info); + unsigned long m_provision_start_time = 0; + static const unsigned long PROVISION_TIMEOUT_MS = 600000; // 10 minutes + bool m_provision_timeout = false; public: int start(); @@ -53,6 +61,12 @@ public: private: WIFI_STATUS connectToDefault(); + unsigned long m_last_recalibration_time = 0; + static const unsigned long RECALIBRATION_COOLDOWN_MS = 3600000; // 1 hour + + bool shouldRecalibrateRadio(int failed_ssid_index); + void performRadioRecalibration(); + bool isSSIDVisible(const char* ssid); }; #endif /* __WIFI_H__ */ \ No newline at end of file