ESP32 ESP-IDF Connect with WiFi – Station Mode Example

In this user guide, we will learn to set up ESP32 in Station (STA) mode using ESP-IDF. In other words, we will see how to make WiFi connection and connect with an access point using esp-idf Wi-Fi drivers. This guide includes the explanations of the necessary APIs required for W-Fi connection, details about the Wi-Fi driver, and an example sketch for ESP-IDF demonstrating the ESP32 board connecting to the wireless network.

We also have a guide to set ESP3 in station mode:

Before we move ahead, make sure you have the latest version of VS Code installed on your system with the ESP-IDF extension configured.

ESP32 ESP-IDF Wi-Fi APIs

Let’s first discuss some important functions that are required to connect the ESP32 with Wi-Fi. ESP-IDF provides esp_wifi.h library that is used to setup and monitor the working of the ESP32 Wi-Fi network. This includes configuration of both Access point and Wi-Fi station modes of ESP32 in various security modes e.g. WPA, WEP, etc., monitoring of Wi-Fi packets and scanning nearby access points.

In this guide, we will focus on how to connect our ESP32 board to an access point by configuring it in station mode which is also known as STA mode/ Wi-Fi client mode. Let’s see how it will be accomplished. 

The first step is to include the header file:

#include "esp_wifi.h"

Configuration

We start off by initializing the Wi-Fi allocate resource for the Wi-Fi driver. It is responsible for initiating the Wi-Fi task.

esp_wifi_init(const wifi_init_config_t *config)

It takes in a single parameter config which is a pointer to the already initialized Wi-Fi configuration structure. We usually set the Wi-Fi configuration structure to WIFI_INIT_CONFIG_DEFAULT() so that the initialization of the configuration is at default values. This is shown below:

wifi_init_config_t wifi_config = WIFI_INIT_CONFIG_DEFAULT();

Here wifi_init_config_t is a structure that denotes the Wi-Fi stack configuration parameters that are passed inside the esp_wifi_init() function.

Next up, we will set the mode of Wi-Fi. As mentioned earlier, this ESP-IDF Wi-Fi library enables multiple operating modes of Wi-Fi. To set the Wi-Fi mode, we use the function esp_wifi_set_mode() and pass the Wi-Fi mode as a parameter inside it. By default, the mode is set to station. We can set the mode to station, soft-AP or both (station + soft-AP). The parameter can take either of the three values:

  • WIFI_MODE_STA (for station mode)
  • WIFI_MODE_AP (for soft-AP mode)
  • WIFI_MODE_APSTA (for station + soft-AP mode)
esp_wifi_set_mode(wifi_mode_t mode)

Start Wi-Fi

In order to start the Wi-Fi connection at the set configuration, we call the function esp_wifi_start(). According to the configured mode, it first creates its control block and then initiates the mode.

esp_wifi_start(void)

Finally, to connect the ESP32 board set as a station with an access point, we use the function esp_wifi_connect(). This function is only applicable if the configured mode is station or station + soft-AP.

esp_wifi_connect(void)

Features of ESP32 Wi-Fi

The ESP32 Wi-Fi supports four virtual Wi-Fi interfaces that include STA ,AP, Sniffer and reserved. Moreover, the ESP32 board can be configured in three modes that include station mode, soft-AP mode and both station and soft-AP mode together. Below we have stated some more features of ESP32 Wi-Fi.

  • The ESP-NOW protocol and Long Range mode supports a maximum of 1 km of data traffic.
  • It has a maximum of 20 MBit/s TCP throughput over the air.
  • Additionally, it features a maximum of 30 MBit/s UDP throughput over the air.
  • Coupled with various security standards including WPA/WPA2/WPA3/WPA2-Enterprise/WPA3-Enterprise/WAPI/WPS and DPP.
  • IEEE 802.11b, IEEE 802.11g, IEEE 802.11n, and APIs to configure the protocol mode.
  • AMSDU, AMPDU, HT40, QoS, modem sleep, multiple antennas.

ESP32 Wi-Fi Station Connection

Lets now discuss the process of how the ESP32 board connects with the Wi-Fi station which involves a total of 4 phases.

  • Scan Phase
  • Auth Phase
  • Association Phase
  • Four-way Handshake Phase

Let us briefly discuss these phases.

Scan Phase

s1.1: At this point the Wi-Fi driver starts to scan the configure AP. This is when esp_wifi_connect() is called.

s1.2: When the target AP is not found during the scan, the Wi-Fi event: WIFI_EVENT_STA_DISCONNECTED will occur. This results in the Wi-Fi reason code: WIFI_EVENT_STA_DISCONNECTED.

Auth Phase

s2.1: The auth phase starts with the authentication request which is sent and eventually the auth timer gets started to monitor the request.

s2.2: The Wi-Fi event: WIFI_EVENT_STA_DISCONNECTED will occur, if the auth timer runs out and the authentication response packet is still not received yet. This results in the Wi-Fi reason code: WIFI_REASON_AUTH_EXPIRE.

s2.3: At this stage, the auth timer stops, once the auth response packet is received.

s2.4: In this case, the AP does not accept the auth response packet which causes the Wi-Fi event: WIFI_EVENT_STA_DISCONNECTED to occur. This results in the Wi-Fi reason code: WIFI_REASON_AUTH_FAIL.

Association Phase

s3.1: This stage starts when the association request is sent which enables the association timer.

s3.2: The Wi-Fi event: WIFI_EVENT_STA_DISCONNECTED will occur, if the association timer runs out and the association response packet is still not received yet. This results in the Wi-Fi reason code: WIFI_REASON_ASSOC_EXPIRE.

s3.3: At this stage, the association timer stops, once the association response packet is received.

s3.4: In this case, the AP does not accept the association response packet which causes the Wi-Fi event: WIFI_EVENT_STA_DISCONNECTED to occur. This results in the Wi-Fi reason code: WIFI_REASON_AUTH_FAIL.

Four-way Handshake Phase

s4.1: In this case, once the handshake is initiated and the handshake timer runs out while the 1/4 EAPOL is not received then the Wi-Fi event: WIFI_EVENT_STA_DISCONNECTED occurs. This results in the Wi-Fi reason code: WIFI_REASON_HANDSHAKE_TIMEOUT.

s4.2: At this stage, the 1/4 EAPOL is acquired.

s4.3: At this point, the station sends a reply 2/4 EAPOL.

s4.4: In this case, the Wi-Fi event: WIFI_EVENT_STA_DISCONNECTED occurs when the 3/4 EAPOL is not received within the handshake timer timeout. This results in the Wi-Fi reason code: WIFI_REASON_HANDSHAKE_TIMEOUT.

s4.5: At this stage, the 3/4 EAPOL is acquired.

s4.6: At this point, the station sends a reply 4/4 EAPOL.

s4.7: The Wi-Fi event: WIFI_EVENT_STA_CONNECTED occurs.

ESP32 Station Mode Example with ESP-IDF

In station mode, the ESP32 board connects to a Wi-Fi network through a router. We use a router to connect ESP32 boards to get access to the local network. The ESP32 module acts as a station client and the router is set up as an access point.

Create Example Project

Open your VS Code and head over to View > Command Palette. Type ESP-IDF: New Project in the search bar and press enter.

Specify the project name and directory. We have named our project ‘ESP_IDF_WIFI_STA.’ For the ESP-IDF board, we have chosen the custom board option. For ESP-IDF target, we have chosen ESP32 module. Click ‘Choose Template’ button to proceed forward.

Create ESP-IDF ESP32 Wi-Fi STA Project

In the Extension, select ESP-IDF option:

ESP-IDF in VS Code New Project 2

We will click the ‘station’ under the getting_started tab for wifi. Now click ‘Create project using template station.’

Create ESP-IDF ESP32 Wi-Fi Project 2

You will get a notification that the project has been created. To open the project in a new window, click ‘Yes.’

This opens our ESP_IDF_WIFI_STA project that we created inside the EXPLORER tab. There are several folders inside our project folder. This is the same for every project which you will create through ESP-IDF Explorer. The main folder contains the source code meaning the main.c file will be found here.

Go to main > station_example_main.c and open it.

Create ESP-IDF ESP32 Wi-Fi Project 3

The following code opens up which is shown below. This example focuses on the functions of the Wi-Fi station to connect to an AP.

ESP32 connect to Wi-Fi (Station Mode) Code

/* WiFi station Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"

/* The examples use WiFi configuration that you can set via project configuration menu

   If you'd rather not, just change the below entries to strings with
   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/

#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

/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

static const char *TAG = "wifi station";

static int s_retry_num = 0;

static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } 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");
    } 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);
    }
}

void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

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

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Setting a password implies station will connect to all security modes including WEP/WPA.
             * However these modes are deprecated and not advisable to be used. Incase your Access point
             * doesn't support WPA2, these mode can be enabled by commenting below line */
	     .threshold.authmode = WIFI_AUTH_WPA2_PSK,
        },
    };
    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() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } 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);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }

    /* The event will not be processed after unregister */
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
    vEventGroupDelete(s_wifi_event_group);
}

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();
}

Make sure to define the following variables with your own parameters. You will have to specify your Wi-Fi network’s SSID and password, inside double quotation marks. Moreover, you can also set the maximum retry time although it is set as 5 (default).

#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

How the Code Works?

Firstly, we will start by including the necessary libraries that includes the FreeRTOS libraries to generate delays, create tasks and event groups. The esp_wifi.h to enable Wi-Fi connectivity, esp_event.h to monitor the Wi-Fi events and esp_log.h as the logging library.

#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"

Define the SSID and password of your network that the ESP32 board will connect to. In our case we have specifies the SSID as “PTCL-08” and password as “44332211.”

#define EXAMPLE_ESP_WIFI_SSID      "PTCL-08"
#define EXAMPLE_ESP_WIFI_PASS      "44332211"

Additionally, we have defined the maximum retry number as 10.

#define EXAMPLE_ESP_MAXIMUM_RETRY  10

Next, we declare a variable ‘s_wifi-event_group’ to hold the created FreeRTOS event group. This FreeRTOS event group is used to signal when we are connected to Wi-Fi.

static EventGroupHandle_t s_wifi_event_group;

Then we define two bits for the Wi-Fi events that are of importance to us. These include the bit for a successful Wi-Fi connection with an AP and another bit for a failed Wi-Fi connection with an AP after the maximum number of retries are over.

#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT      BIT1

This code uses Informational Logging. The log function takes in two arguments. The first argument is the tag and the second argument is a formatted string. Therefore this global variable will be useful while calling the ESP_LOGI() functions. Here, “wifi station” is the tag that will be used while logging.

static const char *TAG = "wifi station";

event_handler()

Then we have the event_handler() function which handles the Wi-Fi events. This acts as a callback function when either Wi-Fi event or IP event occurs.

The IP event occurs when the ESP32 board connects with our access point and router assigned an IP address to it. IP events can be one of the following types. But here we are using only on that is IP_EVENT_STA_GOT_IP.

/** IP event declarations */
typedef enum {
    IP_EVENT_STA_GOT_IP,               /*!< station got IP from connected AP */
    IP_EVENT_STA_LOST_IP,              /*!< station lost IP and the IP is reset to 0 */
    IP_EVENT_AP_STAIPASSIGNED,         /*!< soft-AP assign an IP to a connected station */
    IP_EVENT_GOT_IP6,                  /*!< station or ap or ethernet interface v6IP addr is preferred */
    IP_EVENT_ETH_GOT_IP,               /*!< ethernet got IP from connected AP */
    IP_EVENT_ETH_LOST_IP,              /*!< ethernet lost IP and the IP is reset to 0 */
    IP_EVENT_PPP_GOT_IP,               /*!< PPP interface got IP */
    IP_EVENT_PPP_LOST_IP,              /*!< PPP interface lost IP */
} ip_event_t;

Firstly, when the Wi-Fi events (WIFI_EVENT and WIFI_EVENT_STA_START) occur, we connect the ESP32 with the AP. We use the function esp_wifi_connect() to connect the board with the AP.

If the ESP32 board is unable to connect to an AP within the maximum number of retries set, then it again tries to connect with the AP and logs “retry to connect to the AP”. However, if the ESP32 is unable to establish connection with the AP after the maximum number of retries are over, then it logs “connect to the AP fail” and sets the WIFI_FAIL_BIT. Now, if the ESP32 board is able to successfully connect with an AP, then it suggests that both the IP events (IP_EVENT and IP_EVENT_STA_GOT_IP) occurred. In this case, it prints the ip address as an output. Moreover, it also sets the WIFI_CONNECTED_BIT.

static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } 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");
    } 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);
    }
}

wifi_init_sta()

The wifi_init_sta() function will be called inside the app_main() function to initialize Wi-Fi in station mode for ESP32.


void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();

    ESP_ERROR_CHECK(esp_netif_init());

    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();

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

    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Setting a password implies station will connect to all security modes including WEP/WPA.
             * However these modes are deprecated and not advisable to be used. Incase your Access point
             * doesn't support WPA2, these mode can be enabled by commenting below line */
	     .threshold.authmode = WIFI_AUTH_WPA2_PSK,
        },
    };
    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() );

    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } 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);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }

    /* The event will not be processed after unregister */
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
    vEventGroupDelete(s_wifi_event_group);
}

We start off by creating a FreeRTOS event group to monitor the connection. This returns a handle to the event group.

s_wifi_event_group = xEventGroupCreate();

The ESP-IDF provides a useful macro called ESP_ERROR_CHECK() that will be used to check whether an error occurred or not. If the function that we pass inside it does not return ESP_OK, then we assert and log the line.

Here we are initializing lwIP through the function esp_netif_init() and create an IwIP task which is also known as a TCP/IP task. lwIP is a TCP/IP library stack provided by ESP-IDF that is used to perform various protocols such as TCP, UDP, DHCP etc.

ESP_ERROR_CHECK(esp_netif_init());

Next, we create a default event loop which enables the system events to be sent to the event task.

ESP_ERROR_CHECK(esp_event_loop_create_default());

Moreover, the following line is used for Wi-Fi default initialization for station mode. This API is used to initialize as well as register event handlers for the default interface which is station in our case. It creates a network interface instance binding Wi-Fi driver and TCP/IP stack. When a station is in the process of connecting to an AP, various processes automatically get handled through this function.

esp_netif_create_default_wifi_sta();

Then we initialize the Wi-Fi allocate resource for the Wi-Fi driver. It is responsible for initiating the Wi-Fi task. It takes in a single parameter cfg which is a pointer to the already initialized Wi-Fi configuration structure which is set to WIFI_INIT_CONFIG_DEFAULT() so that the initialization of the configuration is at default values. Here wifi_init_config_t is a structure that denotes the Wi-Fi stack configuration parameters that are passed inside the esp_wifi_init() function.

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

Next, we create two event handlers called ‘instance_any_id’ for all Wi-Fi events and ‘instance_any_ip’ for when the station obtains the IP.

esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;

Next, we have two registers for the event handler instances that we set up. This way the application task can register for a callback that can listen for events for Wi-Fi and TCP/IP. The first event is ‘ESP_EVENT_ANY_ID‘ and the second event is ‘IP_EVENT_STA_GOT_IP.’ Therefore it will listen to all Wi-Fi events (ESP_EVENT_ANY_ID) and an IP event when the station got its IP address (IP_EVENT_STA_GOT_IP). Hence, the callback event_handler function will be called if any of these two events occur.

ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));

Other wifi events which we can use in our code are:

typedef enum {
    WIFI_EVENT_STA_CONNECTED,            /**< ESP32 station connected to AP */
    WIFI_EVENT_STA_DISCONNECTED,         /**< ESP32 station disconnected from AP */
    WIFI_EVENT_AP_START,                 /**< ESP32 soft-AP start */
    WIFI_EVENT_AP_STOP,                  /**< ESP32 soft-AP stop */
} mdns_used_event_t;

In this part, we set up the SSID and password of the network we want our ESP32 to connect with, as well as assign the security setting.

wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
	    .threshold.authmode = WIFI_AUTH_WPA2_PSK,
        },
    };

Moreover, we set Wi-Fi mode as station. To set the Wi-Fi mode as station, we use the function esp_wifi_set_mode() and pass the WiFI_MODE_STA as a parameter inside it.


ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );

Then we assign our network’s SSID and password. This way the Wi-Fi driver gets configured with the AP network credentials and Wi-Fi mode. Then, we start the Wi-Fi connection at our assigned configuration.

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

At this point the information log prints “wifi_init_sta finished.” We are done with the process of initializing the Wi-Fi in station mode.

ESP_LOGI(TAG, "wifi_init_sta finished.");

Next the application moves to a blocked state whereby it waits for either of the bits in the event group to be set. This happens after the Wi-Fi is initialized and started. The application remains in the blocked state until either the Wi-Fi gets connected which is monitored by WIFI_CONNECTED_BIT or the W-Fi fails to connect within the maximum number of retries which is monitored by WIFI_FAIL_BIT.

Now if the event_handler() function sets the WIFI_CONNECTED_BIT which suggests that the ESP32 was able to successfully connect with an AP, then the informational log will print that it got connected to the SSID and password of the specified AP. If on the other hand, the event_handler() function sets the WIFI_FAIL_BIT which suggests that the ESP32 was not able to connected to the AP even after the maximum number of retries have been reached, then the informational log will print that it failed to connect to the SSID and password of the specified AP.

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


    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } 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);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }

Moreover, we unregister the two handlers from the system event loop for IP_EVENT (base event) and WIFI_EVENT (base event). The esp_vent_handler_instance_unregister() function takes in three parameters. The first is the event base. The second is the event id. The third is the instance object. Moreover, we also delete the event group ‘s_wifi_event_group’ using the vEventGroupDelete() function. It was created before by using a call to xEventGroupCreate().

    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
    vEventGroupDelete(s_wifi_event_group);

app_main()

Inside the app_main() function, we will first initialize NVS by calling the nvs_flash_init() function. Then we will check if the NVS partition does not contain any empty pages or if it contains data in a format which is different from the current version of code. If any of these condition is true then we will erase the NVS flash using nvs_flash_erase() and initialize it again.

Then we will print “ESP_WIFI_MODE_STA” in the terminal and call the wifi_init_sta() function to initialize the Wi-Fi for station mode.

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();
}

Compiling the Sketch

To flash your chip, type the following command in the serial terminal. Remember to replace the COM port with the one through which your board is connected.

idf.py -p COMX flash monitor
ESP32 Connect with Wi-Fi STA using ESP-IDF compile project

After the code flashes successfully, you can view all the informational logs.

We can first see “ESP_WIFI_MODE_STA” printed in the terminal. Followed by “wifi_init_sta finished” which denotes that the Station Wi-Fi is initialized. Then we can view the esp_netif_handlers which includes the IP, mask, and gw addresses. Then we get the log that the wifi station got IP followed by the ip address. This shows that the ESP32 successfully connected with the AP. Finally, you can view the SSID and password of the AP with which the board connected with.

ESP32 Connect with Wi-Fi STA using ESP-IDF terminal

4 thoughts on “ESP32 ESP-IDF Connect with WiFi – Station Mode Example”

  1. This code has the following errors:

    Line 30:
    ‘CONFIG_ESP_MAXIMUM_RETRY’ undeclared (first use in this function); did you mean ‘EXAMPLE_ESP_MAXIMUM_RETRY’?

    Line 61 Syntax error
    ESP_LOGI(TAG, “got ip:” IPSTR, IP2STR(&event->ip_info.ip));

    Line 82 and line 130
    Symbol ‘ESP_EVENT_ANY_ID’ could not be resolved

    Line 138:
    Symbol ‘ESP_ERR_NVS_NO_FREE_PAGES’ could not be resolved
    Symbol ‘ESP_ERR_NVS_NEW_VERSION_FOUND’ could not be resolved

    Reply
      • Good morning,

        I’m using the last stable version of Espressif-IDE:

        Operating System: windows 10
        Java Runtime Version: 17.0.6+10-LTS
        Eclipse Version: 4.25.0.v20220831-1800
        Eclipse CDT Version: 10.7.1.202208160035
        IDF Eclipse Plugin Version: 2.9.1.202304060814
        ESP-IDF v5.0.1-dirty
        Python set for IDF_PYTHON_ENV: Python 3.11.2

        If your code doesn’t work in the last version, you should update your programming environment and revalidate this code.

        It’s a great website, but its content should be validated and updated when needed.

        Thanks.

        Reply

Leave a Comment