2025-11-28 18:26:32 -06:00
|
|
|
#include "WiFi.hpp"
|
2025-11-29 16:24:56 -06:00
|
|
|
#include "esp_eap_client.h"
|
2025-11-28 18:26:32 -06:00
|
|
|
#include "cJSON.h" // Native replacement for ArduinoJson
|
|
|
|
|
#include "BLE.hpp"
|
2026-01-11 19:02:14 -06:00
|
|
|
#include "esp_wifi_he.h"
|
2026-03-18 01:47:23 -05:00
|
|
|
#include "esp_netif.h"
|
|
|
|
|
#include "lwip/dns.h"
|
2025-11-28 18:26:32 -06:00
|
|
|
|
2026-01-11 19:02:14 -06:00
|
|
|
TaskHandle_t WiFi::awaitConnectHandle = NULL;
|
2025-11-29 16:24:56 -06:00
|
|
|
EventGroupHandle_t WiFi::s_wifi_event_group = NULL;
|
|
|
|
|
esp_netif_t* WiFi::netif = NULL;
|
|
|
|
|
esp_event_handler_instance_t WiFi::instance_any_id = NULL;
|
|
|
|
|
esp_event_handler_instance_t WiFi::instance_got_ip = NULL;
|
2025-11-28 18:26:32 -06:00
|
|
|
|
2025-11-29 16:24:56 -06:00
|
|
|
#define WIFI_CONNECTED_BIT BIT0
|
2025-12-23 17:21:44 -06:00
|
|
|
#define WIFI_STARTED_BIT BIT1
|
2025-11-28 18:26:32 -06:00
|
|
|
|
2025-11-29 16:24:56 -06:00
|
|
|
// The Event Handler (The engine room)
|
|
|
|
|
void WiFi::event_handler(void* arg, esp_event_base_t event_base,
|
|
|
|
|
int32_t event_id, void* event_data) {
|
|
|
|
|
|
2025-12-23 17:21:44 -06:00
|
|
|
// WiFi driver has finished initialization
|
|
|
|
|
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
|
|
|
|
printf("WiFi initialized and ready\n");
|
|
|
|
|
xEventGroupSetBits(s_wifi_event_group, WIFI_STARTED_BIT);
|
|
|
|
|
}
|
2025-11-29 16:24:56 -06:00
|
|
|
// We got disconnected -> Retry automatically
|
2025-12-23 17:21:44 -06:00
|
|
|
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
2025-11-29 16:24:56 -06:00
|
|
|
// 1. Cast the data to the correct struct
|
|
|
|
|
wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*) event_data;
|
|
|
|
|
|
|
|
|
|
printf("WiFi Disconnected. Reason Code: %d\n", event->reason);
|
|
|
|
|
|
|
|
|
|
// 2. Check specific Reason Codes
|
|
|
|
|
switch (event->reason) {
|
|
|
|
|
case WIFI_REASON_AUTH_EXPIRE: // Reason 2
|
|
|
|
|
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: // Reason 15 (Most Common for Wrong Pass)
|
|
|
|
|
case WIFI_REASON_BEACON_TIMEOUT: // Reason 200
|
2025-12-23 17:21:44 -06:00
|
|
|
case WIFI_REASON_AUTH_FAIL: // Reason 202
|
|
|
|
|
case WIFI_REASON_HANDSHAKE_TIMEOUT: // Reason 204
|
2025-11-29 16:24:56 -06:00
|
|
|
printf("ERROR: Likely Wrong Password!\n");
|
2026-01-11 19:02:14 -06:00
|
|
|
if (awaitConnectHandle != NULL) {
|
|
|
|
|
xTaskNotify(awaitConnectHandle, false, eSetValueWithOverwrite);
|
|
|
|
|
}
|
2025-11-29 16:24:56 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WIFI_REASON_NO_AP_FOUND: // Reason 201
|
|
|
|
|
printf("ERROR: SSID Not Found\n");
|
2026-01-11 19:02:14 -06:00
|
|
|
if (awaitConnectHandle != NULL) {
|
|
|
|
|
xTaskNotify(awaitConnectHandle, false, eSetValueWithOverwrite);
|
|
|
|
|
}
|
2025-11-29 16:24:56 -06:00
|
|
|
break;
|
2025-12-23 17:21:44 -06:00
|
|
|
|
|
|
|
|
case WIFI_REASON_ASSOC_LEAVE: // Reason 8 - Manual disconnect
|
|
|
|
|
printf("Manual disconnect, not retrying\n");
|
2026-03-18 01:47:23 -05:00
|
|
|
esp_netif_dhcpc_start(netif);
|
2025-12-23 17:21:44 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WIFI_REASON_ASSOC_FAIL: // Reason 203 (Can be AP busy/rate limiting)
|
|
|
|
|
printf("Association failed, will retry...\n");
|
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(1000)); // Wait 1 second before retry to avoid rate limiting
|
2026-01-11 19:02:14 -06:00
|
|
|
esp_netif_dhcpc_start(netif);
|
2025-12-23 17:21:44 -06:00
|
|
|
esp_wifi_connect();
|
|
|
|
|
break;
|
2025-11-29 16:24:56 -06:00
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
printf("Retrying...\n");
|
2026-01-11 19:02:14 -06:00
|
|
|
esp_netif_dhcpc_start(netif);
|
2025-12-23 17:21:44 -06:00
|
|
|
esp_wifi_connect();
|
2025-11-29 16:24:56 -06:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
|
|
|
|
}
|
2025-12-18 22:08:07 -06:00
|
|
|
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) {
|
|
|
|
|
// This is triggered when the scan finishes!
|
|
|
|
|
printf("Scan complete, processing results...\n");
|
|
|
|
|
|
|
|
|
|
// Call a function to process results and notify BLE
|
|
|
|
|
processScanResults();
|
|
|
|
|
}
|
2025-11-29 16:24:56 -06:00
|
|
|
// 3. We got an IP Address -> Success!
|
|
|
|
|
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
|
|
|
|
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
|
|
|
|
printf("Got IP: " IPSTR "\n", IP2STR(&event->ip_info.ip));
|
|
|
|
|
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
2026-01-11 19:02:14 -06:00
|
|
|
if (awaitConnectHandle != NULL) {
|
|
|
|
|
xTaskNotify(awaitConnectHandle, true, eSetValueWithOverwrite);
|
|
|
|
|
}
|
2025-11-29 16:24:56 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WiFi::init() {
|
2025-12-17 21:52:00 -06:00
|
|
|
s_wifi_event_group = xEventGroupCreate();
|
2025-11-29 16:24:56 -06:00
|
|
|
// 1. Init Network Interface
|
|
|
|
|
ESP_ERROR_CHECK(esp_netif_init());
|
|
|
|
|
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
2025-12-18 22:08:07 -06:00
|
|
|
netif = esp_netif_create_default_wifi_sta();
|
2025-11-29 16:24:56 -06:00
|
|
|
|
|
|
|
|
// 2. Init WiFi Driver
|
|
|
|
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
|
|
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
|
|
|
|
|
|
|
|
|
// 3. Set Mode to Station (Client)
|
|
|
|
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
|
|
|
WIFI_EVENT, // The "Topic" (Base)
|
|
|
|
|
ESP_EVENT_ANY_ID, // The specific "Subject" (Any ID)
|
|
|
|
|
&event_handler, // The Function to call
|
|
|
|
|
NULL, // Argument to pass to the function (optional)
|
|
|
|
|
&instance_any_id // Where to store the registration handle
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK(esp_event_handler_instance_register(
|
|
|
|
|
IP_EVENT,
|
|
|
|
|
IP_EVENT_STA_GOT_IP,
|
|
|
|
|
&event_handler,
|
|
|
|
|
NULL,
|
|
|
|
|
&instance_got_ip
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
ESP_ERROR_CHECK(esp_wifi_start());
|
2025-12-23 17:21:44 -06:00
|
|
|
xEventGroupWaitBits(s_wifi_event_group, WIFI_STARTED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
|
2026-01-11 19:02:14 -06:00
|
|
|
awaitConnectHandle = NULL;
|
2025-11-29 16:24:56 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- CHECK STATUS ---
|
|
|
|
|
bool WiFi::isConnected() {
|
|
|
|
|
if (s_wifi_event_group == NULL) return false;
|
|
|
|
|
EventBits_t bits = xEventGroupGetBits(s_wifi_event_group);
|
|
|
|
|
return (bits & WIFI_CONNECTED_BIT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- GET IP AS STRING ---
|
|
|
|
|
std::string WiFi::getIP() {
|
|
|
|
|
esp_netif_ip_info_t ip_info;
|
|
|
|
|
esp_netif_get_ip_info(netif, &ip_info);
|
|
|
|
|
char buf[20];
|
|
|
|
|
sprintf(buf, IPSTR, IP2STR(&ip_info.ip));
|
|
|
|
|
return std::string(buf);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 21:52:00 -06:00
|
|
|
bool WiFi::attemptConnect(const std::string ssid, const std::string password,
|
|
|
|
|
const wifi_auth_mode_t authMode) {
|
|
|
|
|
esp_wifi_sta_enterprise_disable();
|
|
|
|
|
esp_wifi_disconnect();
|
|
|
|
|
|
2025-11-29 16:24:56 -06:00
|
|
|
wifi_config_t wifi_config = {};
|
2025-12-17 21:52:00 -06:00
|
|
|
snprintf((char*)wifi_config.sta.ssid, sizeof(wifi_config.sta.ssid), "%s", ssid.c_str());
|
|
|
|
|
snprintf((char*)wifi_config.sta.password, sizeof(wifi_config.sta.password), "%s", password.c_str());
|
2025-11-29 16:24:56 -06:00
|
|
|
|
|
|
|
|
wifi_config.sta.threshold.authmode = authMode;
|
|
|
|
|
wifi_config.sta.pmf_cfg.capable = true;
|
|
|
|
|
wifi_config.sta.pmf_cfg.required = false;
|
|
|
|
|
|
|
|
|
|
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
|
|
|
|
|
return awaitConnected();
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 21:52:00 -06:00
|
|
|
bool WiFi::attemptConnect(const std::string ssid, const std::string uname,
|
|
|
|
|
const std::string password, const wifi_auth_mode_t authMode) {
|
|
|
|
|
esp_wifi_disconnect();
|
|
|
|
|
|
2025-11-29 16:24:56 -06:00
|
|
|
// 1. Auto-generate the Identity
|
|
|
|
|
std::string identity = "anonymous";
|
|
|
|
|
size_t atPos = uname.find('@');
|
2025-12-17 21:52:00 -06:00
|
|
|
if (atPos != std::string::npos) identity += uname.substr(atPos);
|
2025-11-29 16:24:56 -06:00
|
|
|
|
|
|
|
|
printf("Real User: %s\n", uname.c_str());
|
|
|
|
|
printf("Outer ID : %s (Privacy Safe)\n", identity.c_str());
|
|
|
|
|
|
|
|
|
|
wifi_config_t wifi_config = {};
|
2025-12-17 21:52:00 -06:00
|
|
|
snprintf((char*)wifi_config.sta.ssid, sizeof(wifi_config.sta.ssid), "%s", ssid.c_str());
|
2025-11-29 16:24:56 -06:00
|
|
|
wifi_config.sta.threshold.authmode = authMode;
|
2025-12-17 21:52:00 -06:00
|
|
|
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
2025-11-29 16:24:56 -06:00
|
|
|
|
|
|
|
|
// 3. Set the calculated identity (using new ESP-IDF v5.x API)
|
2025-12-17 21:52:00 -06:00
|
|
|
esp_wifi_sta_enterprise_enable();
|
2025-11-29 16:24:56 -06:00
|
|
|
esp_eap_client_set_identity((uint8_t *)identity.c_str(), identity.length());
|
|
|
|
|
esp_eap_client_set_username((uint8_t *)uname.c_str(), uname.length());
|
|
|
|
|
esp_eap_client_set_password((uint8_t *)password.c_str(), password.length());
|
|
|
|
|
|
|
|
|
|
return awaitConnected();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool WiFi::awaitConnected() {
|
2026-01-11 19:02:14 -06:00
|
|
|
awaitConnectHandle = xTaskGetCurrentTaskHandle();
|
|
|
|
|
if (esp_wifi_connect() != ESP_OK) {
|
|
|
|
|
awaitConnectHandle = NULL;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2025-11-29 16:24:56 -06:00
|
|
|
|
2026-01-11 19:02:14 -06:00
|
|
|
uint32_t status;
|
|
|
|
|
uint8_t MAX_TIMEOUT = 10; //seconds
|
|
|
|
|
if (xTaskNotifyWait(0, ULONG_MAX, &status, pdMS_TO_TICKS(MAX_TIMEOUT * 1000)) == pdTRUE) {
|
|
|
|
|
awaitConnectHandle = NULL;
|
|
|
|
|
if (!status) {
|
2025-11-29 16:24:56 -06:00
|
|
|
printf("SSID/Password was wrong! Aborting connection attempt.\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2026-01-11 19:02:14 -06:00
|
|
|
} else {
|
|
|
|
|
// Timeout - check if connected anyway
|
|
|
|
|
awaitConnectHandle = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isConnected()) {
|
2026-03-18 01:47:23 -05:00
|
|
|
// --- DIAGNOSTIC: snapshot network state before DHCP stop ---
|
|
|
|
|
// Save IP and DNS before stopping DHCP — dhcpc_stop clears both
|
|
|
|
|
esp_netif_ip_info_t ip_info;
|
|
|
|
|
esp_netif_get_ip_info(netif, &ip_info);
|
|
|
|
|
esp_netif_dns_info_t dns_main, dns_backup;
|
|
|
|
|
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_main);
|
|
|
|
|
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_backup);
|
|
|
|
|
|
|
|
|
|
esp_netif_dhcpc_stop(netif);
|
|
|
|
|
|
|
|
|
|
// Re-apply IP and DNS as static configuration
|
|
|
|
|
esp_netif_set_ip_info(netif, &ip_info);
|
|
|
|
|
esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_main);
|
|
|
|
|
esp_netif_set_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_backup);
|
2026-01-11 19:02:14 -06:00
|
|
|
uint8_t protocol_bitmap = 0;
|
|
|
|
|
esp_err_t err = esp_wifi_get_protocol(WIFI_IF_STA, &protocol_bitmap);
|
|
|
|
|
|
|
|
|
|
if (err == ESP_OK && (protocol_bitmap & WIFI_PROTOCOL_11AX)) {
|
|
|
|
|
// WiFi 6 (802.11ax) - Use Target Wake Time (TWT) for power saving
|
|
|
|
|
wifi_twt_setup_config_t twt_config = {
|
|
|
|
|
.setup_cmd = TWT_REQUEST,
|
|
|
|
|
.trigger = true,
|
|
|
|
|
.flow_type = 0, // Announced
|
|
|
|
|
.flow_id = 0,
|
|
|
|
|
.wake_invl_expn = 12, // Exponent for interval
|
|
|
|
|
.min_wake_dura = 255, // ~65ms (unit is 256 microseconds)
|
|
|
|
|
.wake_invl_mant = 14648, // Mantissa (mant * 2^exp = 60,000,000 us = 60s)
|
|
|
|
|
.timeout_time_ms = 5000,
|
|
|
|
|
};
|
|
|
|
|
esp_wifi_sta_itwt_setup(&twt_config);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2025-11-29 16:24:56 -06:00
|
|
|
}
|
|
|
|
|
return false;
|
2025-11-28 18:26:32 -06:00
|
|
|
}
|
|
|
|
|
|
2025-11-29 16:24:56 -06:00
|
|
|
// ------------- non-class --------------
|
2025-12-18 22:08:07 -06:00
|
|
|
void WiFi::scanAndUpdateSSIDList() {
|
2025-11-28 18:26:32 -06:00
|
|
|
printf("Starting WiFi Scan...\n");
|
|
|
|
|
|
2025-12-18 22:08:07 -06:00
|
|
|
esp_wifi_sta_enterprise_disable();
|
|
|
|
|
esp_wifi_disconnect();
|
|
|
|
|
|
2025-11-28 18:26:32 -06:00
|
|
|
wifi_scan_config_t scan_config = {
|
|
|
|
|
.ssid = NULL,
|
|
|
|
|
.bssid = NULL,
|
|
|
|
|
.channel = 0,
|
|
|
|
|
.show_hidden = false
|
|
|
|
|
};
|
2025-12-18 22:08:07 -06:00
|
|
|
esp_err_t err = esp_wifi_scan_start(&scan_config, false);
|
2025-11-28 18:26:32 -06:00
|
|
|
|
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
|
printf("Scan failed!\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-12-18 22:08:07 -06:00
|
|
|
}
|
2025-11-28 18:26:32 -06:00
|
|
|
|
2025-12-18 22:08:07 -06:00
|
|
|
void WiFi::processScanResults() {
|
2025-11-28 18:26:32 -06:00
|
|
|
// 2. Get the results
|
|
|
|
|
uint16_t ap_count = 0;
|
|
|
|
|
esp_wifi_scan_get_ap_num(&ap_count);
|
|
|
|
|
|
|
|
|
|
// Limit to 10 networks to save RAM/BLE MTU space
|
|
|
|
|
if (ap_count > 10) ap_count = 10;
|
|
|
|
|
|
|
|
|
|
wifi_ap_record_t *ap_list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * ap_count);
|
2026-01-03 17:47:07 -06:00
|
|
|
if (ap_list == NULL) {
|
|
|
|
|
printf("Heap allocation error in processScanResults\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-01-11 19:02:14 -06:00
|
|
|
|
|
|
|
|
esp_err_t err = esp_wifi_scan_get_ap_records(&ap_count, ap_list);
|
|
|
|
|
if (err != ESP_OK) {
|
|
|
|
|
printf("Failed to get scan records\n");
|
|
|
|
|
free(ap_list);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-11-28 18:26:32 -06:00
|
|
|
|
|
|
|
|
// 3. Build JSON using cJSON
|
|
|
|
|
cJSON *root = cJSON_CreateArray();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < ap_count; i++) {
|
2025-12-18 22:08:07 -06:00
|
|
|
cJSON *item = cJSON_CreateObject();
|
|
|
|
|
// ESP-IDF stores SSID as uint8_t, cast to char*
|
|
|
|
|
cJSON_AddStringToObject(item, "ssid", (char *)ap_list[i].ssid);
|
|
|
|
|
cJSON_AddNumberToObject(item, "rssi", ap_list[i].rssi);
|
|
|
|
|
// Add encryption type if you want (optional)
|
|
|
|
|
cJSON_AddNumberToObject(item, "auth", ap_list[i].authmode);
|
|
|
|
|
|
|
|
|
|
cJSON_AddItemToArray(root, item);
|
2025-11-28 18:26:32 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. Convert to String
|
|
|
|
|
char *json_string = cJSON_PrintUnformatted(root); // Compact JSON
|
|
|
|
|
printf("JSON: %s\n", json_string);
|
|
|
|
|
|
|
|
|
|
// 5. Update BLE
|
|
|
|
|
if (ssidListChar != nullptr) {
|
2025-12-18 22:28:55 -06:00
|
|
|
ssidListChar.load()->setValue(std::string(json_string));
|
|
|
|
|
NimBLECharacteristic *tmpRefreshChar = ssidRefreshChar.load();
|
|
|
|
|
tmpRefreshChar->setValue("Ready");
|
|
|
|
|
tmpRefreshChar->notify();
|
2025-11-28 18:26:32 -06:00
|
|
|
}
|
|
|
|
|
|
2025-12-18 22:08:07 -06:00
|
|
|
// 6. Cleanup Memory
|
2025-11-28 18:26:32 -06:00
|
|
|
free(ap_list);
|
|
|
|
|
cJSON_Delete(root); // This deletes all children (items) too
|
|
|
|
|
free(json_string); // cJSON_Print allocates memory, you must free it
|
2026-01-11 19:02:14 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool WiFi::attemptDHCPrenewal() {
|
|
|
|
|
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
|
|
|
|
esp_netif_dhcpc_start(netif);
|
|
|
|
|
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
|
|
|
|
WIFI_CONNECTED_BIT,
|
|
|
|
|
pdFALSE,
|
|
|
|
|
pdFALSE,
|
|
|
|
|
pdMS_TO_TICKS(4000));
|
|
|
|
|
|
|
|
|
|
if (bits & WIFI_CONNECTED_BIT) {
|
2026-03-18 01:47:23 -05:00
|
|
|
printf("renewal success\n");
|
|
|
|
|
esp_netif_ip_info_t ip_info;
|
|
|
|
|
esp_netif_get_ip_info(netif, &ip_info);
|
|
|
|
|
esp_netif_dns_info_t dns_main, dns_backup;
|
|
|
|
|
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_main);
|
|
|
|
|
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_backup);
|
|
|
|
|
|
2026-01-11 19:02:14 -06:00
|
|
|
esp_netif_dhcpc_stop(netif);
|
2026-03-18 01:47:23 -05:00
|
|
|
|
|
|
|
|
esp_netif_set_ip_info(netif, &ip_info);
|
|
|
|
|
esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_main);
|
|
|
|
|
esp_netif_set_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_backup);
|
2026-01-11 19:02:14 -06:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
printf("DHCP Renewal failed. Reconnecting Wi-Fi...\n");
|
|
|
|
|
esp_wifi_disconnect();
|
|
|
|
|
return awaitConnected();
|
2025-11-28 18:26:32 -06:00
|
|
|
}
|