Assignment 3: Connect to Wi-Fi
Now it’s finally time to connect our ESP32-C5 to a Wi-Fi network. ESP32-C5 supports both Wi-Fi 4 and Wi-Fi 6 standards on the 2.4 GHz frequency.
Wi-Fi connectivity is one of the most important features of most chips from the ESP32 family and is one of the essential components of their success. Thanks to Wi-Fi, it is possible to connect your IoT device to the internet and truly use all its features. This doesn’t necessarily mean just connecting to cloud services, but also e.g. over-the-air (OTA) updates, remote control and monitoring and much more.
ESP32 supports two modes: Station and SoftAP:
- Station mode: ESP connects to an existing network (like a home router).
- SoftAP mode: Other devices (like laptop or mobile) connect directly to ESP, where e.g. a web server with control can run.
For this assignment, we will build on the project from the previous assignment — the one using the
led_strip component — and connect to an existing Wi-Fi 4/Wi-Fi 6 network (so we will use
station mode).
Connecting to Wi-Fi
To be able to start using Wi-Fi, we need to tell the framework that we will use Wi-Fi:
in the main/CMakeLists.txt file, specifically in the idf_component_register function, we add
the following line:
REQUIRES esp_wifi esp_netif esp_event nvs_flash
Now we need to set up the Wi-Fi driver: we need to specify SSID and password.
- Copy the skeleton
Open your assignment-2 project and extend main.c with the additions below, or copy the full
skeleton into a fresh project (remember to add the led_strip component as you did in
assignment 2).
#include <stdio.h>
#include "led_strip.h"
#include "esp_log.h"
#include "esp_err.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 "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#define LED_STRIP_GPIO 27
#define LED_STRIP_RMT_RES_HZ (10 * 1000 * 1000)
#define WIFI_SSID "network-ssid"
#define WIFI_PASS "network-pass"
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static led_strip_handle_t led_strip;
static EventGroupHandle_t s_wifi_event_group;
static int s_retry_num = 0;
static const char *TAG = "workshop";
led_strip_handle_t configure_led(void)
{
led_strip_handle_t strip;
led_strip_config_t strip_config = {
.strip_gpio_num = LED_STRIP_GPIO,
.max_leds = 1,
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB,
.led_model = LED_MODEL_WS2812,
.flags.invert_out = false,
};
led_strip_rmt_config_t rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = LED_STRIP_RMT_RES_HZ,
.mem_block_symbols = 0,
.flags.with_dma = false,
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &strip));
ESP_LOGI(TAG, "LED strip initialized successfully");
return strip;
}
static void led_set_color(uint8_t r, uint8_t g, uint8_t b)
{
ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, 0, r, g, b));
ESP_ERROR_CHECK(led_strip_refresh(led_strip));
}
// TODO handler
void wifi_init_sta(void)
{
s_wifi_event_group = xEventGroupCreate();
//TODO
}
void app_main(void)
{
esp_err_t ret = nvs_flash_init();
//TODO
led_strip = configure_led();
led_set_color(0x20, 0x0, 0x0);
wifi_init_sta();
}
- Wi-Fi initialization
Wi-Fi initialization consists of these steps, which we will add to the wifi_init_sta() function:
- TCP/IP stack initialization:
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
- Creating default configuration for Wi-Fi initialization and the initialization itself:
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
- Registering event handlers for
WIFI_EVENTandIP_EVENTevents:
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id);
esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip);
- Setting Wi-Fi mode to station using
WIFI_MODE_STA:
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
- Setting the connection parameters themselves using the
wifi_config_tstructure:
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASS,
.threshold.authmode = WIFI_AUTH_WPA_PSK,
.sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
.sae_h2e_identifier = "",
},
};
- Now we can call the
esp_wifi_set_configfunction.
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
- Now that both the Wi-Fi controller and the connection itself are set up, we can turn on Wi-Fi:
ESP_ERROR_CHECK(esp_wifi_start());
- Now we just need to wait for
WIFI_CONNECTED_BITorWIFI_FAIL_BITand make sure everything worked:
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!");
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGE(TAG, "Failed to connect!");
}
- Creating Wi-Fi event handler
This will not be part of either app_main or wifi_init_sta, but will be at the same level as
these two functions. It must be located before wifi_init_sta, in place of the comment
//TODO event handler. We use the led_set_color() helper from the skeleton to update the LED
status on each Wi-Fi event:
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 < 30) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGW(TAG, "Trying to connect to WiFi");
led_set_color(0x0, 0x0, 0x20);
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGE(TAG, "Failed to connect to WiFi");
led_set_color(0x20, 0x0, 0x0);
} 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));
led_set_color(0x0, 0x20, 0x0);
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
- NVS initialization check
We will discuss NVS in the next assignment, so for now it will be a bit of a blackbox. We will
add this code to app_main.
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);
led_strip = configure_led();
led_set_color(0x0, 0x0, 0x20);
- Wi-Fi initialization
The last step is calling our function in app_main:
wifi_init_sta();
Now you can build and upload your code.
The ESP_LOGI and ESP_LOGE functions output data to the serial line. After we upload the
program to the development board, we can open communication with the board using the Monitor
command in ESP-IDF Explorer or using ESP-IDF: Monitor Device via Command Palette.
Complete code
Below you can find the complete code for this assignment:
#include <stdio.h>
#include "led_strip.h"
#include "esp_log.h"
#include "esp_err.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 "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#define LED_STRIP_GPIO 27
#define LED_STRIP_RMT_RES_HZ (10 * 1000 * 1000)
#define WIFI_SSID "network-ssid"
#define WIFI_PASS "network-pass"
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static led_strip_handle_t led_strip;
static EventGroupHandle_t s_wifi_event_group;
static int s_retry_num = 0;
static const char *TAG = "workshop";
led_strip_handle_t configure_led(void)
{
led_strip_handle_t strip;
led_strip_config_t strip_config = {
.strip_gpio_num = LED_STRIP_GPIO,
.max_leds = 1,
.color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB,
.led_model = LED_MODEL_WS2812,
.flags.invert_out = false,
};
led_strip_rmt_config_t rmt_config = {
.clk_src = RMT_CLK_SRC_DEFAULT,
.resolution_hz = LED_STRIP_RMT_RES_HZ,
.mem_block_symbols = 0,
.flags.with_dma = false,
};
ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &strip));
ESP_LOGI(TAG, "LED strip initialized successfully");
return strip;
}
static void led_set_color(uint8_t r, uint8_t g, uint8_t b)
{
ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, 0, r, g, b));
ESP_ERROR_CHECK(led_strip_refresh(led_strip));
}
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 < 30) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGW(TAG, "Trying to connect to WiFi");
led_set_color(0x0, 0x0, 0x20);
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGE(TAG, "Failed to connect to WiFi");
led_set_color(0x20, 0x0, 0x0);
} 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));
led_set_color(0x0, 0x20, 0x0);
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 = WIFI_SSID,
.password = WIFI_PASS,
.threshold.authmode = WIFI_AUTH_WPA_PSK,
.sae_pwe_h2e = WPA3_SAE_PWE_BOTH,
.sae_h2e_identifier = "",
},
};
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());
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!");
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGE(TAG, "Failed to connect!");
}
}
void app_main(void)
{
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);
led_strip = configure_led();
led_set_color(0x0, 0x0, 0x20);
wifi_init_sta();
}
Extra
- If you want, you can try connecting to Wi-Fi at home using the common_components/protocol_examples_common component.
Next step
Now that we have successfully connected to Wi-Fi, let’s move on to working with memory!