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:
  • AP out of range or powered off.
  • SSID is hidden and ESP32 not configured to scan for it.
  • Incorrect SSID specified in ESP32 configuration.
  • Radio interference on operating channels.
  • ESP32 antenna issue.
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:
  • Incorrect password/pre-shared key.
  • Unsupported security type by ESP32 or AP (e.g., WEP vs WPA2).
  • MAC address filtering enabled on the AP, and ESP32’s MAC is not whitelisted.
  • AP rejecting authentication due to internal error or policy.
  • Authentication timeout (AP not responding). See WIFI_REASON_AUTH_EXPIRE, WIFI_REASON_MIC_FAILURE, WIFI_REASON_AUTH_FAIL.
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:
  • AP has reached its maximum client capacity (WIFI_REASON_ASSOC_TOOMANY).
  • Configuration mismatch (e.g., data rates, channel capabilities).
  • Poor signal quality leading to request not being received or response lost.
  • AP policy or internal error.
  • Association timeout. See WIFI_REASON_ASSOC_EXPIRE, WIFI_REASON_ASSOC_FAIL.
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:
  • No DHCP server available or responding on the network.
  • DHCP server’s IP address pool is exhausted.
  • Network configuration issues preventing DHCP packets (e.g., VLAN, firewall).
  • Severe packet loss preventing DHCP handshake completion.
  • ESP32’s DHCP client issue (less common).
  • (Indicated by never receiving IP_EVENT_STA_GOT_IP after WIFI_EVENT_STA_CONNECTED).
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:
  • Signal strength drops too low (device moved, interference increased).
  • AP reboots or goes down.
  • ESP32 misses too many beacons (WIFI_REASON_BEACON_TIMEOUT).
  • AP explicitly disassociates/deauthenticates the ESP32 (e.g., due to inactivity, policy).
  • Interference from other devices.
%%{ 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 call esp_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 after WIFI_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. Use esp_log_level_set(TAG, LEVEL) to adjust levels dynamically or permanently via menuconfig.
  • 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.

C
// 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:

  1. Integrate this handler into a working WiFi station project (like from Chapter 27 or 36).
  2. Build, flash, and monitor.
  3. Test Cases:
    • Enter the wrong password for your network. Observe the disconnect reason (likely WIFI_REASON_MIC_FAILURE or WIFI_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).

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.

C
// 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:

  1. Add the log_connected_ap_info function and the call within the IP_EVENT_STA_GOT_IP handler.
  2. Build, flash, and monitor.
  3. Observe the RSSI value printed after a successful connection.
  4. 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 after WIFI_EVENT_STA_CONNECTED or, more reliably, after IP_EVENT_STA_GOT_IP.

3. Verifying IP Configuration

Create a function to log the IP details obtained via DHCP.

C
// 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:

  1. Add the log_ip_configuration function and the call within the IP_EVENT_STA_GOT_IP handler.
  2. Build, flash, and monitor.
  3. 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

  1. 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 call log_connected_ap_info() every 10 seconds to monitor signal strength over time. Ensure the task suspends itself or doesn’t run when disconnected.
  2. 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), attempt esp_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.
  3. 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“). Use esp_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).
  4. 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 if attempt_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) after IP_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

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top