
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:
| Mode | What It Does | Real-World Example |
|---|---|---|
| AP Mode | ESP32 creates WiFi network | Your home WiFi router |
| STA Mode | ESP32 connects to WiFi network | Your phone connecting to WiFi |
In STA mode:
- ESP32 scans for WiFi networks
- ESP32 connects to your home WiFi (like “Home-WiFi-123”)
- ESP32 gets internet access (can browse web, send data to cloud)
- 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 passwordCONFIG_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):
WIFI_AUTH_OPEN– No password (public WiFi)WIFI_AUTH_WEP– Old, insecure (don’t use!)WIFI_AUTH_WPA_PSK– WPA securityWIFI_AUTH_WPA2_PSK– WPA2 security (most common)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 connectstatic= 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 happenedevent_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:
- WiFi system has started
- Now try to connect to the WiFi network
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 groupWIFI_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 addressIP2STR()= 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:
esp_netif_init()– Initialize network interface systemesp_event_loop_create_default()– Create event systemesp_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 startedWIFI_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.aplike 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:
esp_wifi_set_mode(WIFI_MODE_STA)– Set WiFi to Station modeesp_wifi_set_config(WIFI_IF_STA, &wifi_config)– Apply our configurationesp_wifi_start()– Start WiFi!
After esp_wifi_start():
- WiFi hardware is running
WIFI_EVENT_STA_STARTevent 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
pdTRUEwould 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)
pdTRUEwould 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 = ...
bitscontains 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:
- Initialize NVS (storage) – same as AP mode
- Print “ESP_WIFI_MODE_STA” message
- Call
wifi_init_sta()to start WiFi connection - 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
| Feature | AP Mode | STA Mode |
|---|---|---|
| Role | Creates WiFi network | Connects to WiFi network |
| Like | WiFi router | Phone/laptop |
| Network interface | esp_netif_create_default_wifi_ap() | esp_netif_create_default_wifi_sta() |
| Configuration | .ap = { ... } | .sta = { ... } |
| Mode | WIFI_MODE_AP | WIFI_MODE_STA |
| Events | WIFI_EVENT_AP_STACONNECTED | WIFI_EVENT_STA_START<br>WIFI_EVENT_STA_DISCONNECTED<br>IP_EVENT_STA_GOT_IP |
| IP Address | Fixed (192.168.4.1) | Assigned by DHCP |
| Internet | No | Yes (if router has internet) |
| Event Group | Not used | Used 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:
- Wrong SSID (network name)
- Wrong password
- WiFi network is 5GHz (ESP32 only supports 2.4GHz)
- Network is out of range
- 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:
- Router has no internet connection
- 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:
- Combine AP + STA mode → ESP32 acts as both router AND connects to WiFi
- Make HTTP requests → Fetch data from websites/APIs
- Connect to MQTT broker → IoT communication
- Implement OTA updates → Update ESP32 firmware over WiFi
- Create a web server → Control ESP32 from browser
Comparison: When to Use Each Mode
| Use Case | Mode | Example |
|---|---|---|
| Connect to internet | STA | Weather station fetching data from API |
| Configuration portal | AP | First-time setup for smart device |
| Direct device control | AP | Control LED without router |
| IoT device with cloud | STA | Send sensor data to cloud server |
| Both local control AND cloud | AP+STA | Smart 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!