ESP32 (101) Station (STA) Mode

What You’ll Learn

This guide explains how to connect your ESP32 to an existing WiFi network (like your home WiFi). We’ll break down every single line of code so you understand exactly what’s happening.


What is Station Mode?

Station (STA) mode means your ESP32 acts like your phone or laptop – it connects to an existing WiFi network.

The Difference:

ModeWhat It DoesReal-World Example
AP ModeESP32 creates WiFi networkYour home WiFi router
STA ModeESP32 connects to WiFi networkYour phone connecting to WiFi

In STA mode:

  1. ESP32 scans for WiFi networks
  2. ESP32 connects to your home WiFi (like “Home-WiFi-123”)
  3. ESP32 gets internet access (can browse web, send data to cloud)
  4. ESP32 gets an IP address from your router (like 192.168.1.45)

Real-world analogy: Your phone connecting to Starbucks WiFi. Your phone is a “station” connecting to the Starbucks network.


Before We Start: New Concepts

What is an Event Group?

Think of it like a status board with light switches:

┌─────────────────────────────┐
│    WiFi Status Board        │
│                             │
│  [●] Connected    (ON)      │
│  [○] Failed       (OFF)     │
│  [○] Disconnected (OFF)     │
└─────────────────────────────┘
  • Each “switch” is called a bit
  • When WiFi connects, we turn ON the “Connected” bit
  • When WiFi fails, we turn ON the “Failed” bit
  • Our code waits and watches these bits to know what happened

Complete Code Breakdown

Part 1: Configuration Defines

#define EXAMPLE_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY  CONFIG_ESP_MAXIMUM_RETRY

What this means:

These get values from the project configuration menu (menuconfig):

  • CONFIG_ESP_WIFI_SSID → Your WiFi network name (like “Home-WiFi”)
  • CONFIG_ESP_WIFI_PASSWORD → Your WiFi password
  • CONFIG_ESP_MAXIMUM_RETRY → How many times to retry if connection fails (default: 5)

Alternative (hardcoded): You can also just write them directly:

#define EXAMPLE_ESP_WIFI_SSID      "MyHomeWiFi"
#define EXAMPLE_ESP_WIFI_PASS      "mypassword123"
#define EXAMPLE_ESP_MAXIMUM_RETRY  5

Part 2: Security Configuration (WPA3 Settings)

#if CONFIG_ESP_WPA3_SAE_PWE_HUNT_AND_PECK
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HUNT_AND_PECK
#define EXAMPLE_H2E_IDENTIFIER ""
#elif CONFIG_ESP_WPA3_SAE_PWE_HASH_TO_ELEMENT
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_HASH_TO_ELEMENT
#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID
#elif CONFIG_ESP_WPA3_SAE_PWE_BOTH
#define ESP_WIFI_SAE_MODE WPA3_SAE_PWE_BOTH
#define EXAMPLE_H2E_IDENTIFIER CONFIG_ESP_WIFI_PW_ID
#endif

What this is:

  • Advanced WPA3 security settings
  • WPA3 = Newest WiFi security standard (most secure)
  • SAE = Simultaneous Authentication of Equals
  • For beginners: You don’t need to understand this! It’s automatically configured.

Think of it like: Advanced car engine settings. You can drive the car without knowing how the fuel injection system works!


Part 3: Authentication Mode Threshold

#if CONFIG_ESP_WIFI_AUTH_OPEN
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN
#elif CONFIG_ESP_WIFI_AUTH_WEP
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP
#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK
#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK
// ... more options
#endif

What this means:

  • Sets the minimum security level required
  • ESP32 won’t connect to networks less secure than this

Security levels (from weakest to strongest):

  1. WIFI_AUTH_OPEN – No password (public WiFi)
  2. WIFI_AUTH_WEP – Old, insecure (don’t use!)
  3. WIFI_AUTH_WPA_PSK – WPA security
  4. WIFI_AUTH_WPA2_PSK – WPA2 security (most common)
  5. WIFI_AUTH_WPA3_PSK – WPA3 security (newest, most secure)

Real-world example: Like setting your phone to only connect to password-protected WiFi networks.


Part 4: Event Group and Status Bits

static EventGroupHandle_t s_wifi_event_group;

What this is:

  • Creates a handle (reference) to our event group
  • The “status board” we talked about earlier
  • static = Only visible in this file

Think of it like: Getting a TV remote control. The remote (handle) lets you control the TV (event group).


#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

What this means:

  • BIT0 = First switch on our status board (Connected)
  • BIT1 = Second switch on our status board (Failed)

Visual representation:

Status Board:
BIT0 (WIFI_CONNECTED_BIT): [○]  ← Connection successful
BIT1 (WIFI_FAIL_BIT):      [○]  ← Connection failed

When connection succeeds, BIT0 turns ON: [●][○] When connection fails, BIT1 turns ON: [○][●]


Part 5: Tag and Retry Counter

static const char *TAG = "wifi station";
static int s_retry_num = 0;

What this means:

  • TAG = Label for log messages (we’ve seen this before!)
  • s_retry_num = Counts how many times we’ve tried to connect
  • static = Variables only visible in this file

Why retry counter? If WiFi connection fails, we try again. But we don’t want to try forever!

  • Try 1: Failed → retry
  • Try 2: Failed → retry
  • Try 3: Failed → retry
  • Try 4: Failed → retry
  • Try 5: Failed → STOP (give up)

Part 6: The Event Handler Function

This is the BRAIN of the WiFi connection! Let’s break it down carefully:

static void event_handler(void* arg, esp_event_base_t event_base,
                          int32_t event_id, void* event_data)
{

Function parameters (same as AP mode):

  • arg = Extra arguments (not used)
  • event_base = Category of event (WIFI_EVENT or IP_EVENT)
  • event_id = Specific event that happened
  • event_data = Data about the event

Event 1: WiFi Started

if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
    esp_wifi_connect();
}

What happens:

  1. WiFi system has started
  2. Now try to connect to the WiFi network
  3. esp_wifi_connect() initiates the connection

Timeline:

ESP32 boots → WiFi starts → WIFI_EVENT_STA_START fires → esp_wifi_connect() called

Real-world analogy: You turn on your phone’s WiFi → Phone automatically tries to connect to known networks.


Event 2: WiFi Disconnected

else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
    if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
        esp_wifi_connect();
        s_retry_num++;
        ESP_LOGI(TAG, "retry to connect to the AP");
    } else {
        xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
    }
    ESP_LOGI(TAG,"connect to the AP fail");
}

What happens when disconnected:

Step 1: Check retry count

if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
  • Have we tried less than maximum retries? (e.g., tried 3 times, max is 5)
  • If YES → Try again
  • If NO → Give up

Step 2: If we can retry

esp_wifi_connect();      // Try connecting again
s_retry_num++;           // Increment counter (0→1, 1→2, etc.)
ESP_LOGI(TAG, "retry to connect to the AP");  // Print message

Output looks like:

[wifi station] retry to connect to the AP
[wifi station] retry to connect to the AP
[wifi station] retry to connect to the AP

Step 3: If we’ve exceeded retries

else {
    xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}

What this does:

  • xEventGroupSetBits() = Turn ON a bit in the event group
  • WIFI_FAIL_BIT = The “Failed” switch
  • Now our status board shows: [○][●] (Connected=OFF, Failed=ON)

Always prints:

ESP_LOGI(TAG,"connect to the AP fail");

This prints whether we’re retrying or giving up.


Event 3: Got 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;
    ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
    s_retry_num = 0;
    xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}

What happens when we get an IP:

Step 1: Extract IP address

ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
  • Get the IP information from the event data
  • Contains: IP address, netmask, gateway

Step 2: Print the IP address

ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
  • IPSTR = Format placeholder for IP address
  • IP2STR() = Convert IP to string format

Output looks like:

[wifi station] got ip:192.168.1.45

Step 3: Reset retry counter

s_retry_num = 0;
  • We’re connected now!
  • Reset counter back to 0 for next time

Step 4: Set the CONNECTED bit

xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
  • Turn ON the “Connected” switch
  • Status board now shows: [●][○] (Connected=ON, Failed=OFF)

Part 7: WiFi Initialization Function

This is where we set up everything!

void wifi_init_sta(void)
{

Step 1: Create Event Group

s_wifi_event_group = xEventGroupCreate();

What this does:

  • Creates the event group (our status board)
  • Now we can set and check bits (switches)

Think of it like: Installing the status board on the wall. Now we can start flipping switches!


Step 2: Initialize Network

ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();

Line by line:

  1. esp_netif_init() – Initialize network interface system
  2. esp_event_loop_create_default() – Create event system
  3. esp_netif_create_default_wifi_sta() – Create network interface for Station mode

What’s different from AP mode?

  • AP mode: esp_netif_create_default_wifi_ap() (creates AP interface)
  • STA mode: esp_netif_create_default_wifi_sta() (creates Station interface)

Step 3: Initialize WiFi

wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));

What this does:

  • Get default WiFi configuration
  • Initialize WiFi hardware with these settings

(Same as AP mode!)


Step 4: Register Event Handlers

This part is different from AP mode – we register TWO event handlers!

esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;

What these are:

  • Handles to store our event handler registrations
  • Like getting receipt numbers when you register for events

Handler 1: WiFi Events

ESP_ERROR_CHECK(esp_event_handler_instance_register(
    WIFI_EVENT,              // Listen for WiFi events
    ESP_EVENT_ANY_ID,        // ANY WiFi event
    &event_handler,          // Call this function
    NULL,                    // No extra arguments
    &instance_any_id         // Store registration handle
));

What events this catches:

  • WIFI_EVENT_STA_START – WiFi started
  • WIFI_EVENT_STA_DISCONNECTED – Disconnected from WiFi
  • Any other WiFi events

Handler 2: IP Events

ESP_ERROR_CHECK(esp_event_handler_instance_register(
    IP_EVENT,                // Listen for IP events
    IP_EVENT_STA_GOT_IP,     // Specifically: Got IP address
    &event_handler,          // Call this function
    NULL,                    // No extra arguments
    &instance_got_ip         // Store registration handle
));

Why separate?

  • WiFi connection and IP assignment are different events
  • You can be WiFi-connected but not have an IP yet!

Process:

1. WiFi connects       → WIFI_EVENT
2. DHCP assigns IP     → IP_EVENT (got IP)
3. NOW you're online!

Step 5: Configure WiFi Station Settings

wifi_config_t wifi_config = {
    .sta = {
        .ssid = EXAMPLE_ESP_WIFI_SSID,
        .password = EXAMPLE_ESP_WIFI_PASS,
        .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
        .sae_pwe_h2e = ESP_WIFI_SAE_MODE,
        .sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
    },
};

Let’s break this down:

wifi_config_t wifi_config = {
    .sta = {
  • Create WiFi configuration structure
  • .sta = We’re configuring Station mode (not .ap like before!)

.ssid = EXAMPLE_ESP_WIFI_SSID,
  • SSID = The WiFi network name to connect to
  • Example: “Home-WiFi-123” or “Starbucks”

.password = EXAMPLE_ESP_WIFI_PASS,
  • The WiFi password
  • If network is open (no password), leave this empty: ""

.threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
  • Minimum security level required
  • ESP32 won’t connect to networks less secure than this
  • Default: WIFI_AUTH_WPA2_PSK (WPA2)

What happens:

  • Your WiFi is WPA2 → ✅ Connect
  • Your WiFi is WEP (old, insecure) → ❌ Refuse to connect

.sae_pwe_h2e = ESP_WIFI_SAE_MODE,
.sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
  • Advanced WPA3 security settings
  • For beginners: Don’t worry about these!
  • They’re automatically configured for compatibility

Step 6: Set Mode and Configuration

ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());

Line by line:

  1. esp_wifi_set_mode(WIFI_MODE_STA) – Set WiFi to Station mode
  2. esp_wifi_set_config(WIFI_IF_STA, &wifi_config) – Apply our configuration
  3. esp_wifi_start() – Start WiFi!

After esp_wifi_start():

  • WiFi hardware is running
  • WIFI_EVENT_STA_START event fires
  • Event handler automatically calls esp_wifi_connect()
  • Connection process begins!

ESP_LOGI(TAG, "wifi_init_sta finished.");

Print confirmation message.


Step 7: Wait for Connection Result

This is the CRITICAL PART – we wait to see if connection succeeded or failed!

EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
        WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
        pdFALSE,
        pdFALSE,
        portMAX_DELAY);

What this function does:

  • WAITS (blocks) until one of the specified bits is set
  • Like waiting for a light to turn on

Parameters explained:

s_wifi_event_group          // Which event group to watch

The status board we created earlier.


WIFI_CONNECTED_BIT | WIFI_FAIL_BIT
  • Wait for EITHER bit to turn on
  • | means “OR”
  • Wake up when CONNECTED or FAILED

Visual:

Waiting...
Status Board: [○][○]

Connection succeeds → [●][○] → Wake up!
    OR
Connection fails → [○][●] → Wake up!

pdFALSE  // Don't clear bits on exit
  • After waking up, leave the bits as they are
  • pdTRUE would turn them off automatically

pdFALSE  // Wait for ANY bit (not ALL bits)
  • We want to wake up when ANY bit is set (CONNECTED or FAILED)
  • pdTRUE would wait for ALL bits (CONNECTED and FAILED – impossible!)

portMAX_DELAY  // Wait forever
  • No timeout – wait as long as it takes
  • Alternative: Could specify timeout like pdMS_TO_TICKS(10000) for 10 seconds

What gets returned:

EventBits_t bits = ...
  • bits contains the current status of all bits
  • We can check which bits are set

Step 8: Check Connection Result

if (bits & WIFI_CONNECTED_BIT) {
    ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}

What bits & WIFI_CONNECTED_BIT means:

  • & is a bitwise AND operation
  • Checks if WIFI_CONNECTED_BIT is ON

If connected:

  • Print success message with SSID and password

Output:

[wifi station] connected to ap SSID:Home-WiFi password:mypassword123

else if (bits & WIFI_FAIL_BIT) {
    ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}

If failed:

  • Print failure message

Output:

[wifi station] Failed to connect to SSID:Home-WiFi, password:wrongpassword

else {
    ESP_LOGE(TAG, "UNEXPECTED EVENT");
}

This should never happen!

  • ESP_LOGE = Print ERROR level message
  • If we get here, something went wrong with the event system

Part 8: The app_main() Function

void app_main(void)
{
    // Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta();
}

What happens:

  1. Initialize NVS (storage) – same as AP mode
  2. Print “ESP_WIFI_MODE_STA” message
  3. Call wifi_init_sta() to start WiFi connection
  4. Function blocks at xEventGroupWaitBits() until connected or failed

Complete Execution Flow

Let’s trace what happens when you run this code:

Timeline Diagram

1. ESP32 boots
   ↓
2. app_main() starts
   ↓
3. NVS initialized
   ↓
4. wifi_init_sta() called
   ↓
5. Event group created
   ↓
6. Network interface initialized
   ↓
7. Event handlers registered
   ↓
8. WiFi configured (SSID, password)
   ↓
9. WiFi started → WIFI_EVENT_STA_START fires
   ↓
10. Event handler calls esp_wifi_connect()
    ↓
11. ESP32 scans for WiFi network
    ↓
    ┌─────────────┬─────────────┐
    │ Found?      │ Not found?  │
    ↓             ↓
12a. Connect    12b. WIFI_EVENT_STA_DISCONNECTED
    ↓                ↓
13a. Authenticate   13b. Retry (up to max retries)
    ↓                ↓
14a. Get IP (DHCP)  14c. Max retries → Set WIFI_FAIL_BIT
    ↓                ↓
15a. IP_EVENT_STA_GOT_IP fires   15b. Wake up from wait
    ↓                ↓
16a. Set WIFI_CONNECTED_BIT   16b. Print "Failed to connect"
    ↓
17a. Wake up from wait
    ↓
18a. Print "connected to ap..."
    ↓
19. Continue program (you can now use internet!)

Detailed Event Flow Example

Scenario 1: Successful Connection

[wifi station] ESP_WIFI_MODE_STA
[wifi station] wifi_init_sta finished.

← Waiting at xEventGroupWaitBits() ←

[Event] WIFI_EVENT_STA_START
  → event_handler() calls esp_wifi_connect()

[Event] Scanning for "Home-WiFi"...
[Event] Found network!
[Event] Connecting...
[Event] Authenticating...
[Event] IP_EVENT_STA_GOT_IP
  → event_handler() prints IP
  → Sets WIFI_CONNECTED_BIT

[wifi station] got ip:192.168.1.45

← xEventGroupWaitBits() wakes up ←

[wifi station] connected to ap SSID:Home-WiFi password:mypass123

Scenario 2: Failed Connection (Wrong Password)

[wifi station] ESP_WIFI_MODE_STA
[wifi station] wifi_init_sta finished.

← Waiting at xEventGroupWaitBits() ←

[Event] WIFI_EVENT_STA_START
  → event_handler() calls esp_wifi_connect()

[Event] WIFI_EVENT_STA_DISCONNECTED (authentication failed)
  → s_retry_num = 1
[wifi station] retry to connect to the AP
[wifi station] connect to the AP fail

[Event] WIFI_EVENT_STA_DISCONNECTED
  → s_retry_num = 2
[wifi station] retry to connect to the AP
[wifi station] connect to the AP fail

[Event] WIFI_EVENT_STA_DISCONNECTED
  → s_retry_num = 3
[wifi station] retry to connect to the AP
[wifi station] connect to the AP fail

[Event] WIFI_EVENT_STA_DISCONNECTED
  → s_retry_num = 4
[wifi station] retry to connect to the AP
[wifi station] connect to the AP fail

[Event] WIFI_EVENT_STA_DISCONNECTED
  → s_retry_num = 5 (max reached!)
  → Sets WIFI_FAIL_BIT
[wifi station] connect to the AP fail

← xEventGroupWaitBits() wakes up ←

[wifi station] Failed to connect to SSID:Home-WiFi, password:wrongpass

Key Differences: AP vs STA Mode

FeatureAP ModeSTA Mode
RoleCreates WiFi networkConnects to WiFi network
LikeWiFi routerPhone/laptop
Network interfaceesp_netif_create_default_wifi_ap()esp_netif_create_default_wifi_sta()
Configuration.ap = { ... }.sta = { ... }
ModeWIFI_MODE_APWIFI_MODE_STA
EventsWIFI_EVENT_AP_STACONNECTEDWIFI_EVENT_STA_START<br>WIFI_EVENT_STA_DISCONNECTED<br>IP_EVENT_STA_GOT_IP
IP AddressFixed (192.168.4.1)Assigned by DHCP
InternetNoYes (if router has internet)
Event GroupNot usedUsed to wait for connection

Important Concepts Explained

What is Event Group?

Simple explanation: A set of flags (bits) that can be turned on/off, and you can wait for specific flags.

Code example:

// Create event group
EventGroupHandle_t my_events = xEventGroupCreate();

// Set a bit (turn on flag)
xEventGroupSetBits(my_events, BIT0);

// Wait for a bit
EventBits_t bits = xEventGroupWaitBits(my_events, BIT0, ...);

// Check if bit is set
if (bits & BIT0) {
    printf("BIT0 is ON!\n");
}

Real-world analogy: Like waiting at a traffic light. You wait (block) until the light turns green (bit is set), then you proceed.


What is Bitwise AND (&)?

if (bits & WIFI_CONNECTED_BIT)

What this does: Checks if a specific bit is ON.

How it works:

bits =              00000011  (both BIT0 and BIT1 are ON)
WIFI_CONNECTED_BIT = 00000001  (BIT0)
                    --------
Result =            00000001  (non-zero = true!)

bits =              00000010  (only BIT1 is ON)
WIFI_CONNECTED_BIT = 00000001  (BIT0)
                    --------
Result =            00000000  (zero = false!)

Think of it like: Checking if a specific switch on a control panel is flipped on.


Why Two Event Handlers?

// Handler 1: WiFi events
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, ...);

// Handler 2: IP events
esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, ...);

Because:

  • WiFi connection and IP assignment are separate processes
  • WiFi might connect but DHCP could fail
  • We want to handle both types of events in the same function

Process:

Step 1: WiFi connects        → WIFI_EVENT
Step 2: Request IP from DHCP → (waiting)
Step 3: Receive IP           → IP_EVENT

What is DHCP?

DHCP = Dynamic Host Configuration Protocol

What it does: Automatically gives your device:

  • IP address (192.168.1.45)
  • Subnet mask (255.255.255.0)
  • Gateway (192.168.1.1)
  • DNS servers

Without DHCP:

// You'd have to manually configure:
IP:      192.168.1.45
Netmask: 255.255.255.0
Gateway: 192.168.1.1
DNS:     8.8.8.8

With DHCP:

// Automatic! Router assigns everything
esp_wifi_connect();
// ... wait ...
// Got IP: 192.168.1.45 (automatically!)

What Happens After Connection?

Once connected, your ESP32 can:

1. Access the Internet

// Make HTTP requests
esp_http_client_config_t config = {
    .url = "http://example.com",
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_perform(client);

2. Connect to Cloud Services

// MQTT, AWS IoT, Google Cloud, etc.
mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(mqtt_client);

3. Make Local Network Requests

// Communicate with other devices on the same WiFi
// Example: Control smart home devices

Common Issues and Troubleshooting

Issue 1: “Failed to connect”

Possible causes:

  1. Wrong SSID (network name)
  2. Wrong password
  3. WiFi network is 5GHz (ESP32 only supports 2.4GHz)
  4. Network is out of range
  5. Router has MAC filtering enabled

How to fix:

// Double-check your configuration:
#define EXAMPLE_ESP_WIFI_SSID      "YourExactNetworkName"
#define EXAMPLE_ESP_WIFI_PASS      "YourExactPassword"

Issue 2: Connects but no internet

Possible causes:

  1. Router has no internet connection
  2. ESP32 needs to accept terms of service (captive portal)

Check:

// After connection, try pinging Google:
ping 8.8.8.8

Issue 3: “retry to connect” loops forever

Cause: Maximum retries not reached, but connection keeps failing

Solution: Check the retry counter logic


Issue 4: ESP32 supports only 2.4GHz

Important: ESP32 cannot connect to 5GHz WiFi networks!

Check your router:

  • Make sure you’re using the 2.4GHz network
  • Often routers have separate SSIDs: “Home-WiFi-2.4” and “Home-WiFi-5”
  • Or check router settings to see which band the network uses

Testing the Code

Step 1: Configure WiFi Credentials

Option A: Using menuconfig

idf.py menuconfig
# Navigate to: Example Connection Configuration
# Set WiFi SSID and Password

Option B: Hardcode in the file

#define EXAMPLE_ESP_WIFI_SSID      "MyHomeWiFi"
#define EXAMPLE_ESP_WIFI_PASS      "mypassword123"
#define EXAMPLE_ESP_MAXIMUM_RETRY  5

Step 2: Build and Flash

idf.py build
idf.py flash

Step 3: Monitor Output

idf.py monitor

Expected output (success):

[wifi station] ESP_WIFI_MODE_STA
[wifi station] wifi_init_sta finished.
[wifi station] got ip:192.168.1.45
[wifi station] connected to ap SSID:MyHomeWiFi password:mypassword123

Expected output (failure):

[wifi station] ESP_WIFI_MODE_STA
[wifi station] wifi_init_sta finished.
[wifi station] retry to connect to the AP
[wifi station] connect to the AP fail
[wifi station] retry to connect to the AP
[wifi station] connect to the AP fail
[wifi station] Failed to connect to SSID:MyHomeWiFi, password:wrongpass

Code Structure Summary

app_main()
├─ Initialize NVS
└─ wifi_init_sta()
    ├─ Create event group
    ├─ Initialize network
    ├─ Initialize WiFi
    ├─ Register event handlers
    │   ├─ WiFi events → event_handler()
    │   └─ IP events → event_handler()
    ├─ Configure WiFi (SSID, password)
    ├─ Start WiFi
    └─ Wait for connection
        ├─ Success → Print "connected"
        └─ Failure → Print "Failed to connect"

event_handler()
├─ WIFI_EVENT_STA_START
│   └─ Call esp_wifi_connect()
├─ WIFI_EVENT_STA_DISCONNECTED
│   ├─ If retries left → Try again
│   └─ If max retries → Set WIFI_FAIL_BIT
└─ IP_EVENT_STA_GOT_IP
    ├─ Print IP address
    └─ Set WIFI_CONNECTED_BIT

Quick Reference

Event Flow

1. Start WiFi
2. WIFI_EVENT_STA_START → Connect
3. WIFI_EVENT_STA_DISCONNECTED → Retry or Fail
4. IP_EVENT_STA_GOT_IP → Success!

Event Bits

WIFI_CONNECTED_BIT (BIT0) → Connection successful
WIFI_FAIL_BIT (BIT1) → Connection failed

Key Functions

esp_wifi_connect()              // Start connection attempt
xEventGroupCreate()             // Create event group
xEventGroupSetBits()            // Turn on a bit
xEventGroupWaitBits()           // Wait for bit(s)

Your First Modification Challenge!

Challenge 1: Change WiFi Credentials

Try connecting to a different WiFi network:

#define EXAMPLE_ESP_WIFI_SSID      "YourOtherNetwork"
#define EXAMPLE_ESP_WIFI_PASS      "differentpassword"

Challenge 2: Increase Retry Count

Make it try 10 times instead of 5:

#define EXAMPLE_ESP_MAXIMUM_RETRY  10

Challenge 3: Add More Logging

Add a print statement when WiFi starts:

if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
    ESP_LOGI(TAG, "WiFi started, attempting to connect...");
    esp_wifi_connect();
}

Challenge 4: Do Something After Connection

Add code after the connection check:

if (bits & WIFI_CONNECTED_BIT) {
    ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
             EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    
    // YOUR CODE HERE
    ESP_LOGI(TAG, "I'm now connected to the internet!");
    // Maybe start a web server, connect to MQTT, etc.
}

Next Steps

After understanding STA mode, you can:

  1. Combine AP + STA mode → ESP32 acts as both router AND connects to WiFi
  2. Make HTTP requests → Fetch data from websites/APIs
  3. Connect to MQTT broker → IoT communication
  4. Implement OTA updates → Update ESP32 firmware over WiFi
  5. Create a web server → Control ESP32 from browser

Comparison: When to Use Each Mode

Use CaseModeExample
Connect to internetSTAWeather station fetching data from API
Configuration portalAPFirst-time setup for smart device
Direct device controlAPControl LED without router
IoT device with cloudSTASend sensor data to cloud server
Both local control AND cloudAP+STASmart home hub

Congratulations! 🎉

You now understand:

  • ✅ How ESP32 connects to WiFi networks (STA mode)
  • ✅ How event handlers work with multiple event types
  • ✅ How event groups are used for synchronization
  • ✅ The difference between WiFi connection and IP assignment
  • ✅ How retry logic works
  • ✅ How to wait for asynchronous events

This is the foundation for building internet-connected IoT projects with ESP32!

Leave a Reply

Your email address will not be published.