846  Wi-Fi Implementation: ESP32 Basics

846.1 Learning Objectives

By the end of this chapter, you will be able to:

  • Configure ESP32 Station Mode: Connect ESP32 devices to existing Wi-Fi networks with proper error handling
  • Implement Access Point Mode: Create Wi-Fi hotspots for device configuration and local control
  • Scan Available Networks: Discover and analyze nearby Wi-Fi networks including security types
  • Handle Connection Events: Implement reconnection logic and status monitoring
  • Use SmartConfig Provisioning: Configure Wi-Fi credentials without hardcoding them

What is this chapter? Practical ESP32 Wi-Fi programming including station mode, access point mode, and network scanning.

When to use: - When building your first Wi-Fi-connected IoT device - When you need to configure Wi-Fi on ESP32/ESP8266 - Before implementing more complex Wi-Fi applications

Key Topics:

Topic Application
Station Mode Connect device to existing network
AP Mode Create device hotspot
Network Scanning Discover available networks
SmartConfig Provision credentials wirelessly

Prerequisites: - Wi-Fi fundamentals knowledge - Basic C/C++ programming - Understanding of TCP/IP basics

846.2 Prerequisites

Before diving into this chapter, you should be familiar with:

846.3 Hands-on: ESP32 Wi-Fi Configuration

Time: ~25 min | Level: Advanced | Code: P08.C36.U01

846.3.1 Basic Wi-Fi Connection

// ESP32 Wi-Fi Station Mode - Basic Connection
#include <Wi-Fi.h>

// Wi-Fi credentials
const char* ssid = "YourNetworkSSID";
const char* password = "YourPassword";

void setup() {
  Serial.begin(115200);
  delay(1000);

  // Connect to Wi-Fi
  Serial.println("Connecting to Wi-Fi...");
  Wi-Fi.mode(WIFI_STA);  // Station mode
  Wi-Fi.begin(ssid, password);

  // Wait for connection
  int attempts = 0;
  while (Wi-Fi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }

  if (Wi-Fi.status() == WL_CONNECTED) {
    Serial.println("\nWi-Fi connected!");
    Serial.print("IP address: ");
    Serial.println(Wi-Fi.localIP());
    Serial.print("MAC address: ");
    Serial.println(Wi-Fi.macAddress());
    Serial.print("Signal strength (RSSI): ");
    Serial.print(Wi-Fi.RSSI());
    Serial.println(" dBm");
  } else {
    Serial.println("\nFailed to connect to Wi-Fi");
  }
}

void loop() {
  // Check Wi-Fi connection status
  if (Wi-Fi.status() != WL_CONNECTED) {
    Serial.println("Wi-Fi disconnected! Reconnecting...");
    Wi-Fi.reconnect();
  }
  delay(10000);
}
WarningSecurity Note

These examples inline SSID/password for clarity. For production IoT, avoid hardcoding credentials: use a provisioning flow (BLE/SoftAP/SmartConfig as appropriate) and store credentials in NVS protected by flash encryption/secure boot where supported. See Wi-Fi Security and Provisioning.

TipInteractive Simulator: ESP32 Wi-Fi Connection

Try it yourself! See how ESP32 connects to Wi-Fi networks and retrieves network information.

What This Simulates: An ESP32 connecting to a Wi-Fi network in Station (STA) mode, displaying connection status, IP address, and signal strength.

How to Use: 1. Click Start Simulation 2. Watch the Serial Monitor show connection progress 3. Observe the Wi-Fi connection status LEDs 4. See the IP address assignment (DHCP) 5. Monitor signal strength (RSSI) readings 6. Try modifying credentials to see connection failures

NoteLearning Points

Observe: - Wi-Fi.mode(WIFI_STA): Sets ESP32 as Wi-Fi client (station mode) - Wi-Fi.begin(): Initiates connection to access point - Wi-Fi.status(): Returns connection state (WL_CONNECTED, WL_DISCONNECTED, etc.) - Wi-Fi.localIP(): Gets assigned IP address from DHCP server - Wi-Fi.macAddress(): Unique hardware identifier for the device - Wi-Fi.RSSI(): Received Signal Strength Indicator in dBm (-30 = excellent, -90 = weak)

Connection Process:

1. Scan for SSID
2. Associate with Access Point
3. Authenticate (WPA2/WPA3, depending on network)
4. DHCP request - Receive IP address
5. Connected! (WL_CONNECTED status)

RSSI Signal Strength Guide:

> -30 dBm : Excellent (very close to AP)
-30 to -67 dBm : Very Good
-67 to -70 dBm : Good
-70 to -80 dBm : Fair (usable but not ideal)
-80 to -90 dBm : Weak (connection drops likely)
< -90 dBm : Extremely weak (unusable)

Real-World Applications: - Smart Home Devices: Thermostats, lights, plugs connecting to home network - Sensor Networks: Environmental monitors sending data to local server - Industrial IoT: Factory sensors reporting to edge gateway - Building Automation: HVAC, lighting, security systems

Experiment: - Add retry logic with exponential backoff - Implement connection timeout handling - Create Wi-Fi signal strength monitor with alerts - Add multiple SSID fallback (try home Wi-Fi, then hotspot) - Implement provisioning and store Wi-Fi credentials in NVS (with encryption where supported)

846.3.2 Wi-Fi with Auto-Reconnect

// ESP32 Wi-Fi with Automatic Reconnection
#include <Wi-Fi.h>

const char* ssid = "YourSSID";
const char* password = "YourPassword";

void connectWiFi() {
  if (Wi-Fi.status() != WL_CONNECTED) {
    Serial.print("Connecting to Wi-Fi");
    Wi-Fi.begin(ssid, password);

    int timeout = 0;
    while (Wi-Fi.status() != WL_CONNECTED && timeout < 30) {
      delay(500);
      Serial.print(".");
      timeout++;
    }

    if (Wi-Fi.status() == WL_CONNECTED) {
      Serial.println("\nConnected!");
      Serial.println("IP: " + Wi-Fi.localIP().toString());
    } else {
      Serial.println("\nConnection failed!");
    }
  }
}

void setup() {
  Serial.begin(115200);

  // Configure Wi-Fi for low power
  Wi-Fi.mode(WIFI_STA);
  Wi-Fi.setAutoReconnect(true);
  Wi-Fi.persistent(false);  // Don't save Wi-Fi config to flash

  connectWiFi();
}

void loop() {
  // Your IoT logic here

  // Periodic connection check
  static unsigned long lastCheckMs = 0;
  if (millis() - lastCheckMs >= 30000) {  // Every 30 seconds
    lastCheckMs = millis();
    if (Wi-Fi.status() != WL_CONNECTED) {
      connectWiFi();
    }
  }
}

846.3.3 Wi-Fi Scanning (Find Available Networks)

// ESP32 Wi-Fi Network Scanner
#include <Wi-Fi.h>

void setup() {
  Serial.begin(115200);
  Wi-Fi.mode(WIFI_STA);
  Wi-Fi.disconnect();
  delay(100);

  Serial.println("Scanning Wi-Fi networks...");
}

void loop() {
  int n = Wi-Fi.scanNetworks();

  Serial.println("\n=== Wi-Fi Scan Results ===");
  if (n == 0) {
    Serial.println("No networks found");
  } else {
    Serial.printf("Found %d networks:\n", n);

    for (int i = 0; i < n; i++) {
      Serial.printf("%2d: %-32s ", i + 1, Wi-Fi.SSID(i).c_str());
      Serial.printf("(%3d dBm) ", Wi-Fi.RSSI(i));
      Serial.printf("CH:%2d ", Wi-Fi.channel(i));

      // Security type
      switch (Wi-Fi.encryptionType(i)) {
        case WIFI_AUTH_OPEN:
          Serial.print("[OPEN]");
          break;
        case WIFI_AUTH_WEP:
          Serial.print("[WEP]");
          break;
        case WIFI_AUTH_WPA_PSK:
          Serial.print("[WPA]");
          break;
        case WIFI_AUTH_WPA2_PSK:
          Serial.print("[WPA2]");
          break;
        case WIFI_AUTH_WPA_WPA2_PSK:
          Serial.print("[WPA/WPA2]");
          break;
#ifdef WIFI_AUTH_WPA2_WPA3_PSK
        case WIFI_AUTH_WPA2_WPA3_PSK:
          Serial.print("[WPA2/WPA3]");
          break;
#endif
#ifdef WIFI_AUTH_WPA3_PSK
        case WIFI_AUTH_WPA3_PSK:
          Serial.print("[WPA3]");
          break;
#endif
        case WIFI_AUTH_WPA2_ENTERPRISE:
          Serial.print("[WPA2-ENT]");
          break;
        default:
          Serial.print("[UNKNOWN]");
      }
      Serial.println();
    }
  }

  delay(10000);  // Scan every 10 seconds
}
TipInteractive Simulator: Wi-Fi Network Scanner

Try it yourself! See how ESP32 scans and discovers available Wi-Fi networks.

What This Simulates: An ESP32 performing Wi-Fi network scans to discover nearby access points, displaying SSID, signal strength, channel, and security type.

How to Use: 1. Click Start Simulation 2. Watch the Serial Monitor show discovered networks 3. Observe network details: SSID, RSSI (dBm), channel, security 4. See how scan results update periodically 5. Notice different security protocols (OPEN, WPA2, etc.)

NoteLearning Points

Observe: - Wi-Fi.scanNetworks(): Performs active scan, returns number of networks found - Wi-Fi.SSID(i): Network name (Service Set Identifier) - Wi-Fi.RSSI(i): Signal strength in dBm (closer to 0 = stronger) - Wi-Fi.channel(i): Operating channel (2.4 GHz: 1-11 US, 1-13 EU; 5 GHz varies by region) - Wi-Fi.encryptionType(i): Security protocol (OPEN, WEP, WPA, WPA2, WPA3)

Wi-Fi Channels (2.4 GHz):

Channels 1, 6, 11: Non-overlapping (recommended)
Channels 2-5, 7-10, 12-13: Overlapping (interference)

Channel Selection Impact:
- Overlapping channels = slower speeds, more interference
- Proper channel selection crucial for IoT device placement

Security Protocol Ranking:

OPEN: No encryption (never use for IoT!)
WEP: Broken encryption (obsolete)
WPA: Deprecated (TKIP weakness)
WPA2-PSK: Good (AES-CCMP encryption)
WPA2-Enterprise: Better (802.1X authentication)
WPA3: Best (SAE, forward secrecy)

Real-World Applications: - Smart Wi-Fi Configuration: Device discovers networks, presents list to user - Network Selection: Auto-connect to strongest known network - Site Survey: Analyze RF environment for optimal AP placement - Roaming: Switch between APs based on signal strength - Captive Portal Detection: Identify networks requiring web authentication

Experiment: - Implement β€œauto-connect to strongest known network” logic - Create Wi-Fi signal strength heat map - Add channel conflict detection (warn if multiple APs on same channel) - Filter networks by minimum RSSI threshold (-70 dBm) - Implement preferred network list with priorities

846.3.4 ESP32 as Access Point (Soft AP)

// ESP32 as Wi-Fi Access Point
#include <Wi-Fi.h>

const char* ap_ssid = "ESP32-IoT-AP";
const char* ap_password = "12345678";  // Min 8 characters

void setup() {
  Serial.begin(115200);

  // Configure Access Point
  Wi-Fi.softAP(ap_ssid, ap_password);

  IPAddress IP = Wi-Fi.softAPIP();
  Serial.println("Access Point Started");
  Serial.print("AP IP address: ");
  Serial.println(IP);
  Serial.print("AP SSID: ");
  Serial.println(ap_ssid);

  // Optional: Configure AP with more parameters
  // Wi-Fi.softAP(ssid, password, channel, hidden, max_connections)
  // Wi-Fi.softAP(ap_ssid, ap_password, 6, false, 4);
}

void loop() {
  // Check connected clients
  Serial.printf("Connected stations: %d\n", Wi-Fi.softAPgetStationNum());
  delay(5000);
}
TipInteractive Simulator: ESP32 Access Point Mode

Try it yourself! See how ESP32 creates its own Wi-Fi network that other devices can connect to.

What This Simulates: An ESP32 running as a Wi-Fi Access Point (Soft AP), allowing other devices to connect and displaying the number of connected clients.

How to Use: 1. Click Start Simulation 2. Watch the Serial Monitor show AP configuration 3. See the AP IP address (typically 192.168.4.1) 4. Observe connected station count updates 5. Notice the ESP32 becomes a Wi-Fi router!

NoteLearning Points

Observe: - Wi-Fi.softAP(): Creates a software-based access point - Default IP: 192.168.4.1 (ESP32 acts as DHCP server for clients) - Wi-Fi.softAPgetStationNum(): Returns number of connected devices - No Internet: Soft AP provides local network only (unless ESP32 also connects to WAN) - Dual Mode Possible: ESP32 can be both AP and Station simultaneously

Access Point Parameters:

Wi-Fi.softAP(ssid, password, channel, hidden, max_connections)

ssid: Network name (max 32 characters)
password: WPA2 password (8-64 characters, or empty for open network)
channel: Wi-Fi channel (2.4 GHz: 1-11 US, 1-13 EU; default: 1)
hidden: Hide SSID from scans (default: false)
max_connections: Maximum clients (1-4, default: 4)

Soft AP Configuration:

%%{init: {'theme': 'base', 'themeVariables': { 'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#ecf0f1', 'nodeBorder': '#2C3E50', 'clusterBkg': '#ecf0f1', 'clusterBorder': '#2C3E50', 'edgeLabelBackground':'#ffffff'}}}%%
graph TB
    ESP32["ESP32 Soft AP<br/>192.168.4.1"]
    Client1["Phone<br/>192.168.4.2"]
    Client2["Laptop<br/>192.168.4.3"]
    Client3["Tablet<br/>192.168.4.4"]

    ESP32 -.->|"SSID: ESP32-IoT-AP<br/>Password: &lt;setup password&gt;"| Client1
    ESP32 -.->|"DHCP Assigns IP"| Client2
    ESP32 -.->|"Wi-Fi Channels 1-11 (2.4 GHz)"| Client3

    style ESP32 fill:#2C3E50,stroke:#16A085,stroke-width:3px,color:#fff
    style Client1 fill:#E67E22,stroke:#2C3E50,stroke-width:2px
    style Client2 fill:#E67E22,stroke:#2C3E50,stroke-width:2px
    style Client3 fill:#E67E22,stroke:#2C3E50,stroke-width:2px

Figure 846.1: ESP32 SoftAP mode for local configuration with DHCP client assignment

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
stateDiagram-v2
    [*] --> IDLE: Power On

    IDLE --> SCANNING: Wi-Fi.begin()
    SCANNING --> ASSOCIATING: SSID Found
    SCANNING --> IDLE: Timeout/Not Found

    ASSOCIATING --> AUTHENTICATING: Association OK
    ASSOCIATING --> SCANNING: Association Failed

    AUTHENTICATING --> DHCP: Auth Success (WPA2/WPA3)
    AUTHENTICATING --> SCANNING: Wrong Password

    DHCP --> CONNECTED: IP Assigned
    DHCP --> SCANNING: DHCP Timeout

    CONNECTED --> IDLE: Wi-Fi.disconnect()
    CONNECTED --> SCANNING: Connection Lost
    CONNECTED --> CONNECTED: Data TX/RX

    note right of SCANNING
        Active scan for SSID
        Check all channels
    end note

    note right of CONNECTED
        WL_CONNECTED status
        Ready for HTTP/MQTT
    end note

    note left of AUTHENTICATING
        4-way handshake
        Key derivation
    end note

Figure 846.2: Wi-Fi connection lifecycle showing state transitions from power-on through scanning, authentication, DHCP, and connected states with error recovery paths.

Real-World Applications: - IoT Device Configuration: ESP32 creates temporary AP for initial setup - Smart bulbs, plugs use this for Wi-Fi provisioning - User connects to β€œESP32-Setup”, configures home Wi-Fi via web page - Local Control: Smart home devices create AP for direct control without router - Mesh Networks: Multiple ESP32s as repeaters extending coverage - Captive Portal: ESP32 AP redirects to config page (hotels, cafes) - Data Collection Points: ESP32 AP collects sensor data from nearby devices - Educational: Teaching networking without needing external router

Experiment: - Create captive portal with web server on 192.168.4.1 - Implement STA+AP mode: connect to home Wi-Fi AND create AP - Add web-based Wi-Fi credential configuration - Create mesh network with multiple ESP32s - Use a device-specific setup password; optionally add MAC filtering as defense-in-depth (not primary security)

846.3.5 Wi-Fi Provisioning (SmartConfig)

// ESP32 Wi-Fi Provisioning with SmartConfig
#include <Wi-Fi.h>

void setup() {
  Serial.begin(115200);
  Wi-Fi.mode(WIFI_STA);

  // Start SmartConfig
  Serial.println("Starting SmartConfig...");
  Serial.println("Use a SmartConfig-compatible app to provide Wi-Fi credentials");

  Wi-Fi.beginSmartConfig();

  // Wait for SmartConfig completion
  while (!Wi-Fi.smartConfigDone()) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nSmartConfig received!");
  Serial.println("Connecting to Wi-Fi...");

  // Wait for Wi-Fi connection
  while (Wi-Fi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nWi-Fi Connected!");
  Serial.print("IP Address: ");
  Serial.println(Wi-Fi.localIP());

  // Save credentials (optional)
  Serial.println("SSID: " + Wi-Fi.SSID());
}

void loop() {
  // Your application code
}

846.4 Raspberry Pi Wi-Fi Configuration

For a quick overview, see Wi-Fi Fundamentals and Standards. Below are CLI-first options commonly used in IoT deployments.

846.4.1 Option A: NetworkManager (nmcli)

sudo nmcli dev wifi list
sudo nmcli dev wifi connect "<SSID>" password "<PASSWORD>" ifname wlan0
ip -br a show wlan0
ping -c 3 1.1.1.1

846.4.2 Option B: wpa_supplicant (legacy / minimal images)

Edit /etc/wpa_supplicant/wpa_supplicant.conf:

country=US
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
  ssid="YourNetworkSSID"
  psk="YourPassword"
}

WPA2-Enterprise (example; validate server certificates):

network={
  ssid="Enterprise-Wi-Fi"
  key_mgmt=WPA-EAP
  eap=PEAP
  identity="username"
  password="password"
  ca_cert="/etc/ssl/certs/your_ca.pem"
  phase2="auth=MSCHAPV2"
}

Apply and verify:

sudo wpa_cli -i wlan0 reconfigure
sudo systemctl restart dhcpcd || true
ip -br a show wlan0
iw dev wlan0 link

846.4.3 Python Wi-Fi Client (MQTT over Wi-Fi)

# Python Wi-Fi-enabled MQTT IoT Sensor
import paho.mqtt.client as mqtt
import time
import random

# MQTT Configuration
MQTT_BROKER = "192.168.1.100"  # Local broker or cloud
MQTT_PORT = 1883
MQTT_TOPIC = "home/sensors/temperature"

# Callback signature for paho-mqtt 2.0+
def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code == 0:
        print("Connected to MQTT broker via Wi-Fi")
    else:
        print(f"Connection failed with reason code {reason_code}")

def on_publish(client, userdata, mid):
    print(f"Message {mid} published")

# Create MQTT client (paho-mqtt 2.0+ API)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="RaspberryPi-Sensor")
client.on_connect = on_connect
client.on_publish = on_publish

# Connect to broker
try:
    client.connect(MQTT_BROKER, MQTT_PORT, 60)
    client.loop_start()

    while True:
        # Simulate sensor reading
        temperature = round(20 + random.uniform(-5, 5), 2)

        # Publish to MQTT
        result = client.publish(MQTT_TOPIC, str(temperature))
        print(f"Published temperature: {temperature}C (QoS: {result.rc})")

        time.sleep(10)  # Publish every 10 seconds

except KeyboardInterrupt:
    print("\nDisconnecting...")
    client.loop_stop()
    client.disconnect()

846.5 Summary

This chapter covered the fundamentals of ESP32 Wi-Fi implementation:

  • Station Mode Configuration: Connecting ESP32 to existing Wi-Fi networks with connection handling, timeout management, and auto-reconnect logic
  • Access Point Mode: Creating ESP32-hosted Wi-Fi networks for device configuration, local control, and mesh networking
  • Network Scanning: Discovering available networks with SSID, RSSI, channel, and security information for network selection and site surveys
  • SmartConfig Provisioning: Wirelessly configuring Wi-Fi credentials without hardcoding them in firmware
  • Raspberry Pi Configuration: Using nmcli and wpa_supplicant for Linux-based IoT Wi-Fi setup

846.6 What’s Next

The next chapter covers Wi-Fi Power Optimization, exploring power-saving modes, deep sleep implementations, and battery life calculations for battery-powered Wi-Fi IoT devices.