Skip to content

uPesy only delivers currently in France.

Contents Menu Expand Light mode Dark mode Auto light/dark mode

Connect to Wi-Fi networks with the ESP32

The WiFi.h library (installed automatically) will allow us to easily use the Wi-Fi features of the ESP32.

The ESP32 has 2 Wi-Fi modes:
  • STATION ( WIFI_STA ) : Station mode (STA) is used to connect the ESP32 module to a Wi-Fi access point (AP). The ESP32 behaves like a computer that would be connected to our AP. If the box is connected to the Internet, then the ESP32 can access the Internet too. The ESP32 can behave as a client , i.e., making requests to other devices connected on the network or as a server , i.e., other devices connected to the network will send requests to the ESP32. In both cases, the ESP32 can access the Internet.

  • AP (Access Point) ( WIFI_AP ) : In Access Point mode, the ESP32 behaves like a Wi-Fi network, like an AP: other devices can connect to it. In this mode, the ESP32 is not connected to any other network, and therefore the ESP32 is not connected to the Internet. This mode is more heavy computing and less power saving (the ESP32 board will heat up too) since the ESP32 must simulate a full Wi-Fi AP (Soft AP). Latency and throughput will be less good than with a classic Access Point.

Note

The ESP32 is by default in STATION mode.

Pour le choix du mode :
  • In general, STATION mode is used . We can access the Internet to retrieve API data, have a ‘home automation’ server with sensors,…

  • In general, AP mode is used temporarily to enter the credentials of the Wi-Fi AP (SSID and password) and then connect to it in STATION mode. You can also use it to have a network separated from your home network and not have Internet.

Connecting to a Wi-Fi Access Point

The code to connect to your AP is as follow:

#include <WiFi.h>

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

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

    WiFi.mode(WIFI_STA); //Optional
    WiFi.begin(ssid, password);
    Serial.println("\nConnecting");

    while(WiFi.status() != WL_CONNECTED){
        Serial.print(".");
        delay(100);
    }

    Serial.println("\nConnected to the WiFi network");
    Serial.print("Local ESP32 IP: ");
    Serial.println(WiFi.localIP());
}

void loop(){}

Hint

You have to modify "yourNetworkName" by the Wi-Fi AP name (SSID) and "yourNetworkPassword" by the AP password.

Terminal output

Connecting
 ................
 Connected to the WiFi network
 Local ESP32 IP: 192.168.43.129

Note

A simple way to have an AP to test the program is to share the Wi-Fi connection from your smartphone.

Le code fonctionne de la manière suivante :
  • We don’t forget to include the WiFi.h library.

  • Then we enter the Wi-Fi network name (SSID) and its password.

  • We put the ESP32 in STATION mode with the function WiFi.mode(WIFI_STA)

  • The ESP32 tries to connect to the Wi-Fi network using the function WiFi.begin (ssid, password)

  • Connection is not instant! We must regularly check the connection state: as long as the ESP32 is not connected to the network, we remain stuck in the while loop. We add a slight delay to avoid constantly check the status.

  • Once we are connected, we will display the local IP address of the ESP32 on this network.

If it is an open network (without a password), then the program is simplified:

#include <WiFi.h>

const char* ssid = "yourNetworkName";

void setup(){
Serial.begin(115200);
delay(1000);
WiFi.begin(ssid);
Serial.println("\nConnecting");

while(WiFi.status() != WL_CONNECTED){
    Serial.print(".");
    delay(100);
}

Serial.println("\nConnected to the WiFi network");
Serial.print("Local ESP32 IP: ");
Serial.println(WiFi.localIP());
}

void loop(){}

Get information on the Wi-Fi network

You can get information about the network once you are connected to it:
  • WiFi signal strength (RSSI) with the function WiFi.RSSI()

  • The WiFi network MAC address with WiFi.BSSIDstr() or WiFi.macAddress()

  • The local IP address of the ESP32 assigned by the DHCP server of the Wi-Fi network with WiFi.localIP()

  • The local IP address of the WiFi network (gateway) with WiFi.gatewayIP() (usually 192.168.0.1)

  • The subnet mask with WiFi.subnetMask() (usually 255.255.255.0)

The code below displays all of this information:

#include <WiFi.h>

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

void get_network_info(){
    if(WiFi.status() == WL_CONNECTED) {
        Serial.print("[*] Network information for ");
        Serial.println(ssid);

        Serial.println("[+] BSSID : " + WiFi.BSSIDstr());
        Serial.print("[+] Gateway IP : ");
        Serial.println(WiFi.gatewayIP());
        Serial.print("[+] Subnet Mask : ");
        Serial.println(WiFi.subnetMask());
        Serial.println((String)"[+] RSSI : " + WiFi.RSSI() + " dB");
        Serial.print("[+] ESP32 IP : ");
        Serial.println(WiFi.localIP());
    }
}

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

    WiFi.begin(ssid, password);
    Serial.println("\nConnecting");

    while(WiFi.status() != WL_CONNECTED){
        Serial.print(".");
        delay(100);
    }

    Serial.println("\nConnected to the WiFi network");
    get_network_info();
}

void loop(){}

Terminal output

Connecting
 ..............
 Connected to the WiFi network
 [*] Network information for HUAWEI _ **
 [+] BSSID: F0: 43: 47: 32: 1F: 4D
 [+] Gateway IP: 192.168.43.1
 [+] Subnet Mask: 255.255.255.0
 [+] RSSI: -25 dB
 [+] ESP32 IP: 192.168.43.129

Debug Wi-Fi connection issues

By monitoring connection status

You can know the WiFi connection status with the WiFi.status() function. This function returns an integer based on the current state of the connection.

The possible statuses are :
  • WL_IDLE_STATUS : This is the default status before trying to connect to a Wi-Fi network.

  • WL_SCAN_COMPLETED : The scan for Wi-Fi networks is complete.

  • WL_NO_SSID_AVAIL : The ESP32 cannot find the name of the Wi-Fi network. Either the network is too far from the ESP32, or the network name (SSID) is incorrect.

  • WL_CONNECT_FAILED : The ESP32 cannot connect to the designated Wi-Fi network.

  • WL_CONNECTION_LOST : The Wi-Fi connection to the network is lost. If this error is randomly repeated, it may be a problem with the ESP32 power supply.

  • WL_CONNECTED : The ESP32 is connected to the Wi-Fi network.

  • WL_DISCONNECTED : The ESP32 is disconnected from the Wi-Fi network.

Code used to display the status of the Wi-Fi connection.

#include <WiFi.h>

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

String get_wifi_status(int status){
    switch(status){
        case WL_IDLE_STATUS:
        return "WL_IDLE_STATUS";
        case WL_SCAN_COMPLETED:
        return "WL_SCAN_COMPLETED";
        case WL_NO_SSID_AVAIL:
        return "WL_NO_SSID_AVAIL";
        case WL_CONNECT_FAILED:
        return "WL_CONNECT_FAILED";
        case WL_CONNECTION_LOST:
        return "WL_CONNECTION_LOST";
        case WL_CONNECTED:
        return "WL_CONNECTED";
        case WL_DISCONNECTED:
        return "WL_DISCONNECTED";
    }
}

void setup(){
    Serial.begin(115200);
    delay(1000);
    int status = WL_IDLE_STATUS;
    Serial.println("\nConnecting");
    Serial.println(get_wifi_status(status));
    WiFi.begin(ssid, password);
    while(status != WL_CONNECTED){
        delay(500);
        status = WiFi.status();
        Serial.println(get_wifi_status(status));
    }

    Serial.println("\nConnected to the WiFi network");
    Serial.print("Local ESP32 IP: ");
    Serial.println(WiFi.localIP());
}

void loop(){}

Examples of possible scenarios

Successful connection case

Connecting
 WL_IDLE_STATUS
 WL_DISCONNECTED
 WL_DISCONNECTED
 WL_CONNECTED

 Connected to the WiFi network
 Local ESP32 IP: 192.168.43.129

SSID not found case

Connecting
 WL_IDLE_STATUS
 WL_DISCONNECTED
 WL_DISCONNECTED
 WL_NO_SSID_AVAIL
 WL_NO_SSID_AVAIL
 WL_NO_SSID_AVAIL
 WL_NO_SSID_AVAIL

Bad password case

Connecting
 WL_IDLE_STATUS
 WL_DISCONNECTED
 WL_DISCONNECTED
 WL_NO_SSID_AVAIL
 WL_NO_SSID_AVAIL
 WL_NO_SSID_AVAIL
 WL_NO_SSID_AVAIL

Restart the ESP32

Occasionally, for some unknown reason, the ESP32 may temporarily fail to connect to the Wi-Fi network. The best solution is to say that after n seconds if the ESP32 is still not connected to Wi-Fi, we restart the ESP32. You just need to add a timeout and use the ESP.restart() function to restart the ESP32 from the code.

If it’s still not connected to Wi-Fi, here is an example that restart the ESP32 after 10 s .

#include <WiFi.h>

#define CONNECTION_TIMEOUT 10

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

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

    WiFi.mode(WIFI_STA); //Optional
    WiFi.begin(ssid, password);
    Serial.println("\nConnecting");
    int timeout_counter = 0;

    while(WiFi.status() != WL_CONNECTED){
        Serial.print(".");
        delay(200);
        timeout_counter++;
        if(timeout_counter >= CONNECTION_TIMEOUT*5){
        ESP.restart();
        }
    }

    Serial.println("\nConnected to the WiFi network");
    Serial.print("Local ESP32 IP: ");
    Serial.println(WiFi.localIP());
}

void loop(){}

The ESP32 is reset after 10 s in the event of a connection failure from the code with the SW_CPU_RESET flag display in the boot debug output.

Connecting
 ..................................................  .....

 ets Jun 8 2016 00:22:57

 rst: 0xc (SW_CPU_RESET), boot: 0x13 (SPI_FAST_FLASH_BOOT)
 configsip: 0, SPIWP: 0xee
 clk_drv: 0x00, q_drv: 0x00, d_drv: 0x00, cs0_drv: 0x00, hd_drv: 0x00, wp_drv: 0x00
 mode: DIO, clock div: 1
 load: 0x3fff0018, len: 4
 load: 0x3fff001c, len: 1044
 load: 0x40078000, len: 8896
 load: 0x40080400, len: 5816
 entry 0x400806ac

 Connecting
 .......
 Connected to the WiFi network
 Local ESP32 IP: 192.168.43.129

Advance stuffs

Assign a fixed IP address

The local IP address of the ESP32 was assigned automatically by the AP’s DHCP server. This is convenient with a computer because you don’t have to manually configure an IP address. The downside (or advantage depending on the case) is that the IP address is dynamic. For example, this can become annoying if, as soon as you restart the ESP32 (or the DHCP lease has expired), the IP address could change while you have a web server running on the ESP32. It would be necessary each time to find the IP of the ESP32. This problem can be overcome by setting the IP address of the ESP32 on the network. For this, you must use the WiFi.config (ip, dns, gateway, subnet) function.

The required parameters are:
  • IP : The IP address you want to assign.

  • DNS : Service which makes the link between an URL and an IP. By default, we use the DNS server of the AP: we indicate the same IP address as the AP (generally 192.168.0.1).

  • GATEWAY : This is the IP address of the internet AP or router (generally 192.168.0.1)

  • SUBNET : Subnet mask (in general 255.255.255.0)

Note

You need to know the AP’s or router’s IP address: the easiest way is to use the code that displays the Wi-Fi network information in the serial monitor (generally 192.168.0.1)

In this example, using a phone’s Wi-Fi hotspot, the router’s IP address is 192.168.43.1 . I choose to have a static IP 192.168.43.42 for the ESP32.

Code that set a fixed IP address for the ESP32

#include <WiFi.h>

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

IPAddress ip(192, 168, 43, 42);
IPAddress dns(192, 168, 43, 1);
IPAddress gateway(192, 168, 43, 1);
IPAddress subnet(255, 255, 255, 0);

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

WiFi.config(ip, dns, gateway, subnet);
WiFi.begin(ssid, password);
Serial.println("\nConnecting");

while(WiFi.status() != WL_CONNECTED){
    Serial.print(".");
    delay(100);
}

Serial.println("\nConnected to the WiFi network");
Serial.print("[+] ESP32 IP : ");
Serial.println(WiFi.localIP());
}

void loop(){}

We can then ping from the computer to the IP 192.168.43.42 to see if the new IP address has been used:

Ping de l’ESP32 depuis le terminal Windows (cmd.exe)

Warning

Remember not to use an IP address already taken by another device on the network. You can also assign a fixed IP address linked to the MAC address directly from the router settings.

Change MAC address

In some applications, it may be interesting to change the MAC address of the ESP32. You can change the MAC address with a few lines of code using the function esp_wifi_set_mac()

Note

Changing the MAC address is temporary. It does not replace the original one. You just have to upload a new program to find the original MAC address.

#include <WiFi.h>
#include <esp_wifi.h>

uint8_t new_mac[] = {0x60, 0x8B, 0x0E, 0x01, 0x5A, 0x32};

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

    WiFi.mode(WIFI_STA);//Needed to change MAC adress
    Serial.print("[+] Current MAC Address:  ");
    Serial.println(WiFi.macAddress());

    esp_wifi_set_mac(ESP_IF_WIFI_STA, new_mac);

    Serial.print("[+] New MAC Address:  ");
    Serial.println(WiFi.macAddress());
}

void loop(){}

Serial terminal:

[+] Current MAC Address: 24: 6F: 28: BB: 2E: E8
 [+] New MAC Address: 60: 8B: 0E: 01: 5A: 32

Code that connects to a Wi-Fi network with a changed MAC address

#include <WiFi.h>
#include <esp_wifi.h>

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

uint8_t new_mac[] = {0x6C, 0x8D, 0xC1, 0x01, 0x5A, 0x32};

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

    WiFi.mode(WIFI_STA);//Needed to change MAC adress
    esp_wifi_set_mac(ESP_IF_WIFI_STA, new_mac);
    delay(1000);
    WiFi.begin(ssid, password);
    Serial.println("\nConnecting");

    while(WiFi.status() != WL_CONNECTED){
        Serial.print(".");
        delay(100);
    }

    Serial.println("\nConnected to the WiFi network");
    Serial.print("Local ESP32 IP: ");
    Serial.println(WiFi.localIP());
}

void loop(){}

A Wireshark capture shows that the address has been changed (here by an Apple MAC address):

Wireshark capture

Save energy

Suppose you are using an ESP32 in a project that must necessarily use Wi-Fi to work. In that case, it is a good idea to put the ESP32 in Deep Sleep mode in case of connection failure to minimize power consumption. It’s a code similar to this with the ESP32 ‘sleeping’ for 10 seconds between each attempt.

Code that puts the ESP32 in Deep Sleep between 2 connection attempts

#include <WiFi.h>
#include <esp_wifi.h>

//Time in seconds
#define CONNECTION_TIMEOUT 5
#define DEEP_SLEEP_DURATION 10

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

void setup(){
    Serial.begin(115200);
    WiFi.begin(ssid, password);
    Serial.println("\nConnecting");
    int timeout_counter = 0;

    while(WiFi.status() != WL_CONNECTED){
        Serial.print(".");
        delay(100);
        timeout_counter++;
            if(timeout_counter >= CONNECTION_TIMEOUT*10){
                Serial.println("\nCan't establish WiFi connexion");
                //Setup timer
                esp_sleep_enable_timer_wakeup(DEEP_SLEEP_DURATION * 1000000);
                //Start deep sleep
                esp_deep_sleep_start();
            }
    }
    Serial.println("\nConnected to the WiFi network");
    Serial.print("Local ESP32 IP: ");
    Serial.println(WiFi.localIP());
}

void loop(){}

Use Wi-Fi events to have optimized code

Until now, polling was made with the Wi-Fi functions. The ESP32 remains blocked until it receives an event (Event) by the Wi-Fi controller. Sequential programming was done. Let’s take an example :

while(WiFi.status() != WL_CONNECTED){
    Serial.print(".");
    delay(100);
}

We regularly poll if the ESP32 has managed to connect to the Wi-Fi network. We do nothing during the waiting (we could, however, make calculations between 2 polls) and remain blocked in the loop. Hard to navigate if we want to do different things depending on the status of Wi-Fi.

A cleaner way is to make Event programming using events. Indeed, events are generated when the WIFI changes state. The interest is that we can execute code automatically according to the received event. This is very similar to the interruptions that are used on the GPIO pines. A change of PIN status generates an interruption, which will execute a priority code portion. Here is a modification of a Wi-Fi state that causes an event that will also run a code portion.

The basic code for managing events is:

#include <WiFi.h>

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

void my_function(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info){
    //Code
}

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

    WiFi.mode(WIFI_STA); //Optional
    WiFi.onEvent(my_function, WIFI_EVENT_ID);

    WiFi.begin(ssid, password);
}

void loop(){}

The WiFi.onEvent(my_function, WIFI_EVENT_ID) function is used to specify which function will be executed when the WIFI_EVENT_ID event will be detected. It is necessary to replace WIFI_EVENT_ID with the name or number of the event (see table below).The function my_function() should have as parameters : WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info even if they are not used.

The following code does the same as the code at the very beginning to connect to a box, but this time with events when connected to a network.

Code that allows you to connect to a box with Wi-Fi events

#include <WiFi.h>

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

void connected_to_ap(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info){
    Serial.println("\nConnected to the WiFi network");
}

void got_ip_from_ap(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info){
    Serial.print("Local ESP32 IP: ");
Serial.println(WiFi.localIP());
}

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

    WiFi.mode(WIFI_STA); //Optional
    WiFi.onEvent(connected_to_ap, SYSTEM_EVENT_STA_CONNECTED);
    WiFi.onEvent(got_ip_from_ap, SYSTEM_EVENT_STA_GOT_IP);

    WiFi.begin(ssid, password);
    Serial.println("\nConnecting");
}

void loop(){}

Terminal output:

Connecting
 .............
 Connected to the WiFi network
 Local ESP32 IP: 192.168.43.167

The execution of the function related to an event can be removed while running the program with Wi-Fi.removeEvent (Wifi_Event_ID)

Practical use of events is the ability to automatically reconnect the ESP32 in case of disconnection.

#include <WiFi.h>

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";

void connected_to_ap(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info){
    Serial.println("[+] Connected to the WiFi network");
}

void disconnected_from_ap(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info){
    Serial.println("[-] Disconnected from the WiFi AP");
    WiFi.begin(ssid, password);
}

void got_ip_from_ap(WiFiEvent_t wifi_event, WiFiEventInfo_t wifi_info){
    Serial.print("[+] Local ESP32 IP: ");
    Serial.println(WiFi.localIP());
}

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

    WiFi.mode(WIFI_STA); //Optional
    WiFi.onEvent(connected_to_ap, SYSTEM_EVENT_STA_CONNECTED);
    WiFi.onEvent(got_ip_from_ap, SYSTEM_EVENT_STA_GOT_IP);
    WiFi.onEvent(disconnected_from_ap, SYSTEM_EVENT_STA_DISCONNECTED);

    WiFi.begin(ssid, password);
    Serial.println("\nConnecting");
}

void loop(){}

Terminal output:

Connecting
 [-] Disconnected from the WiFi AP
 [+] Connected to the WiFi network
 [+] Local ESP32 IP: 192.168.43.167
 [-] Disconnected from the WiFi AP
 [-] Disconnected from the WiFi AP
 [-] Disconnected from the WiFi AP
 [-] Disconnected from the WiFi AP
 [+] Connected to the WiFi network
 Local ESP32 IP: 192.168.43.167

Application: Wi-Fi Scan

Here is a concrete application that allows scanning the Wi-Fi networks around:

#include "WiFi.h"

String get_encryption_type(wifi_auth_mode_t encryptionType) {
    switch (encryptionType) {
        case (WIFI_AUTH_OPEN):
            return "Open";
        case (WIFI_AUTH_WEP):
            return "WEP";
        case (WIFI_AUTH_WPA_PSK):
            return "WPA_PSK";
        case (WIFI_AUTH_WPA2_PSK):
            return "WPA2_PSK";
        case (WIFI_AUTH_WPA_WPA2_PSK):
            return "WPA_WPA2_PSK";
        case (WIFI_AUTH_WPA2_ENTERPRISE):
            return "WPA2_ENTERPRISE";
    }
}

void setup(){
    Serial.begin(115200);
    WiFi.mode(WIFI_STA);
}

void loop() {
    Serial.println("uPesy WiFi Scan Demo");
    Serial.println("[*] Scanning WiFi network");

        // WiFi.scanNetworks will return the number of networks found
        int n = WiFi.scanNetworks();
        Serial.println("[*] Scan done");
        if (n == 0) {
            Serial.println("[-] No WiFi networks found");
        } else {
            Serial.println((String)"[+] " + n + " WiFi networks found\n");
            for (int i = 0; i < n; ++i) {
                // Print SSID, RSSI and WiFi Encryption for each network found
                Serial.print(i + 1);
                Serial.print(": ");
                Serial.print(WiFi.SSID(i));
                Serial.print(" (");
                Serial.print(WiFi.RSSI(i));
                Serial.print(" dB) [");
                Serial.print(get_encryption_type(WiFi.encryptionType(i)));
                Serial.println("]");
                delay(10);
            }
        }
        Serial.println("");

        // Wait a bit before scanning again
        delay(5000);
}

Program that scans Wi-Fi boxes

We use cookies to make your visit to the site as pleasant as possible. Privacy Policy