diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index bb5c4a4..433ae55 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,23 +1,23 @@ -{ - "configurations": [ - { - "name": "ESP-IDF", - "cStandard": "c11", - "cppStandard": "c++17", - "compileCommands": "${workspaceFolder}/build/compile_commands.json", - "includePath": [ - "~/esp/esp-idf/components/**", - "~/esp/esp-idf/components/arduino/libraries/**", - "${workspaceFolder}/**" - ], - "browse": { - "path": [ - "~/esp/esp-idf/components", - "${workspaceFolder}" - ], - "limitSymbolsToIncludedHeaders": false - } - } - ], - "version": 4 +{ + "configurations": [ + { + "name": "ESP-IDF", + "cStandard": "c11", + "cppStandard": "c++17", + "compileCommands": "${workspaceFolder}/build/compile_commands.json", + "includePath": [ + "~/esp/esp-idf/components/**", + "~/esp/esp-idf/components/arduino/libraries/**", + "${workspaceFolder}/**" + ], + "browse": { + "path": [ + "~/esp/esp-idf/components", + "${workspaceFolder}" + ], + "limitSymbolsToIncludedHeaders": false + } + } + ], + "version": 4 } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 3069537..42abf02 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,79 +1,79 @@ -{ - "files.associations": { - "*.ipp": "cpp", - "*.tcc": "cpp", - "fstream": "cpp", - "array": "cpp", - "string": "cpp", - "string_view": "cpp", - "regex": "cpp", - "bitset": "cpp", - "memory": "cpp", - "random": "cpp", - "future": "cpp", - "optional": "cpp", - "new": "cpp", - "condition_variable": "cpp", - "algorithm": "cpp", - "streambuf": "cpp", - "numeric": "cpp", - "functional": "cpp", - "deque": "cpp", - "list": "cpp", - "vector": "cpp", - "unordered_map": "cpp", - "istream": "cpp", - "ostream": "cpp", - "sstream": "cpp", - "unordered_set": "cpp", - "system_error": "cpp", - "atomic": "cpp", - "strstream": "cpp", - "cctype": "cpp", - "chrono": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "codecvt": "cpp", - "csignal": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "exception": "cpp", - "iterator": "cpp", - "map": "cpp", - "memory_resource": "cpp", - "ratio": "cpp", - "set": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "initializer_list": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "limits": "cpp", - "mutex": "cpp", - "stdexcept": "cpp", - "thread": "cpp", - "cinttypes": "cpp", - "typeinfo": "cpp", - "bit": "cpp", - "compare": "cpp", - "concepts": "cpp", - "netfwd": "cpp", - "numbers": "cpp", - "semaphore": "cpp", - "stop_token": "cpp", - "*.inc": "cpp" - }, - - "cmake.configureOnOpen": false, - "C_Cpp.dimInactiveRegions": true, - "editor.autoIndent": "full", -} +{ + "files.associations": { + "*.ipp": "cpp", + "*.tcc": "cpp", + "fstream": "cpp", + "array": "cpp", + "string": "cpp", + "string_view": "cpp", + "regex": "cpp", + "bitset": "cpp", + "memory": "cpp", + "random": "cpp", + "future": "cpp", + "optional": "cpp", + "new": "cpp", + "condition_variable": "cpp", + "algorithm": "cpp", + "streambuf": "cpp", + "numeric": "cpp", + "functional": "cpp", + "deque": "cpp", + "list": "cpp", + "vector": "cpp", + "unordered_map": "cpp", + "istream": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "unordered_set": "cpp", + "system_error": "cpp", + "atomic": "cpp", + "strstream": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "codecvt": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "exception": "cpp", + "iterator": "cpp", + "map": "cpp", + "memory_resource": "cpp", + "ratio": "cpp", + "set": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "stdexcept": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "bit": "cpp", + "compare": "cpp", + "concepts": "cpp", + "netfwd": "cpp", + "numbers": "cpp", + "semaphore": "cpp", + "stop_token": "cpp", + "*.inc": "cpp" + }, + + "cmake.configureOnOpen": false, + "C_Cpp.dimInactiveRegions": true, + "editor.autoIndent": "full", +} diff --git a/main/App.cpp b/main/App.cpp index a117555..58334dd 100644 --- a/main/App.cpp +++ b/main/App.cpp @@ -44,6 +44,9 @@ void App::init() 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); + ESP_LOGW(TAG, "Ver:1.00"); + + m_led = new Led(LED_PIN); m_wifi = new Wifi(); m_commandProcessor = new CommandProcessor(*this); diff --git a/main/Wifi.cpp b/main/Wifi.cpp index f641fd2..1fcccdb 100644 --- a/main/Wifi.cpp +++ b/main/Wifi.cpp @@ -10,18 +10,102 @@ #include #include "esp_phy_init.h" +#include "esp_ota_ops.h" static const char *TAG = "Wifi"; #define IGNORE_SSID_MINS 20 using namespace std::placeholders; +const char* Wifi::FALLBACK_NETWORKS[] = {"CBX_IoT", "welltest"}; +const char* Wifi::FALLBACK_PASSWORDS[] = {"69696969", "well1234"}; +const int Wifi::NUM_FALLBACK_NETWORKS = 2; + +bool Wifi::shouldPerformBootupCalibration() +{ + uint32_t reset_reason = esp_reset_reason(); + + ESP_LOGI(TAG, "Checking if bootup calibration needed, reset reason: %d", reset_reason); + + // Always calibrate after these conditions: + bool should_calibrate = false; + + // 1. After OTA update + const esp_partition_t* running_partition = esp_ota_get_running_partition(); + const esp_partition_t* boot_partition = esp_ota_get_boot_partition(); + if (running_partition != boot_partition) { + ESP_LOGW(TAG, "Bootup calibration: Running from different partition (OTA update detected)"); + should_calibrate = true; + } + + // 2. After power-related resets that might affect calibration + if(reset_reason == ESP_RST_BROWNOUT) { + ESP_LOGW(TAG, "Bootup calibration: Brown-out reset detected"); + should_calibrate = true; + } + + // 3. After watchdog resets (system instability) + if(reset_reason == ESP_RST_TASK_WDT || reset_reason == ESP_RST_WDT) { + ESP_LOGW(TAG, "Bootup calibration: Watchdog reset detected"); + should_calibrate = true; + } + + // 4. After panic/exception resets + if(reset_reason == ESP_RST_PANIC) { + ESP_LOGW(TAG, "Bootup calibration: Panic reset detected"); + should_calibrate = true; + } + + // 5. First boot after firmware flash (power-on reset) + if(reset_reason == ESP_RST_POWERON) { + ESP_LOGI(TAG, "Bootup calibration: Power-on reset (fresh boot or firmware flash)"); + should_calibrate = true; + } + + // 6. Check if automatic calibration occurred (failed to load RF data) + // This would require checking a flag set during phy_init + // For now, we'll assume if we got this far, we might need it + + return should_calibrate; +} + +void Wifi::performBootupCalibration() +{ + if(m_bootup_calibration_done) { + ESP_LOGD(TAG, "Bootup calibration already performed"); + return; + } + + ESP_LOGW(TAG, "Performing WiFi calibration after boot-up..."); + + // Ensure WiFi is off before calibration + WiFi.mode(WIFI_OFF); + delay(1000); + + // Clear any existing calibration data to force fresh calibration + esp_phy_erase_cal_data_in_nvs(); + ESP_LOGI(TAG, "Cleared existing PHY calibration data"); + + // Initialize WiFi with fresh calibration + WiFi.mode(WIFI_STA); + delay(2000); // Give time for calibration to complete + + // Turn off WiFi again to save power until actually needed + WiFi.mode(WIFI_OFF); + delay(500); + + m_bootup_calibration_done = true; + ESP_LOGW(TAG, "Bootup WiFi calibration completed"); +} Wifi::Wifi() { esp_log_level_set("wifi", ESP_LOG_WARN); esp_log_level_set("wifi_init", ESP_LOG_INFO); // Add WiFi configuration here + if(shouldPerformBootupCalibration()) { + performBootupCalibration(); + } 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! @@ -169,11 +253,24 @@ bool Wifi::shouldRecalibrateRadio(int failed_ssid_index) bool Wifi::isSSIDVisible(const char* ssid) { - ESP_LOGI(TAG, "Scanning for SSID '%s' visibility...", ssid); + ESP_LOGI(TAG, "=== Starting SSID visibility scan for '%s' ===", ssid); - int num_networks = WiFi.scanNetworks(false, false, false, 500); - ESP_LOGI(TAG, "Found %d networks during visibility check", num_networks); + wl_status_t status = WiFi.status(); + ESP_LOGI(TAG, "Current WiFi status before scan: %d", status); + + // Force WiFi into clean state - more aggressive approach + WiFi.disconnect(true); // true = also forget credentials temporarily + delay(500); + WiFi.mode(WIFI_OFF); // Completely turn off WiFi + delay(500); + WiFi.mode(WIFI_STA); // Turn back on in station mode + delay(1000); // Longer delay for complete initialization + + ESP_LOGI(TAG, "Calling WiFi.scanNetworks(false, false, false, 0)..."); + int num_networks = WiFi.scanNetworks(false, false, false, 0); + ESP_LOGI(TAG, "=== Scan completed, found %d networks ===", num_networks); + for(int n = 0; n < num_networks; n++) { if(strcmp(WiFi.SSID(n).c_str(), ssid) == 0) @@ -205,7 +302,7 @@ void Wifi::performRadioRecalibration() ESP_LOGW(TAG, "Radio recalibration completed - WiFi will reinitialize on next connection attempt"); // Brief delay to let the radio settle - delay(2000); + delay(3000); } @@ -306,16 +403,33 @@ Wifi::WIFI_STATUS Wifi::waitForConnection() // 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"; + // Try each fallback network in sequence using class members + for(int i = 0; i < NUM_FALLBACK_NETWORKS; i++) + { + ESP_LOGI(TAG, "Trying fallback network %d: %s...", i + 1, FALLBACK_NETWORKS[i]); + + WIFI_STATUS status = connectToFallbackNetwork(FALLBACK_NETWORKS[i], FALLBACK_PASSWORDS[i]); + if(status == WIFI_STATUS::CONNECTED) + { + ESP_LOGI(TAG, "Connected to fallback network %s", FALLBACK_NETWORKS[i]); + return WIFI_STATUS::CONNECTED; + } + } + ESP_LOGW(TAG, "All %d fallback networks failed", NUM_FALLBACK_NETWORKS); + return WIFI_STATUS::NOT_CONNECTED; +} + +// New helper method to connect to a specific fallback network +Wifi::WIFI_STATUS Wifi::connectToFallbackNetwork(const char* ssid, const char* password) +{ 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); + ESP_LOGI(TAG, "Connecting to fallback network %s...", ssid); delay(1000); @@ -329,156 +443,285 @@ Wifi::WIFI_STATUS Wifi::connectToDefault() WiFi.mode(WIFI_STA); WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS); - WiFi.begin(default_ssid, default_password); + WiFi.begin(ssid, password); int status = WiFi.waitForConnectResult(10000); if(status == WL_CONNECTED) { - ESP_LOGI(TAG, "Connected to default network"); + ESP_LOGI(TAG, "Connected to fallback network %s", ssid); return WIFI_STATUS::CONNECTED; } delay(1000); WiFi.disconnect(); - ESP_LOGW(TAG, "Failed to connect to default network, status: %d", status); + ESP_LOGW(TAG, "Failed to connect to fallback network %s, status: %d", ssid, status); return WIFI_STATUS::NOT_CONNECTED; } /// @brief Connects to wifi. Returns immediately if already connected. /// @return WH_OK | WH_ERR_WIFI_NOT_PROVISIONED +// Modified startConnecting method to handle dual fallback with recalibration +// Modified startConnecting method - no hardcoded networks Wifi::WIFI_STATUS Wifi::startConnecting() { - if(WiFi.isConnected()) - return WIFI_STATUS::CONNECTED; - - // Try provisioned networks first if any exist - if(SETTINGS.wifi.num > 0) - { - // if only one network is provisioned - if(SETTINGS.wifi.num == 1) - { - SETTINGS.wifi.selected = 0; - for(int n = 0; n < 7; n++) - { - if(connectTo(SETTINGS.wifi.selected) == WIFI_STATUS::CONNECTED) - return WIFI_STATUS::CONNECTED; - - WiFi.disconnect(); - } - - ESP_LOGW(TAG, "Failed to connect to provisioned network"); - } - else - { - // multiple networks are provisioned. Use either specific network or scan for highest rssi - memset(m_ignored, 0, SETTINGS_NUM_WIFI_ENTRIES); - int ssid_ix = SETTINGS.wifi.selected; - - if(SETTINGS.wifi.always_scan_before_connect || SETTINGS.wifi.selected >= SETTINGS.wifi.num) - ssid_ix = scan(); - - if(ssid_ix >= 0) - { - if(connectTo(ssid_ix) == WIFI_STATUS::CONNECTED) - { - SETTINGS.wifi.selected = ssid_ix; - return WIFI_STATUS::CONNECTED; - } - - // didn't work. go through them all giving priority to one with highest rssi - m_ignored[ssid_ix] = IGNORE_SSID_MINS; - - do - { - ssid_ix = scan(); - if(ssid_ix >= 0) - { - if(connectTo(ssid_ix) == WIFI_STATUS::CONNECTED) - return WIFI_STATUS::CONNECTED; - else - m_ignored[ssid_ix] = IGNORE_SSID_MINS; - } - else - break; - - } while(true); - - // that failed too, try them all again round-robin - for(int m = 0; m < 3; m++) - { - for(int n = 0; n < SETTINGS.wifi.num; n++) - { - if(connectTo(n) == WIFI_STATUS::CONNECTED) - return WIFI_STATUS::CONNECTED; - } - } - } - - ESP_LOGW(TAG, "Failed to connect to any provisioned networks"); - } - } - else - { - ESP_LOGW(TAG, "No networks provisioned"); - } - - // 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"); + ESP_LOGW(TAG, "===== START CONNECTING ====="); + + // Diagnostic logging of saved networks + ESP_LOGW(TAG, "Provisioned networks: %d", SETTINGS.wifi.num); + for(int i = 0; i < SETTINGS.wifi.num; i++) { + ESP_LOGW(TAG, "[%d] SSID: '%s'", i, SETTINGS.wifi.entry[i].ssid); + } + + if(::WiFi.isConnected()) { + ESP_LOGW(TAG, "Already connected"); return WIFI_STATUS::CONNECTED; } - // Check if we should recalibrate for the fallback network - ESP_LOGW(TAG, "Fallback connection failed, checking if recalibration needed..."); + // Try provisioned networks first if any exist + if(SETTINGS.wifi.num > 0) + { + // Single network provisioned - try multiple times + if(SETTINGS.wifi.num == 1) + { + ESP_LOGW(TAG, "Single network provisioned, checking visibility first..."); + SETTINGS.wifi.selected = 0; + + // Check if the network is visible before attempting connections + if(isSSIDVisible(SETTINGS.wifi.entry[0].ssid)) + { + ESP_LOGW(TAG, "Network '%s' is visible, attempting connection...", + SETTINGS.wifi.entry[0].ssid); + + for(int n = 0; n < 7; n++) + { + ESP_LOGW(TAG, "Connection attempt %d/7 to '%s'", n+1, + SETTINGS.wifi.entry[0].ssid); + if(connectTo(SETTINGS.wifi.selected) == WIFI_STATUS::CONNECTED) { + ESP_LOGW(TAG, "Successfully connected on attempt %d", n+1); + return WIFI_STATUS::CONNECTED; + } + ::WiFi.disconnect(); + delay(1000); + } + ESP_LOGW(TAG, "Failed to connect to visible network after 7 attempts"); + } + else + { + ESP_LOGW(TAG, "Network '%s' not found in scan - skipping connection attempts", + SETTINGS.wifi.entry[0].ssid); + } + + ESP_LOGW(TAG, "Single provisioned network unavailable or failed"); + } + else + { + // Multiple networks provisioned - ALWAYS scan first to get current visibility/RSSI + ESP_LOGW(TAG, "Multiple networks provisioned, scanning for currently available networks..."); + memset(m_ignored, 0, SETTINGS_NUM_WIFI_ENTRIES); + + // Force a fresh scan to get current network conditions + ESP_LOGW(TAG, "Performing fresh scan to find best available network..."); + int ssid_ix = scan(); + + if(ssid_ix >= 0) + { + ESP_LOGW(TAG, "Found available network with best RSSI: '%s'", + SETTINGS.wifi.entry[ssid_ix].ssid); + if(connectTo(ssid_ix) == WIFI_STATUS::CONNECTED) + { + SETTINGS.wifi.selected = ssid_ix; + ESP_LOGW(TAG, "Connected to best available network"); + return WIFI_STATUS::CONNECTED; + } + + // First choice failed - mark as ignored and try others + ESP_LOGW(TAG, "Best RSSI network failed, trying other available networks..."); + m_ignored[ssid_ix] = IGNORE_SSID_MINS; + + // Keep trying other networks found in the scan + do + { + ssid_ix = scan(); + if(ssid_ix >= 0) + { + ESP_LOGW(TAG, "Trying next best available network: '%s'", + SETTINGS.wifi.entry[ssid_ix].ssid); + if(connectTo(ssid_ix) == WIFI_STATUS::CONNECTED) { + SETTINGS.wifi.selected = ssid_ix; + ESP_LOGW(TAG, "Connected to network '%s'", + SETTINGS.wifi.entry[ssid_ix].ssid); + return WIFI_STATUS::CONNECTED; + } + else { + m_ignored[ssid_ix] = IGNORE_SSID_MINS; + } + } + else { + ESP_LOGW(TAG, "No more available networks found in scan"); + break; + } + } while(true); + + // All scanned networks failed - try a brute force approach on all stored networks + ESP_LOGW(TAG, "Scan-based selection failed, trying brute force on all stored networks..."); + memset(m_ignored, 0, SETTINGS_NUM_WIFI_ENTRIES); // Clear ignore list + + for(int cycle = 0; cycle < 3; cycle++) + { + ESP_LOGW(TAG, "Brute force cycle %d/3", cycle+1); + for(int n = 0; n < SETTINGS.wifi.num; n++) + { + // Check if network is actually visible before trying to connect + ESP_LOGW(TAG, "Checking visibility of stored network '%s'...", + SETTINGS.wifi.entry[n].ssid); + + if(isSSIDVisible(SETTINGS.wifi.entry[n].ssid)) + { + ESP_LOGW(TAG, "Network '%s' is visible, attempting connection...", + SETTINGS.wifi.entry[n].ssid); + if(connectTo(n) == WIFI_STATUS::CONNECTED) { + SETTINGS.wifi.selected = n; + ESP_LOGW(TAG, "Connected to '%s' in brute force mode", + SETTINGS.wifi.entry[n].ssid); + return WIFI_STATUS::CONNECTED; + } + } + else + { + ESP_LOGW(TAG, "Network '%s' not visible, skipping", + SETTINGS.wifi.entry[n].ssid); + } + } + } + } + else + { + // No provisioned networks found in scan - try visibility check on all stored networks + ESP_LOGW(TAG, "No provisioned networks found in scan, checking individual visibility..."); + + for(int n = 0; n < SETTINGS.wifi.num; n++) + { + ESP_LOGW(TAG, "Checking if stored network '%s' is available...", + SETTINGS.wifi.entry[n].ssid); + + if(isSSIDVisible(SETTINGS.wifi.entry[n].ssid)) + { + ESP_LOGW(TAG, "Found available stored network '%s', attempting connection...", + SETTINGS.wifi.entry[n].ssid); + if(connectTo(n) == WIFI_STATUS::CONNECTED) { + SETTINGS.wifi.selected = n; + ESP_LOGW(TAG, "Connected to stored network '%s'", + SETTINGS.wifi.entry[n].ssid); + return WIFI_STATUS::CONNECTED; + } + } + else + { + ESP_LOGW(TAG, "Stored network '%s' not currently available", + SETTINGS.wifi.entry[n].ssid); + } + } + } + + ESP_LOGW(TAG, "Failed to connect to any provisioned networks"); + } + } + else + { + ESP_LOGW(TAG, "No networks provisioned"); + } + + // Fallback: Try fallback WiFi networks + ESP_LOGW(TAG, "===== ATTEMPTING FALLBACK CONNECTIONS ====="); - const char* default_ssid = "CBX_IoT"; - if(isSSIDVisible(default_ssid)) + WIFI_STATUS fallback_status = connectToDefault(); + if(fallback_status == WIFI_STATUS::CONNECTED) + { + ESP_LOGW(TAG, "Successfully connected to fallback network"); + return WIFI_STATUS::CONNECTED; + } + + // Check if we should recalibrate for any visible fallback network + ESP_LOGW(TAG, "All fallback connections failed, checking if recalibration needed..."); + + // Check if any fallback network is visible + bool any_network_visible = false; + const char* visible_network = nullptr; + + for(int i = 0; i < NUM_FALLBACK_NETWORKS; i++) + { + ESP_LOGW(TAG, "Checking visibility of fallback network '%s'...", FALLBACK_NETWORKS[i]); + if(isSSIDVisible(FALLBACK_NETWORKS[i])) + { + any_network_visible = true; + visible_network = FALLBACK_NETWORKS[i]; + ESP_LOGW(TAG, "Fallback network '%s' is VISIBLE", FALLBACK_NETWORKS[i]); + break; + } + else { + ESP_LOGW(TAG, "Fallback network '%s' is NOT visible", FALLBACK_NETWORKS[i]); + } + } + + if(any_network_visible) { 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 + // Allow recalibration if never done or cooldown expired 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); + ESP_LOGW(TAG, "*** RECALIBRATION TRIGGERED ***"); + ESP_LOGW(TAG, "Network '%s' visible but connection failed", visible_network); + ESP_LOGW(TAG, "Current time: %lu ms, Last recalibration: %lu ms ago", + current_time, + m_last_recalibration_time ? (current_time - m_last_recalibration_time) : 0); performRadioRecalibration(); - // Retry fallback connection after recalibration - ESP_LOGI(TAG, "Retrying fallback connection after recalibration..."); + // Retry all fallback networks after recalibration + ESP_LOGW(TAG, "===== RETRYING AFTER RECALIBRATION ====="); fallback_status = connectToDefault(); if(fallback_status == WIFI_STATUS::CONNECTED) { - ESP_LOGI(TAG, "Successfully connected to fallback after recalibration!"); + ESP_LOGW(TAG, "*** SUCCESS *** Connected after recalibration!"); return WIFI_STATUS::CONNECTED; } else { - ESP_LOGW(TAG, "Fallback still failed after recalibration"); + ESP_LOGE(TAG, "*** FAILURE *** Still cannot connect after recalibration"); + + // Try provisioned networks one more time after recalibration + if(SETTINGS.wifi.num > 0) { + ESP_LOGW(TAG, "Final attempt on provisioned networks after recalibration..."); + for(int i = 0; i < SETTINGS.wifi.num; i++) { + if(connectTo(i) == WIFI_STATUS::CONNECTED) { + ESP_LOGW(TAG, "Connected to provisioned network after recalibration!"); + return WIFI_STATUS::CONNECTED; + } + } + } } } 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); + ESP_LOGW(TAG, "Recalibration SKIPPED - cooldown active"); + ESP_LOGW(TAG, "Time remaining: %lu ms (%lu seconds)", + time_remaining, time_remaining / 1000); } } else { - ESP_LOGI(TAG, "Fallback network not visible - network may be down"); + ESP_LOGE(TAG, "No fallback networks visible - all networks may be down"); } - ESP_LOGE(TAG, "Cannot connect to any network including default fallback"); + ESP_LOGE(TAG, "===== CONNECTION FAILED ====="); + ESP_LOGE(TAG, "Cannot connect to any network (provisioned or fallback)"); + //dumpSystemDiagnostics("CONNECTION_FAILED_FINAL"); return WIFI_STATUS::NOT_PROVISIONED; } @@ -488,7 +731,7 @@ int Wifi::scan() { ESP_LOGI(TAG, "Scanning wifi networks..."); - int num_networks = WiFi.scanNetworks(false, false, false, 500); + int num_networks = WiFi.scanNetworks(false, false, false, 0); ESP_LOGI(TAG, "found %d networks", num_networks); int rssi = -500; diff --git a/main/Wifi.h b/main/Wifi.h index 77c960f..1b32a65 100644 --- a/main/Wifi.h +++ b/main/Wifi.h @@ -45,6 +45,8 @@ public: void stopProvisioning(); bool isProvisioningTimedOut(); void resetProvisioningTimer(); + void performBootupCalibration(); + bool shouldPerformBootupCalibration(); protected: void wifi_event(arduino_event_id_t event, arduino_event_info_t info); @@ -60,10 +62,16 @@ public: WIFI_STATUS waitForConnection(); private: - WIFI_STATUS connectToDefault(); + // Single source of truth for fallback networks + static const char* FALLBACK_NETWORKS[]; + static const char* FALLBACK_PASSWORDS[]; + static const int NUM_FALLBACK_NETWORKS; + + WIFI_STATUS connectToDefault(); + WIFI_STATUS connectToFallbackNetwork(const char* ssid, const char* password); unsigned long m_last_recalibration_time = 0; static const unsigned long RECALIBRATION_COOLDOWN_MS = 3600000; // 1 hour - + bool m_bootup_calibration_done = false; bool shouldRecalibrateRadio(int failed_ssid_index); void performRadioRecalibration(); bool isSSIDVisible(const char* ssid);