Chapter 37: WiFi Network Diagnostics
Chapter Objectives
By the end of this chapter, you will be able to:
- Understand the common stages and potential failure points in a WiFi connection process.
- Interpret WiFi disconnection reason codes provided by the ESP-IDF event system.
- Retrieve and evaluate the signal strength (RSSI) of the connected Access Point (AP).
- Verify the IP network configuration obtained via DHCP.
- Utilize the ESP-IDF logging system effectively for debugging WiFi issues.
- Apply basic diagnostic techniques to troubleshoot connection problems.
Introduction
In the previous chapters, we explored how to connect the ESP32 to WiFi networks, including managing multiple profiles. However, wireless environments can be unpredictable. Connections might fail, drop unexpectedly, or suffer from poor performance. Simply knowing that a connection failed is often insufficient; we need to understand why it failed to implement robust and reliable applications.
This chapter delves into WiFi network diagnostics on the ESP32 using ESP-IDF. We will learn how to leverage the information provided by the WiFi driver and networking stack to pinpoint the cause of connection issues. By understanding disconnect reasons, checking signal strength, verifying IP configuration, and using logging effectively, you can significantly improve your ability to troubleshoot and build more resilient WiFi-enabled IoT devices.
Theory
WiFi Connection Stages and Failure Points
Establishing a WiFi connection is a multi-stage process. Failures can occur at any stage:
Stage | Description | Potential Failure Points & Common Causes |
---|---|---|
1. Scanning | The ESP32 actively or passively scans for available WiFi networks in its vicinity. It listens for beacon frames from Access Points (APs). | Target Network Not Found:
|
2. Authentication | The ESP32 attempts to authenticate with the selected AP using the provided credentials (e.g., password for WPA2-PSK). This involves an exchange of authentication frames. | Authentication Rejected/Failed:
|
3. Association | After successful authentication, the ESP32 sends an association request to the AP to formally join the network and receive an Association ID (AID). | Association Rejected/Failed:
|
4. IP Configuration (DHCP) | Once associated, the ESP32 typically requests an IP address, subnet mask, gateway, and DNS server(s) from the network’s DHCP server (usually on the router). | Failed to Obtain IP Address:
|
Ongoing: Maintaining Connection | After successful connection and IP acquisition, the ESP32 must maintain the link with the AP, primarily by receiving beacon frames. | Connection Dropped:
|
%%{ init: { 'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans, sans-serif', 'primaryColor': '#DBEAFE', /* Process Nodes BG */ 'primaryTextColor': '#1E40AF', /* Process Nodes Text */ 'primaryBorderColor': '#2563EB',/* Process Nodes Border */ 'lineColor': '#4B5563', /* Arrow color */ 'textColor': '#1F2937', /* Default text color for labels */ 'mainBkg': 'transparent' /* Diagram background */ }} }%% graph TD A[/"Start WiFi Connection Process"/]:::startNode --> B("1- Scan for Networks<br>(<code>esp_wifi_scan_start</code>)"); B -- "Target AP Found?" --> C{"2- Authenticate with AP<br>(SSID, Password, Security Type)"}; B -- "No AP Found<br><span class='fail'>WIFI_REASON_NO_AP_FOUND</span>" --> F_Scan["<span class='fail'>FAIL:</span> Scan Failure<br>(Out of range, wrong SSID, AP off)"]:::checkNode; C -- "Authentication OK?" --> D{"3- Associate with AP"}; C -- "Auth Failed<br><span class='fail'>WIFI_REASON_MIC_FAILURE</span><br><span class='fail'>WIFI_REASON_AUTH_FAIL</span><br><span class='fail'>WIFI_REASON_AUTH_EXPIRE</span>" --> F_Auth["<span class='fail'>FAIL:</span> Authentication Failure<br>(Wrong password, MAC filter, AP issue)"]:::checkNode; D -- "Association OK?" --> E{"4- Obtain IP Address (DHCP)<br>(Wait for <code>IP_EVENT_STA_GOT_IP</code>)"}; D -- "Assoc. Failed<br><span class='fail'>WIFI_REASON_ASSOC_TOOMANY</span><br><span class='fail'>WIFI_REASON_ASSOC_EXPIRE</span>" --> F_Assoc["<span class='fail'>FAIL:</span> Association Failure<br>(AP full, signal issue, config mismatch)"]:::checkNode; E -- "IP Obtained?" --> F[/"WiFi Connected &<br>IP Configured!"/]:::successNode; E -- "No IP / DHCP Timeout<br>(No <code>IP_EVENT_STA_GOT_IP</code>)" --> F_DHCP["<span class='fail'>FAIL:</span> DHCP Failure<br>(No DHCP server, pool exhausted, network issue)"]:::checkNode; F --> G("Maintain Connection<br>(Monitor Beacons, RSSI)"); G -- "Connection Lost<br><span class='fail'>WIFI_REASON_BEACON_TIMEOUT</span>" --> F_Beacon["<span class='fail'>FAIL:</span> Link Lost<br>(Signal fade, AP reboot, interference)"]:::checkNode; %% Styling for failure text within nodes style F_Scan fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B; style F_Auth fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B; style F_Assoc fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B; style F_DHCP fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B; style F_Beacon fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B; classDef startNode fill:#EDE9FE,stroke:#5B21B6,stroke-width:2px,color:#5B21B6; classDef successNode fill:#D1FAE5,stroke:#059669,stroke-width:2px,color:#065F46; classDef decisionNode fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E; classDef processNode fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF; classDef checkNode fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B; class A startNode; class B,C,D,E,G processNode; class F successNode;
Understanding these stages helps narrow down the possible causes when a connection fails.
Disconnection Reason Codes
The most valuable piece of diagnostic information often comes from the WIFI_EVENT_STA_DISCONNECTED
event. When this event occurs, the associated event data contains a reason
code indicating why the disconnection happened. ESP-IDF defines numerous reason codes in esp_wifi_types.h
. Some common ones include:
Reason Code (Value) | Symbolic Name (from esp_wifi_types.h ) |
Common Interpretation / Likely Cause |
---|---|---|
1 | WIFI_REASON_UNSPECIFIED |
A generic or unspecified error. Not very informative on its own. |
2 | WIFI_REASON_AUTH_EXPIRE |
Authentication timed out. The AP may not have responded to the ESP32’s authentication request in time. Could be due to AP load, poor signal, or network issues. |
3 | WIFI_REASON_AUTH_LEAVE |
Deauthenticated because the ESP32 explicitly left the BSS (e.g., esp_wifi_disconnect() was called by the application). This is an intentional disconnect. |
4 | WIFI_REASON_ASSOC_EXPIRE |
Association timed out. ESP32 sent an association request, but the AP didn’t respond in time. Similar causes to AUTH_EXPIRE. |
5 | WIFI_REASON_ASSOC_TOOMANY |
Association failed because the AP cannot handle any more associated clients (AP capacity reached). |
6 | WIFI_REASON_NOT_AUTHED |
Station is not authenticated. Received a data or management frame from an unauthenticated station (AP perspective). |
7 | WIFI_REASON_NOT_ASSOCED |
Station is not associated. Received a data or management frame from an unassociated station (AP perspective). |
8 | WIFI_REASON_ASSOC_LEAVE |
Association terminated because the ESP32 explicitly left the BSS (similar to AUTH_LEAVE, an intentional disconnect). |
9 | WIFI_REASON_ASSOC_NOT_AUTHED |
Association request rejected by AP because the station is not authenticated. Authentication might have failed or not been attempted. |
13 | WIFI_REASON_IE_INVALID |
Invalid Information Element in a received management frame. Suggests a malformed frame or incompatibility. |
14 | WIFI_REASON_MIC_FAILURE |
Message Integrity Check (MIC) failure during WPA/WPA2 handshake. Very often indicates an incorrect password. |
15 | WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT |
WPA/WPA2 4-way handshake timed out. Password might be correct, but the handshake process failed. Can be due to poor signal, AP issues, or interference. |
16 | WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT |
Group key handshake (part of WPA/WPA2) timed out. |
18 | WIFI_REASON_GROUP_CIPHER_INVALID |
Invalid group cipher. Mismatch in supported encryption algorithms for group traffic. |
19 | WIFI_REASON_PAIRWISE_CIPHER_INVALID |
Invalid pairwise cipher. Mismatch in supported encryption algorithms for unicast traffic. |
23 | WIFI_REASON_802_1X_AUTH_FAILED |
IEEE 802.1X authentication failed. Primarily used in WPA/WPA2 Enterprise networks; credentials (username/password/certificates) are likely incorrect or RADIUS server rejected. |
200 | WIFI_REASON_BEACON_TIMEOUT |
ESP32 missed too many consecutive beacon frames from the AP. Indicates loss of connection, often due to weak signal, AP rebooting, or severe interference. |
201 | WIFI_REASON_NO_AP_FOUND |
ESP32 failed to find the target AP during the scan phase of a connection attempt. SSID might be wrong, AP powered off, out of range, or hidden and not scanned for. |
202 | WIFI_REASON_AUTH_FAIL |
Generic authentication failure. If not MIC_FAILURE, could be other auth issues. Often a wrong password if other specific codes don’t apply. |
203 | WIFI_REASON_ASSOC_FAIL |
Generic association failure. AP rejected association for reasons not covered by more specific codes. |
204 | WIFI_REASON_HANDSHAKE_TIMEOUT |
Generic handshake timeout (could be 4-way or group key). |
205 | WIFI_REASON_CONNECTION_FAIL |
Generic connection failure. A catch-all if no other specific reason code is applicable. |
Note: This table lists common reasons. Refer to esp_wifi_types.h in ESP-IDF for the full list. |
By logging and interpreting these codes in your event handler, you gain significant insight into connection failures.
Signal Strength (RSSI)
Received Signal Strength Indicator (RSSI) measures the power level of the signal received from the AP. It’s a crucial indicator of link quality.
- Units: Typically measured in dBm (decibels relative to one milliwatt).
- Values: Always negative. Values closer to 0 dBm indicate a stronger signal.
RSSI Value (dBm) | Signal Quality | Expected Performance / Stability |
---|---|---|
-30 dBm to -49 dBm | Excellent | Strong, stable signal. Optimal performance. Rarely seen in typical environments unless very close to AP. |
-50 dBm to -59 dBm | Very Good | Reliable connection, good throughput. Suitable for most applications. |
-60 dBm to -67 dBm | Good | Generally reliable connection. -67 dBm is often cited as a minimum for stable data services like voice or video. |
-68 dBm to -70 dBm | Okay / Fair | Connection may be usable, but performance issues (lower speeds, some latency) might start to appear. Signal is becoming weak. |
-71 dBm to -80 dBm | Poor | Unreliable connection. Prone to packet loss and intermittent disconnections. Not recommended for critical applications. |
-81 dBm to -90 dBm | Very Poor | Connection is highly unstable and likely unusable for most practical purposes. Barely maintaining a link. |
Below -90 dBm | No Signal / Unusable | Effectively no usable signal. Connection attempts will likely fail or drop immediately. |
- How to Get: After a successful connection (
IP_EVENT_STA_GOT_IP
), you can callesp_wifi_sta_get_ap_info()
to retrieve information about the connected AP, including its RSSI.
Monitoring RSSI helps diagnose problems related to distance, obstructions, or interference. A low RSSI might explain intermittent disconnections (e.g., WIFI_REASON_BEACON_TIMEOUT
).
IP Configuration Verification
Even if authentication and association succeed, the device isn’t fully connected until it obtains a valid IP address via DHCP. Failures here mean the device can’t communicate on the IP network.
- Success Indicator: The
IP_EVENT_STA_GOT_IP
event signals successful IP acquisition. - Verification: After receiving this event, use
esp_netif_get_ip_info()
with the station network interface handle (esp_netif_t*
) to retrieve the assigned IP address, subnet mask, and gateway address. - Troubleshooting: If
IP_EVENT_STA_GOT_IP
is never received afterWIFI_EVENT_STA_CONNECTED
, suspect DHCP issues (server down, misconfigured, pool exhausted) or severe network problems preventing DHCP communication. Check the IP information retrieved to ensure it’s valid for the target network.
Logging
The ESP-IDF logging library (esp_log
) is indispensable for diagnostics.
- Log Levels: Control the verbosity of output (Error, Warn, Info, Debug, Verbose). For WiFi diagnostics, enabling Debug or even Verbose level for specific components (
wifi
,tcpip_adapter
,phy
) can provide detailed internal state information. Useesp_log_level_set(TAG, LEVEL)
to adjust levels dynamically or permanently viamenuconfig
. - Timestamps: Enable timestamps in logs (
menuconfig
->Component config
->Log output
->Enable timestamps
) to correlate events. - Strategic Logging: Add
ESP_LOGI
,ESP_LOGW
,ESP_LOGE
calls at key points in your connection logic (start attempt, event received, success, failure) to trace the execution flow.
Practical Examples
Let’s enhance our WiFi station code with diagnostic capabilities. Assume you have the basic WiFi initialization (wifi_init_sta
) and event group setup (s_wifi_event_group
, WIFI_CONNECTED_BIT
, WIFI_FAIL_BIT
) from previous chapters.
1. Interpreting Disconnect Reasons
Modify the wifi_event_handler
to provide more detail upon disconnection.
// main.c (or wifi_manager.c)
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
static const char *TAG = "WIFI_DIAG";
// Assume s_wifi_event_group and bits are defined elsewhere
extern EventGroupHandle_t s_wifi_event_group;
extern const int WIFI_CONNECTED_BIT;
extern const int WIFI_FAIL_BIT;
// Helper function to convert reason code to string (add more codes as needed)
static const char* wifi_reason_to_str(wifi_err_reason_t reason) {
switch (reason) {
case WIFI_REASON_UNSPECIFIED: return "UNSPECIFIED";
case WIFI_REASON_AUTH_EXPIRE: return "AUTH_EXPIRE";
case WIFI_REASON_AUTH_LEAVE: return "AUTH_LEAVE";
case WIFI_REASON_ASSOC_EXPIRE: return "ASSOC_EXPIRE";
case WIFI_REASON_ASSOC_TOOMANY: return "ASSOC_TOOMANY";
case WIFI_REASON_NOT_AUTHED: return "NOT_AUTHED";
case WIFI_REASON_NOT_ASSOCED: return "NOT_ASSOCED";
case WIFI_REASON_ASSOC_LEAVE: return "ASSOC_LEAVE";
case WIFI_REASON_ASSOC_NOT_AUTHED: return "ASSOC_NOT_AUTHED";
case WIFI_REASON_DISASSOC_PWRCAP_BAD: return "DISASSOC_PWRCAP_BAD";
case WIFI_REASON_DISASSOC_SUPCHAN_BAD: return "DISASSOC_SUPCHAN_BAD";
case WIFI_REASON_IE_INVALID: return "IE_INVALID";
case WIFI_REASON_MIC_FAILURE: return "MIC_FAILURE (Possibly wrong password)";
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: return "4WAY_HANDSHAKE_TIMEOUT";
case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT: return "GROUP_KEY_UPDATE_TIMEOUT";
case WIFI_REASON_IE_IN_4WAY_DIFFERS: return "IE_IN_4WAY_DIFFERS";
case WIFI_REASON_GROUP_CIPHER_INVALID: return "GROUP_CIPHER_INVALID";
case WIFI_REASON_PAIRWISE_CIPHER_INVALID: return "PAIRWISE_CIPHER_INVALID";
case WIFI_REASON_AKMP_INVALID: return "AKMP_INVALID";
case WIFI_REASON_UNSUPP_RSN_IE_VERSION: return "UNSUPP_RSN_IE_VERSION";
case WIFI_REASON_INVALID_RSN_IE_CAP: return "INVALID_RSN_IE_CAP";
case WIFI_REASON_802_1X_AUTH_FAILED: return "802_1X_AUTH_FAILED";
case WIFI_REASON_CIPHER_SUITE_REJECTED: return "CIPHER_SUITE_REJECTED";
case WIFI_REASON_BEACON_TIMEOUT: return "BEACON_TIMEOUT (Link lost)";
case WIFI_REASON_NO_AP_FOUND: return "NO_AP_FOUND";
case WIFI_REASON_AUTH_FAIL: return "AUTH_FAIL";
case WIFI_REASON_ASSOC_FAIL: return "ASSOC_FAIL";
case WIFI_REASON_HANDSHAKE_TIMEOUT: return "HANDSHAKE_TIMEOUT";
case WIFI_REASON_CONNECTION_FAIL: return "CONNECTION_FAIL";
default: return "UNKNOWN";
}
}
// Modified WiFi Event Handler
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
ESP_LOGI(TAG, "WIFI_EVENT_STA_START: WiFi station started, ready to connect.");
// Trigger connection attempt logic here or elsewhere
// esp_wifi_connect(); // Example: if connecting immediately
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) {
wifi_event_sta_connected_t* event = (wifi_event_sta_connected_t*) event_data;
ESP_LOGI(TAG, "WIFI_EVENT_STA_CONNECTED: Connected to SSID '%.*s', channel %d",
event->ssid_len, event->ssid, event->channel);
// Successfully authenticated and associated, waiting for IP
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*) event_data;
ESP_LOGW(TAG, "WIFI_EVENT_STA_DISCONNECTED: Disconnected from SSID '%.*s'", event->ssid_len, event->ssid);
ESP_LOGW(TAG, "Reason: %d (%s)", event->reason, wifi_reason_to_str(event->reason));
// Signal connection failure (important for connection logic like in Chapter 36)
if (s_wifi_event_group != NULL) {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
// Clear connected bit in case it was set before disconnect
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
// Implement retry logic if desired, potentially based on the reason code
// e.g., if (event->reason == WIFI_REASON_NO_AP_FOUND) { /* Maybe stop retrying? */ }
// else { /* Schedule a retry */ }
} 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;
ESP_LOGI(TAG, "IP_EVENT_STA_GOT_IP: Got IP:" IPSTR, IP2STR(&event->ip_info.ip));
// Signal connection success
if (s_wifi_event_group != NULL) {
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
// Clear fail bit in case it was set during previous attempts
xEventGroupClearBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
// Now is a good time to check RSSI and IP details (see next examples)
} else {
ESP_LOGD(TAG, "Received unhandled event: base=%s, id=%ld", event_base, event_id);
}
}
// Remember to register this handler during wifi_init_sta()
// ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL));
// ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL));
Build/Flash/Observe:
- Integrate this handler into a working WiFi station project (like from Chapter 27 or 36).
- Build, flash, and monitor.
- Test Cases:
- Enter the wrong password for your network. Observe the disconnect reason (likely
WIFI_REASON_MIC_FAILURE
orWIFI_REASON_AUTH_FAIL
). - Configure your router to block the ESP32’s MAC address. Observe the reason (might be
WIFI_REASON_ASSOC_DENIED_UNSPEC
or similar, depending on AP). - Let the ESP32 connect successfully, then turn off your router. Observe the reason (likely
WIFI_REASON_BEACON_TIMEOUT
after a short delay).
- Enter the wrong password for your network. Observe the disconnect reason (likely
2. Checking Signal Strength (RSSI)
Create a function to get and log the RSSI of the currently connected AP. Call this function after obtaining an IP address.
// main.c (or wifi_manager.c) - Add this function
// Function to get and log AP info, including RSSI
void log_connected_ap_info(void) {
wifi_ap_record_t ap_info;
esp_err_t ret = esp_wifi_sta_get_ap_info(&ap_info);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "Connected AP Info:");
ESP_LOGI(TAG, " SSID: %s", ap_info.ssid);
ESP_LOGI(TAG, " Channel: %d", ap_info.primary);
ESP_LOGI(TAG, " RSSI: %d dBm", ap_info.rssi);
// Log other details if needed: ap_info.authmode, ap_info.phy_11b, etc.
} else {
ESP_LOGE(TAG, "Failed to get AP info: %s", esp_err_to_name(ret));
}
}
// --- In the wifi_event_handler, inside the IP_EVENT_STA_GOT_IP case: ---
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
// ... other cases ...
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;
ESP_LOGI(TAG, "IP_EVENT_STA_GOT_IP: Got IP:" IPSTR, IP2STR(&event->ip_info.ip));
// Signal connection success (as before)
if (s_wifi_event_group != NULL) {
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
xEventGroupClearBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
// *** Call the diagnostic function ***
log_connected_ap_info();
// *** Also log IP details (see next example) ***
// log_ip_configuration(event->esp_netif); // Assuming esp_netif is passed or retrieved
}
// ... rest of handler ...
}
Build/Flash/Observe:
- Add the
log_connected_ap_info
function and the call within theIP_EVENT_STA_GOT_IP
handler. - Build, flash, and monitor.
- Observe the RSSI value printed after a successful connection.
- Try moving the ESP32 further from the router and reconnecting. Observe the change in the reported RSSI value.
Warning: Calling
esp_wifi_sta_get_ap_info()
before the ESP32 is fully associated and connected might return an error (ESP_ERR_WIFI_NOT_ASSOC
). It’s best called afterWIFI_EVENT_STA_CONNECTED
or, more reliably, afterIP_EVENT_STA_GOT_IP
.
3. Verifying IP Configuration
Create a function to log the IP details obtained via DHCP.
// main.c (or wifi_manager.c) - Add this function
#include "esp_netif.h" // Ensure this is included
// Function to log IP configuration details
void log_ip_configuration(esp_netif_t *netif) {
if (netif == NULL) {
ESP_LOGE(TAG, "Cannot log IP config: netif handle is NULL");
return;
}
esp_netif_ip_info_t ip_info;
esp_err_t ret = esp_netif_get_ip_info(netif, &ip_info);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "IP Configuration:");
ESP_LOGI(TAG, " IP Address: " IPSTR, IP2STR(&ip_info.ip));
ESP_LOGI(TAG, " Subnet Mask: " IPSTR, IP2STR(&ip_info.netmask));
ESP_LOGI(TAG, " Gateway: " IPSTR, IP2STR(&ip_info.gw));
// Optionally, log DNS servers
esp_netif_dns_info_t dns_info;
if (esp_netif_get_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_info) == ESP_OK) {
ESP_LOGI(TAG, " DNS Server: " IPSTR, IP2STR(&dns_info.ip.u_addr.ip4)); // Assuming IPv4
} else {
ESP_LOGW(TAG, " Could not get DNS server info.");
}
} else {
ESP_LOGE(TAG, "Failed to get IP info: %s", esp_err_to_name(ret));
}
}
// --- In the wifi_event_handler, inside the IP_EVENT_STA_GOT_IP case: ---
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
// ... other cases ...
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;
ESP_LOGI(TAG, "IP_EVENT_STA_GOT_IP: Got IP:" IPSTR, IP2STR(&event->ip_info.ip));
// Signal connection success (as before)
if (s_wifi_event_group != NULL) {
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
xEventGroupClearBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
// Call diagnostic functions
log_connected_ap_info();
log_ip_configuration(event->esp_netif); // Pass the netif handle from the event data
}
// ... rest of handler ...
}
Build/Flash/Observe:
- Add the
log_ip_configuration
function and the call within theIP_EVENT_STA_GOT_IP
handler. - Build, flash, and monitor.
- After a successful connection, observe the logged IP address, subnet mask, gateway, and DNS server. Verify they match your network’s configuration.
Variant Notes
The diagnostic functions and event mechanisms discussed in this chapter rely on core ESP-IDF components (esp_wifi
, esp_event
, esp_log
, esp_netif
) that are designed to be consistent across different ESP32 variants supporting WiFi station mode. Therefore, the techniques described here are applicable to:
- ESP32
- ESP32-S2
- ESP32-S3
- ESP32-C3
- ESP32-C6
- ESP32-C5
- ESP32-C61
While the underlying hardware (radio sensitivity, processing power) might differ slightly, leading to variations in performance or RSSI readings under identical conditions, the software APIs for diagnostics remain the same within the ESP-IDF v5.x framework.
Common Mistakes & Troubleshooting Tips
Mistake / Issue | Symptom(s) | Troubleshooting / Solution |
---|---|---|
Ignoring Disconnect Reasons | Connection fails, but the specific cause is unknown. Debugging is slow and relies on guesswork. | Always log the reason code from the WIFI_EVENT_STA_DISCONNECTED event data. Use a helper function (like wifi_reason_to_str ) or a switch statement to print a human-readable explanation for common codes. |
Checking RSSI Too Early/Late | esp_wifi_sta_get_ap_info() returns ESP_ERR_WIFI_NOT_ASSOC or provides outdated RSSI. Signal quality issues are missed. |
Call esp_wifi_sta_get_ap_info() after the IP_EVENT_STA_GOT_IP event for initial RSSI. For ongoing monitoring, use a separate task to periodically check RSSI while connected. Don’t call it before association is complete. |
Insufficient Logging Detail | Logs show high-level events but miss crucial driver-level or TCP/IP stack information needed to diagnose complex issues. Timestamps missing, making event correlation hard. | During troubleshooting, use esp_log_level_set(TAG, ESP_LOG_DEBUG) or ESP_LOG_VERBOSE for relevant tags (e.g., “wifi”, “tcpip_adapter”, “phy”, your app’s TAG). Enable timestamps in logs via menuconfig (Component config -> Log output -> Enable timestamps ). |
Not Verifying IP Configuration | IP_EVENT_STA_GOT_IP is received, but device still can’t communicate (e.g., ping fails, HTTP requests timeout). |
After IP_EVENT_STA_GOT_IP , always call esp_netif_get_ip_info() and log the obtained IP address, netmask, and gateway. Verify these are correct and valid for the target network. Also check DNS server info. |
Confusing Device vs. Network Issues | Extensive code debugging on ESP32 while the actual problem is with the router (DHCP pool full, MAC filtering, wrong channel), network cable, or RF interference. | Systematically use diagnostic info: disconnect reasons (e.g., WIFI_REASON_NO_AP_FOUND vs. WIFI_REASON_ASSOC_TOOMANY ), RSSI (is it too low?), and IP info. Test connectivity with another device on the same WiFi. Check router logs and settings. Consider the physical environment (distance, obstacles). |
Event Handler Logic Errors | Event group bits (WIFI_CONNECTED_BIT , WIFI_FAIL_BIT ) not set/cleared correctly, leading to main logic getting stuck or behaving unpredictably. |
Carefully review the event handler. Ensure WIFI_FAIL_BIT is set on WIFI_EVENT_STA_DISCONNECTED . Ensure WIFI_CONNECTED_BIT is set on IP_EVENT_STA_GOT_IP and potentially cleared on disconnect. Log event occurrences within the handler. |
Fixed WiFi Channel in Config | ESP32 is configured to connect on a specific channel, but AP changes its channel (e.g., due to auto-channel selection). Connection fails with NO_AP_FOUND on that specific channel. |
In wifi_config_t.sta.channel , set to 0 to allow scanning all channels. Only set a specific channel if you are certain the AP’s channel is fixed and known. |
Exercises
- Periodic RSSI Monitoring: Create a FreeRTOS task that runs only when the ESP32 is connected to WiFi (
WIFI_CONNECTED_BIT
is set). This task should calllog_connected_ap_info()
every 10 seconds to monitor signal strength over time. Ensure the task suspends itself or doesn’t run when disconnected. - Disconnect Reason Retry Logic: Modify the
WIFI_EVENT_STA_DISCONNECTED
handler. Implement a simple retry counter. If the disconnect reason is potentially temporary (e.g.,WIFI_REASON_BEACON_TIMEOUT
,WIFI_REASON_ASSOC_EXPIRE
), attemptesp_wifi_connect()
again after a short delay (e.g., 5 seconds), up to a maximum of 3-5 retries. If the reason suggests a permanent issue (e.g.,WIFI_REASON_NO_AP_FOUND
,WIFI_REASON_AUTH_FAIL
), log the error and do not retry automatically. - Basic Network Check (DNS Lookup): After receiving
IP_EVENT_STA_GOT_IP
, add a call to perform a DNS lookup for a known hostname (e.g., “www.google.com“). Useesp_netif_get_host_by_name()
. Log whether the lookup succeeded and the resolved IP address. This provides a basic check of end-to-end network connectivity beyond just getting a local IP. (Hint: You might need to increase stack size for the task calling this function). - Integrate Diagnostics into Multi-Network Manager: Combine the diagnostic functions (
log_connected_ap_info
,log_ip_configuration
, detailed disconnect logging) into the multi-network connection logic developed in Chapter 36. Log detailed reasons ifattempt_connection
fails for a specific profile. Log RSSI and IP details upon final successful connection.
Summary
- Effective WiFi troubleshooting requires understanding the connection stages (Scan, Auth, Assoc, DHCP) and potential failure points.
- The
WIFI_EVENT_STA_DISCONNECTED
event provides crucial reason codes that help pinpoint the cause of disconnections. - Monitoring RSSI (
esp_wifi_sta_get_ap_info
) helps assess signal quality and diagnose range or interference issues. - Verifying the obtained IP configuration (
esp_netif_get_ip_info
) afterIP_EVENT_STA_GOT_IP
confirms successful DHCP operation. - The ESP-IDF logging system, especially with adjusted log levels and timestamps, is essential for tracing execution and observing driver behavior.
- Combining these techniques allows for systematic diagnosis of WiFi connectivity problems on ESP32 devices.
Further Reading
- ESP-IDF WiFi Library Documentation (Reason Codes): Check
esp_wifi_types.h
or the API guide section on WiFi events. https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/api-reference/network/esp_wifi.html - ESP-IDF Event Handling Documentation: https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/api-reference/system/esp_event.html
- ESP-IDF Logging Library Documentation: https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/api-reference/system/log.html
- ESP-IDF LwIP TCP/IP Stack (Netif): https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/api-reference/network/esp_netif.html