2025-09-27 12:27:58 -07:00

764 lines
26 KiB
C++

/// © MiroZ 2024
#include "Wifi.h"
#include "errors.h"
#include "Settings.h"
#include <WiFi.h>
#include <functional>
#include "utilities.h"
#include "app_config.h"
#include <esp_wifi.h>
#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!
WiFi.onEvent(std::bind(&Wifi::wifi_event, this, _1, _2));
#ifdef USE_TIMER
esp_timer_create_args_t timer;
timer.arg = this;
timer.callback = &timerCallback;
timer.dispatch_method = ESP_TIMER_TASK;
timer.skip_unhandled_events = true;
timer.name = "wifi countdown timer";
ESP_ERROR_CHECK(esp_timer_create(&timer, &m_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(m_timer, 60000000)); // 1 min
#endif
}
#ifdef USE_TIMER
void Wifi::timerCallback(void* arg)
{
for(int n = 0; n < SETTINGS_NUM_WIFI_ENTRIES; n++)
{
if(((Wifi*)arg)->m_ignored[n] > 0)
((Wifi*)arg)->m_ignored[n]--;
}
}
#endif
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, 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)
{
// 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, "=== Starting SSID visibility scan for '%s' ===", ssid);
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)
{
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(3000);
}
/// @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);
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);
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;
}
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()
{
if(m_task == nullptr)
{
uint8_t mac[8];
esp_read_mac(mac, ESP_MAC_WIFI_STA);
ESP_LOGW(TAG, "Starting wifi, mac: %02x:%02x:%02x:%02x:%02x:%02x ...", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
m_task = TaskMgr::getInstance().createTask(std::bind(&Wifi::task, this), WIFI_TASK_NAME, WIFI_TASK_STACK_SIZE, WIFI_TASK_PRIORITY, WIFI_TASK_CORE);
}
return 0;
}
Wifi::WIFI_STATUS Wifi::waitForConnection()
{
Wifi::WIFI_STATUS st;
while((st = status()) == Wifi::WIFI_STATUS::PENDING)
delay(500);
return st;
}
/// @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()
{
// 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 fallback network %s...", 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);
WiFi.mode(WIFI_STA);
WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS);
WiFi.begin(ssid, password);
int status = WiFi.waitForConnectResult(10000);
if(status == WL_CONNECTED)
{
ESP_LOGI(TAG, "Connected to fallback network %s", ssid);
return WIFI_STATUS::CONNECTED;
}
delay(1000);
WiFi.disconnect();
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()
{
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;
}
// 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 =====");
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 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, "*** 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 all fallback networks after recalibration
ESP_LOGW(TAG, "===== RETRYING AFTER RECALIBRATION =====");
fallback_status = connectToDefault();
if(fallback_status == WIFI_STATUS::CONNECTED)
{
ESP_LOGW(TAG, "*** SUCCESS *** Connected after recalibration!");
return WIFI_STATUS::CONNECTED;
}
else
{
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_LOGW(TAG, "Recalibration SKIPPED - cooldown active");
ESP_LOGW(TAG, "Time remaining: %lu ms (%lu seconds)",
time_remaining, time_remaining / 1000);
}
}
else
{
ESP_LOGE(TAG, "No fallback networks visible - all networks may be down");
}
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;
}
/// @brief Scans all visible ssid's and picks known ssid with highest rssi that is not ignored.
/// @return wifi index in Settings
int Wifi::scan()
{
ESP_LOGI(TAG, "Scanning wifi networks...");
int num_networks = WiFi.scanNetworks(false, false, false, 0);
ESP_LOGI(TAG, "found %d networks", num_networks);
int rssi = -500;
int selected_index = -1;
// crossref scanned and saved networks
for(int n = 0; n < num_networks; n++)
{
for(int p = 0; p < SETTINGS.wifi.num; p++)
{
if(strcmp(SETTINGS.wifi.entry[p].ssid, WiFi.SSID(n).c_str()) == 0)
{
// found saved network
ESP_LOGI(TAG, "Found provisioned network '%s' with RSSI %d dBm", SETTINGS.wifi.entry[p].ssid, WiFi.RSSI(n));
if(WiFi.RSSI(n) > rssi && m_ignored[p] == 0)
{
rssi = WiFi.RSSI(n);
selected_index = p;
}
}
}
}
if(selected_index >= 0)
ESP_LOGI(TAG, "Chosen network '%s'", SETTINGS.wifi.entry[selected_index].ssid);
else
ESP_LOGI(TAG, "No suitable networks found at this time");
return selected_index;
}