Chapter 41: WiFi Protected Setup and SmartConfig
Chapter Objectives
By the end of this chapter, you will be able to:
- Briefly recall the purpose and methods of WiFi Protected Setup (WPS).
- Understand the concept and functionality of SmartConfig.
- Describe the SmartConfig process and its advantages/disadvantages.
- Configure the ESP32 to use SmartConfig via ESP-IDF.
- Implement code to initiate and handle SmartConfig events.
- Discuss common issues and troubleshooting steps for SmartConfig.
- Compare WPS and SmartConfig as provisioning methods.
Introduction
In the previous chapter, we explored WiFi Protected Setup (WPS) as a method to simplify connecting ESP32 devices to a WiFi network. While WPS offers convenience, particularly with its Push Button Configuration (PBC) mode, it’s not the only simplified provisioning technique available. Another popular method, especially for headless IoT devices (devices without a screen or extensive input mechanisms), is SmartConfig.
SmartConfig, developed by Espressif, allows users to configure WiFi credentials on an ESP32 device using a smartphone application. The application cleverly broadcasts the SSID and password to the ESP32, which is in a special listening mode. This chapter will provide a concise review of WPS and then delve into the theory and practical implementation of SmartConfig on the ESP32 using ESP-IDF. Understanding both WPS and SmartConfig provides you with a versatile toolkit for creating user-friendly IoT products.
Theory
WiFi Protected Setup (WPS) Recap
As discussed in Chapter 40, WPS is a network security standard that simplifies the process of connecting devices to a wireless network. It aims to automate the secure exchange of network credentials (SSID and password) between a router (Registrar) and a client device (Enrollee), like the ESP32.
Key WPS Methods:
- Push Button Configuration (PBC): The user presses a WPS button on both the router and the client device. The devices then discover each other, and the router securely transmits the credentials.
- Pros: Very simple for users.
- Cons: Potential security risk from “WPS overlap” if an unauthorized device is also in PBC mode nearby; requires physical access to the router.
- Personal Identification Number (PIN): A PIN is used for authentication.
- Device PIN: The client device has a static PIN, entered into the router’s interface.
- Router PIN: The router generates a PIN, entered into the client device (less common for IoT).
- Pros: Can be more secure than PBC if the PIN is strong and kept secret (Device PIN method).
- Cons: Router PIN method is vulnerable; less user-friendly than PBC.
WPS Method | Description | Pros | Cons |
---|---|---|---|
Push Button Configuration (PBC) | User presses a WPS button on both the router and the client device (ESP32). Devices discover each other, and the router securely transmits credentials. | Very simple for users. | Potential security risk from “WPS overlap”; requires physical access to the router. |
Personal Identification Number (PIN) – Device PIN | The client device (ESP32) has a static PIN. This PIN is entered into the router’s configuration interface. | Can be more secure than PBC if the PIN is strong and kept secret. | Less user-friendly than PBC; requires accessing router UI. |
Personal Identification Number (PIN) – Router PIN | The router generates a PIN. This PIN is entered into the client device. (Less common for IoT/ESP32). | Standardized method. | Router PIN method is considered vulnerable; generally less user-friendly for headless devices. |
WPS acts as an intermediary step. Once successful, the ESP32 receives the credentials and proceeds with a standard WPA/WPA2/WPA3 connection.
SmartConfig
SmartConfig is a provisioning technology developed by Espressif for its ESP8266 and ESP32 series of Wi-Fi SoCs. It enables an ESP device to connect to a Wi-Fi network without needing to hardcode credentials or implement a complex configuration interface (like a web server) on the device itself, especially when it’s first unboxed.
How SmartConfig Works:
The SmartConfig process relies on a smartphone application (e.g., Espressif’s Esptouch app for Android/iOS) and clever use of network packet transmission.
- ESP32 in Promiscuous/Sniffing Mode: The ESP32 is put into a special mode where its WiFi radio listens to all nearby WiFi traffic without being connected to a specific Access Point (AP). It doesn’t filter packets based on MAC address at this stage.
- Smartphone App Broadcasting: The user enters the WiFi SSID and password into the SmartConfig smartphone app. The app then connects to the currently connected WiFi network (the one the ESP32 should eventually join).
- Encoding Credentials: The app encodes the SSID and password into the length or content of special UDP broadcast or multicast packets. It sends out a sequence of these packets.
- The ESP32 sniffs these packets. Since it knows the SmartConfig protocol, it can identify these special packets.
- By analyzing the lengths or specific patterns in the sequence of received packets, the ESP32 decodes the SSID and password.
- Confirmation (ACK): Once the ESP32 successfully decodes the credentials, it typically sends a confirmation (ACK) packet back to the smartphone app (usually a UDP packet to a specific port on the phone’s IP address, which the ESP32 also decodes from the broadcast sequence). This tells the app that the ESP32 has received the information.
- Connection Attempt: The ESP32 then disables SmartConfig mode and uses the received SSID and password to connect to the target WiFi network like a normal station.
- App Feedback: The smartphone app, upon receiving the ACK, informs the user that the device is attempting to connect.
%%{ init: { 'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans' } } }%% graph TB %% Define styles for node types classDef startNode fill:#EDE9FE,stroke:#5B21B6,stroke-width:2px,color:#5B21B6; classDef endNode fill:#D1FAE5,stroke:#059669,stroke-width:2px,color:#065F46; classDef decisionNode fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E; classDef processNode fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF; classDef checkNode fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B; %% Actors USER([User]) APP[Smartphone App] ESP32[ESP32 Device] ROUTER[Router/AP] %% Styling actors (optional, if direct styling is preferred over lane-based) %% style USER fill:#ECEFF1,stroke:#37474F,color:#37474F %% style APP fill:#E3F2FD,stroke:#1E88E5,color:#1E88E5 %% style ESP32 fill:#E8EAF6,stroke:#3F51B5,color:#3F51B5 %% style ROUTER fill:#E0F2F1,stroke:#00796B,color:#00796B subgraph User Interaction USER -- "Enters SSID/Password" --> APP(Phase 1: Input Credentials); class APP startNode; end subgraph Provisioning Phase APP -- "1- Connects to Target AP<br>2- Encodes Credentials<br>3- Broadcasts/Multicasts UDP Packets" --> ESP32_LISTEN(Phase 2: ESP32 Listens); class ESP32_LISTEN processNode; ESP32_LISTEN -- "Sniffs All Packets<br>Identifies & Decodes<br>SmartConfig Packets" --> ESP32_DECODE(Get SSID/Password); class ESP32_DECODE processNode; ESP32_DECODE -- "Sends ACK Packet" --> APP_WAIT_ACK(Phase 3: App Waits for ACK); class APP_WAIT_ACK processNode; APP_WAIT_ACK -- "Receives ACK<br>Informs User of Attempt" --> USER_NOTIFIED(User Notified: Connecting...); class USER_NOTIFIED endNode; end subgraph Connection Phase ESP32_DECODE -- "Disables SmartConfig Mode" --> ESP32_CONNECT_ATTEMPT(Phase 4: ESP32 Attempts Connection); class ESP32_CONNECT_ATTEMPT processNode; ESP32_CONNECT_ATTEMPT -- "Uses Received Credentials<br>to Connect" --> ROUTER_AUTH(Router Authenticates ESP32); class ROUTER_AUTH processNode; ROUTER_AUTH -- "Authentication Success" --> ESP32_CONNECTED(Phase 5: ESP32 Connected to WiFi); class ESP32_CONNECTED endNode; ROUTER_AUTH -- "Authentication Fail" --> ESP32_FAIL(Connection Failed); class ESP32_FAIL checkNode; end %% Initial State for ESP32 ESP32_INIT((ESP32 Initial State: <br> Not Connected, <br> Enters SmartConfig Mode)):::startNode --> ESP32_LISTEN; %% Grouping visually (Not strict subgraphs, but shows relation) %% Note: Mermaid's ability to visually group arbitrary nodes without strict subgraph hierarchy is limited. %% The flow itself should imply the roles.
Pros of SmartConfig:
- User-Friendly: No need for the user to connect to an ESP32’s temporary AP or type PINs. The process is managed through a familiar smartphone interface.
- No Physical Access to Router Needed: Unlike WPS PBC, no button press on the router is required.
- Handles Complex Credentials: Can easily transmit SSIDs and passwords with special characters or long lengths, which can be cumbersome with other methods.
- Batch Configuration: Some SmartConfig app versions can potentially configure multiple devices simultaneously if they are all in SmartConfig mode.
Cons of SmartConfig:
- Requires a Smartphone App: Users must download and use a specific app.
- Network Dependency: The smartphone must be connected to the target 2.4 GHz WiFi network. Some complex network configurations (e.g., AP isolation, multicast/broadcast filtering on the router) can interfere with the SmartConfig process.
- Security: The credentials are broadcast over the air. While the encoding provides some obfuscation, it’s not strong encryption. The security relies on the brief window during which provisioning occurs and the assumption that an attacker is not actively sniffing for these specific patterns at that exact moment. It’s generally considered secure enough for initial setup.
- Proprietary Variations: While Espressif provides Esptouch, other vendors might have their own “smart config” variations that are not interoperable.
WPS vs. SmartConfig:
Feature | WPS (PBC/PIN) | SmartConfig |
---|---|---|
Initiation | Button press (PBC) or PIN entry | Smartphone app |
Router Access | Physical access for PBC; Admin UI for PIN | None needed (beyond knowing its credentials) |
App Required | No (for PBC/Device PIN); Router UI (for PIN) | Yes (e.g., Esptouch) |
Security | PBC: Overlap risk. Router PIN: Vulnerable. | Credentials broadcast (obfuscated, not encrypted). |
Complexity | PBC: Very simple. PIN: Moderately simple. | Simple for end-user via app. |
Standard | Wi-Fi Alliance Standard | Espressif Proprietary (but widely adopted for ESP) |
SmartConfig in ESP-IDF
ESP-IDF provides a straightforward API to integrate SmartConfig functionality into your applications. The core components are:
- Include Headers:
#include "esp_wifi.h" #include "esp_smartconfig.h" // For event handling #include "esp_event.h" #include "freertos/event_groups.h" // For synchronization
- Event Handling: SmartConfig operations generate events that your application must handle. Key events include:
Event Name | Description | Event Data Structure |
---|---|---|
SC_EVENT_SCAN_DONE |
Indicates that SmartConfig has completed the process of scanning Wi-Fi channels. This is an informational event. | N/A (No specific data structure for this event itself, check API docs for generic event data args) |
SC_EVENT_FOUND_CHANNEL |
Signifies that SmartConfig has identified the Wi-Fi channel on which the smartphone app is broadcasting the credentials. | N/A (No specific data structure for this event itself) |
SC_EVENT_GOT_SSID_PSWD |
Crucial Event: SmartConfig has successfully received and decoded the Wi-Fi SSID and password from the smartphone app. | smartconfig_event_got_ssid_pswd_t (contains SSID, password, BSSID if available, and type) |
SC_EVENT_SEND_ACK_DONE |
Confirms that the ESP32 has finished sending the acknowledgment (ACK) packet back to the smartphone app. This usually indicates to the app that the ESP32 has the credentials. (This event’s occurrence might depend on esp_smartconfig_set_type configuration, e.g. if ACK is enabled). |
N/A (No specific data structure for this event itself) |
- Configuration:
esp_smartconfig_set_type()
: Configures the SmartConfig type (e.g.,SC_TYPE_ESPTOUCH
for Esptouch app,SC_TYPE_AIRKISS
for WeChat AirKiss).esp_smartconfig_fast_mode()
: Enables or disables fast mode (experimental).
- Starting and Stopping:
ESP-IDF Function | Purpose | Key Parameter(s) / Notes |
---|---|---|
esp_smartconfig_set_type() |
Configures the SmartConfig protocol type to be used. | Parameter: smartconfig_type_t (e.g., SC_TYPE_ESPTOUCH , SC_TYPE_AIRKISS , SC_TYPE_ESPTOUCH_V2 ). Must match the protocol used by the smartphone app. |
esp_smartconfig_fast_mode() |
Enables or disables “fast mode” for SmartConfig. (Experimental feature) | Parameter: bool enable . Default is usually disabled. Check documentation for implications. |
esp_smartconfig_start() |
Starts the SmartConfig process. The ESP32 begins listening for provisioning packets. | Parameter: const smartconfig_start_config_t *config . Configuration includes options like whether to send an ACK packet. Use SMARTCONFIG_START_CONFIG_DEFAULT() for default settings. |
esp_smartconfig_stop() |
Stops the SmartConfig process. | Should be called after credentials are successfully received (SC_EVENT_GOT_SSID_PSWD ), or if the process times out or fails. |
esp_event_handler_register() |
Registers an event handler function to listen for SmartConfig events. | Parameters: event_base (e.g., SC_EVENT ), event_id (e.g., ESP_EVENT_ANY_ID or specific event like SC_EVENT_GOT_SSID_PSWD ), handler function pointer, handler arguments. |
- Event Loop: A default event loop must be running, and you need to register an event handler for SmartConfig events.
Typical Flow in Code:
- Initialize WiFi in station mode.
- Initialize the event loop.
- Register an event handler that listens for both WiFi events and SmartConfig events.
- When provisioning is triggered (e.g., by a button press, or if no credentials are found in NVS):a. Call esp_smartconfig_set_type() to set the desired SmartConfig protocol (usually SC_TYPE_ESPTOUCH).b. Call esp_smartconfig_start() with a configuration structure (smartconfig_start_config_t).
- In the event handler:a. On SC_EVENT_GOT_SSID_PSWD:i. Retrieve the SSID and password from the event data.ii. Call esp_smartconfig_stop().iii.Configure the ESP32 WiFi station with these credentials.iv. Call esp_wifi_connect() to connect to the AP.b. Handle other SmartConfig events (like timeout, if implemented with a timer, or other status updates).
- Once connected (indicated by
WIFI_EVENT_STA_CONNECTED
andIP_EVENT_STA_GOT_IP
), the device is provisioned. It’s good practice to save the credentials to NVS.
%%{ init: { 'theme': 'base', 'themeVariables': { 'fontFamily': 'Open Sans' } } }%% graph TD %% Define styles for node types classDef startNode fill:#EDE9FE,stroke:#5B21B6,stroke-width:2px,color:#5B21B6; classDef endNode fill:#D1FAE5,stroke:#059669,stroke-width:2px,color:#065F46; classDef decisionNode fill:#FEF3C7,stroke:#D97706,stroke-width:1px,color:#92400E; classDef processNode fill:#DBEAFE,stroke:#2563EB,stroke-width:1px,color:#1E40AF; classDef checkNode fill:#FEE2E2,stroke:#DC2626,stroke-width:1px,color:#991B1B; classDef ioNode fill:#F3E5F5,stroke:#8E24AA,stroke-width:1px,color:#6A1B9A; %% For event handling A(Start: Application Main):::startNode --> B{Initialize WiFi & Event Loop}; class B processNode; B --> C{Register WiFi &<br>SmartConfig Event Handlers}; class C processNode; C --> D{"Trigger Provisioning?<br>(e.g., Button Press or No Saved Credentials)"}; class D decisionNode; D -- Yes --> E{"Call <br><code>esp_smartconfig_set_type()</code><br>(e.g., SC_TYPE_ESPTOUCH_V2)"}; class E processNode; E --> F{"Call <br><code>esp_smartconfig_start()</code>"}; class F processNode; F --> G[ESP32 in SmartConfig Mode:<br>Listening for Packets]; class G ioNode; D -- No (e.g. Has Credentials) --> Connect_Direct{Attempt WiFi Connect<br>with Stored Credentials}; class Connect_Direct processNode; Connect_Direct --> IsConnected{Connected?}; class IsConnected decisionNode; IsConnected -- Yes --> Z1(WiFi Connected):::endNode; IsConnected -- No --> D; G --> H{Event Occurs}; class H ioNode; H -- SC_EVENT_GOT_SSID_PSWD --> I{Retrieve SSID & Password<br>from event data}; class I processNode; I --> J{"Call <br><code>esp_smartconfig_stop()</code>"}; class J processNode; J --> K{"Configure WiFi STA<br>with new credentials<br>(<code>esp_wifi_set_config</code>)"}; class K processNode; K --> L{"Call <br><code>esp_wifi_connect()</code>"}; class L processNode; L --> M[Device Attempts Connection to AP]; class M ioNode; M --> N{WiFi Connected &<br>IP Obtained?}; class N decisionNode; N -- Yes --> O{"Save Credentials to NVS<br>(Good Practice)"}; class O processNode; O --> P(Provisioning Successful!<br>Connected to WiFi):::endNode; N -- No --> Q(Connection Failed<br>Handle Error/Timeout):::checkNode; H -- Other SC_EVENTs<br>(SCAN_DONE, FOUND_CHANNEL, ACK_DONE) --> R{"Log Event / Update Status<br>(Informational)"}; class R processNode; R --> G; H -- WiFi Events<br>(STA_DISCONNECTED, etc.) --> S{Handle WiFi State Changes}; class S processNode; S --> T{May trigger reconnect or<br>re-evaluate provisioning state}; class T processNode; T --> G; F -- Error Starting --> StartFail(SmartConfig Start Failed<br>Handle Error):::checkNode;
Practical Examples
Let’s implement SmartConfig on the ESP32. This example will demonstrate how to initialize SmartConfig, handle its events, and then connect to the WiFi network using the obtained credentials.
1. Project Setup & Configuration
- Create a new ESP-IDF project in VS Code or copy an existing basic WiFi station project.
2. Ensure WiFi is enabled in menuconfig
:
- Run
idf.py menuconfig
(or use the VS Code ESP-IDF extension’s GUI for menuconfig). - Navigate to
Component config
->Wi-Fi
. - Ensure
WiFi Station Enable
is checked.
3. Include necessary headers in your main.c
file:
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h" // For event synchronization
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_smartconfig.h" // For SmartConfig API
2. SmartConfig Event Handling and WiFi Initialization
We’ll define event groups to signal the status of SmartConfig and WiFi connection.
// main.c
static const char *TAG = "SMARTCONFIG_EXAMPLE";
// Event group to signal when we are connected & when SmartConfig is done
static EventGroupHandle_t s_wifi_event_group;
// Bits for the event group
#define WIFI_CONNECTED_BIT BIT0 // For general WiFi connection
#define WIFI_FAIL_BIT BIT1 // For general WiFi failure
#define SMARTCONFIG_DONE_BIT BIT2 // For SmartConfig completion (got credentials)
static bool s_is_connected = false; // Global flag for connection status
// Forward declaration
static void smartconfig_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data);
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data);
static void initialise_wifi(void);
static void start_smartconfig(void);
// WiFi Event Handler
static void wifi_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_LOGI(TAG, "WIFI_EVENT_STA_START: WiFi station started.");
// If not provisioned, start SmartConfig.
// In a real app, you might check NVS for saved credentials first.
// For this example, we'll start SmartConfig directly if not connected.
if (!s_is_connected) {
start_smartconfig();
}
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
s_is_connected = false;
ESP_LOGI(TAG, "WIFI_EVENT_STA_DISCONNECTED: Disconnected from AP.");
// If SmartConfig was successful and we got disconnected, try to reconnect.
// If SmartConfig was not done yet, it might be still running or failed.
// If disconnected after a successful SmartConfig connection, attempt reconnect.
// This example doesn't automatically restart SmartConfig on disconnect after initial success.
// A robust application might retry connection or re-initiate provisioning.
if (xEventGroupGetBits(s_wifi_event_group) & SMARTCONFIG_DONE_BIT) {
ESP_LOGI(TAG, "Attempting to reconnect to the AP...");
esp_wifi_connect(); // Try to reconnect with stored credentials
}
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); // Signal failure for waiting tasks
} 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, "IP_EVENT_STA_GOT_IP: Got IP:" IPSTR, IP2STR(&event->ip_info.ip));
s_is_connected = true;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
xEventGroupClearBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
}
// SmartConfig Event Handler
static void smartconfig_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == SC_EVENT) {
switch (event_id) {
case SC_EVENT_SCAN_DONE:
ESP_LOGI(TAG, "SC_EVENT_SCAN_DONE: SmartConfig scan done");
break;
case SC_EVENT_FOUND_CHANNEL:
ESP_LOGI(TAG, "SC_EVENT_FOUND_CHANNEL: SmartConfig found channel");
break;
case SC_EVENT_GOT_SSID_PSWD:
ESP_LOGI(TAG, "SC_EVENT_GOT_SSID_PSWD: SmartConfig got SSID and password");
smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
wifi_config_t wifi_config;
uint8_t ssid[33] = { 0 };
uint8_t password[65] = { 0 };
uint8_t rvd_data[33] = {0}; // For potential router vendor data
bzero(&wifi_config, sizeof(wifi_config_t));
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
wifi_config.sta.bssid_set = evt->bssid_set; // Use BSSID if provided by SmartConfig
if (wifi_config.sta.bssid_set == true) {
memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
}
memcpy(ssid, evt->ssid, sizeof(evt->ssid));
memcpy(password, evt->password, sizeof(evt->password));
ESP_LOGI(TAG, "Received SSID: %s", ssid);
ESP_LOGI(TAG, "Received Password: %s", password);
if (evt->type == SC_TYPE_ESPTOUCH_V2) {
ESP_LOGI(TAG, "SC_TYPE_ESPTOUCH_V2");
if(evt->rvd_data_len > 0) {
memcpy(rvd_data, evt->rvd_data, evt->rvd_data_len);
ESP_LOGI(TAG, "Received RVD_DATA: %s", rvd_data);
} else {
ESP_LOGI(TAG, "No RVD_DATA received");
}
}
// Stop SmartConfig
ESP_ERROR_CHECK(esp_smartconfig_stop());
ESP_LOGI(TAG, "SmartConfig stopped.");
// Configure WiFi with received credentials and connect
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_LOGI(TAG, "Connecting to AP...");
ESP_ERROR_CHECK(esp_wifi_connect());
xEventGroupSetBits(s_wifi_event_group, SMARTCONFIG_DONE_BIT); // Signal SmartConfig is done
break;
case SC_EVENT_SEND_ACK_DONE:
ESP_LOGI(TAG, "SC_EVENT_SEND_ACK_DONE: SmartConfig ACK sent");
// This event means the ESP32 has sent a confirmation to the phone app.
// The app should now indicate success to the user.
// We don't stop SmartConfig here, wait for GOT_SSID_PSWD or timeout.
break;
default:
ESP_LOGW(TAG, "Unhandled SC_EVENT: %ld", event_id);
break;
}
}
}
// Function to initialize WiFi
static void initialise_wifi(void)
{
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init()); // Initialize TCP/IP stack
ESP_ERROR_CHECK(esp_event_loop_create_default()); // Create default event loop
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif); // Ensure netif was created
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // Initialize WiFi driver
// Register event handlers for WiFi events and SmartConfig events
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &smartconfig_event_handler, NULL));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_start()); // Start WiFi. This will trigger WIFI_EVENT_STA_START
ESP_LOGI(TAG, "WiFi Initialized in STA mode.");
}
// Function to start the SmartConfig process
static void start_smartconfig(void)
{
ESP_LOGI(TAG, "Starting SmartConfig...");
// Set SmartConfig type to ESPTOUCH (compatible with Espressif's Esptouch app)
// For Esptouch V2 (recommended for better performance and features like RVD)
ESP_ERROR_CHECK(esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_V2));
// Configure SmartConfig with broadcast option (ESPTOUCH default)
// and enable sending ACK back to the phone app.
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_smartconfig_start(&cfg));
ESP_LOGI(TAG, "SmartConfig started. Waiting for credentials from Esptouch app...");
// Clear any previous done/fail bits before starting a new attempt
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT | SMARTCONFIG_DONE_BIT);
}
3. Main Application (app_main
)
The app_main
function will initialize NVS (Non-Volatile Storage, good practice though not strictly used for loading credentials in this basic example), then initialize WiFi, which in turn will trigger SmartConfig if not connected.
// main.c (continued)
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, "ESP32 SmartConfig Example");
initialise_wifi(); // This will also trigger start_smartconfig via event handler
// Wait for SmartConfig to complete or WiFi to connect/fail
// This loop is just for demonstration. A real app might have other tasks.
while (1) {
EventBits_t uxBits;
uxBits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT | SMARTCONFIG_DONE_BIT,
pdFALSE, // Don't clear bits on exit (handled by handlers)
pdFALSE, // Wait for ANY bit to be set
pdMS_TO_TICKS(15000)); // Wait for 15 seconds
if (uxBits & SMARTCONFIG_DONE_BIT) {
ESP_LOGI(TAG, "SmartConfig process completed. Waiting for connection...");
// The wifi_event_handler will take care of WIFI_CONNECTED_BIT
}
if (uxBits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "Successfully connected to AP via SmartConfig!");
// Application logic can proceed here
// For this example, we just log and continue waiting/idling
}
if (uxBits & WIFI_FAIL_BIT) {
ESP_LOGW(TAG, "WiFi connection failed or SmartConfig timed out (if not completed).");
// Potentially restart SmartConfig or enter a fallback mode
// For this example, if SmartConfig hasn't finished, it's still running.
// If it finished and connection failed, wifi_event_handler might retry.
// If no bits were set, it means timeout from xEventGroupWaitBits
}
if ((uxBits & (WIFI_CONNECTED_BIT | WIFI_FAIL_BIT | SMARTCONFIG_DONE_BIT)) == 0) {
ESP_LOGI(TAG, "Still waiting for SmartConfig/Connection or timed out waiting for event bit...");
// If SmartConfig is still running and hasn't timed out by itself,
// and we haven't connected, we might be in the middle of the process.
// A more robust timeout for the *entire* SmartConfig process might be needed
// using a FreeRTOS timer if esp_smartconfig itself doesn't timeout quickly enough.
}
// Simple delay to prevent busy-looping in main if not much else is happening
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
4. Build, Flash, and Observe
- Build the project:
- Using the VS Code ESP-IDF Extension: Click the “Build” icon (cylinder).
- Using command line:
idf.py build
.
- Flash the project:
- Using the VS Code ESP-IDF Extension: Click the “Flash” icon (lightning bolt). Ensure your ESP32 is connected and the correct COM port is selected.
- Using command line:
idf.py -p (YOUR_PORT) flash
.
- Monitor the output:
- Using the VS Code ESP-IDF Extension: Click the “Monitor” icon (plug).
- Using command line:
idf.py -p (YOUR_PORT) monitor
.
- Test with Esptouch App:a. Download the “Esptouch” app from Espressif Systems on your Android or iOS device. (For ESPTOUCH_V2, ensure you use a compatible app version, often named Esptouch V2 or similar, or the standard Esptouch which may support V2).b. Connect your smartphone to the 2.4 GHz WiFi network that you want the ESP32 to connect to. Important: SmartConfig typically does not work if your phone is connected to a 5 GHz band of the same network, as the ESP32 usually operates on 2.4 GHz.c. Open the Esptouch app.d. The app should automatically pick up the SSID of the network your phone is connected to. Enter the password for this WiFi network.e. You might see options for “Broadcast” or “Multicast”. Usually, “Multicast” is preferred if your router supports it well. You might also see options for “Device count” (set to 1 if configuring one device) and potentially “Reserved Data” (RVD) for ESPTOUCH_V2.f. Tap “Confirm” or “Start” in the app.
- Observe ESP32 Serial Monitor:
- You should see logs like “Starting SmartConfig…”, “SmartConfig scan done”, “SmartConfig found channel”.
- The Esptouch app will start sending packets.
- If successful, the ESP32 monitor will show “SC_EVENT_GOT_SSID_PSWD”, displaying the received SSID and password.
- Then, it will log “SmartConfig stopped,” “Setting WiFi configuration…”, “Connecting to AP…”, and finally “Got IP:…” and “Successfully connected to AP via SmartConfig!”.
- The Esptouch app should also indicate success.
Tip: If SmartConfig fails, try switching between Multicast and Broadcast in the Esptouch app settings (if available). Also, ensure your phone’s mobile data is turned off to prevent the app from trying to send packets over the wrong interface.
Variant Notes
SmartConfig functionality, using esp_smartconfig
, is available on all ESP32 variants that include WiFi capabilities. This includes:
- ESP32
- ESP32-S2
- ESP32-S3
- ESP32-C3
- ESP32-C6
- ESP32-C5
- ESP32-C61
The underlying principles and ESP-IDF API usage for SmartConfig remain consistent across these variants. Performance or minor behavioral nuances related to the specific radio hardware in each variant are possible but generally do not affect the core logic presented.
ESP32-H2 does not support WiFi and therefore does not support WiFi SmartConfig.
Common Mistakes & Troubleshooting Tips
Mistake / Issue | Symptom(s) | Troubleshooting / Solution |
---|---|---|
Smartphone Not on 2.4 GHz Network |
ESP32 does not receive credentials. Esptouch app seems to send data, but ESP32 monitor shows no SC_EVENT_GOT_SSID_PSWD .
|
Fix: Ensure your smartphone is connected to the 2.4 GHz band of your target WiFi network before starting SmartConfig in the app. ESP32 typically operates on 2.4 GHz. |
Router Blocking Multicast/Broadcast or AP Isolation |
SmartConfig process fails repeatedly. ESP32 might not even show SC_EVENT_FOUND_CHANNEL .
|
Fix: 1. Temporarily disable AP Isolation on your router. 2. Check router settings for multicast/broadcast filtering options and adjust if necessary. 3. Try switching between Multicast and Broadcast modes in the Esptouch app settings.
|
Incorrect SmartConfig Type or App |
ESP32 fails to decode credentials. Logs might show unexpected behavior or no relevant SmartConfig events. |
Fix: Ensure you use esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) or SC_TYPE_ESPTOUCH_V2 when using the Espressif Esptouch app. Match the configured type with the app’s protocol. Avoid incompatible third-party “smart connect” apps.
|
WiFi Not Started or Not in STA Mode |
esp_smartconfig_start() returns an error. SmartConfig process doesn’t initiate. |
Fix: Ensure esp_wifi_set_mode(WIFI_MODE_STA) and esp_wifi_start() are successfully called before initiating SmartConfig. Triggering start_smartconfig() from the WIFI_EVENT_STA_START event handler is a good practice.
|
Event Handler Not Registered or Incorrect Logic |
Credentials (SC_EVENT_GOT_SSID_PSWD ) are received, but ESP32 doesn’t connect. Or, SmartConfig process doesn’t stop, continuously draining power. |
Fix: 1. Double-check event handler registration: esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &smartconfig_event_handler, NULL) . 2. Ensure logic in SC_EVENT_GOT_SSID_PSWD handler correctly calls esp_smartconfig_stop() , then esp_wifi_set_config() , and finally esp_wifi_connect() .
|
Mobile Data Interference | Esptouch app fails to send credentials correctly or reports errors, even if WiFi settings seem correct. | Fix: Temporarily turn off mobile data on your smartphone. This ensures the Esptouch app uses the WiFi interface exclusively for broadcasting credentials. |
App Permissions | Esptouch app cannot detect WiFi SSID or fails to operate correctly. | Fix: Ensure the Esptouch app has necessary permissions (e.g., Location services, which are often required to access WiFi information on modern mobile OS). |
Exercises
- Button-Triggered SmartConfig & LED Feedback:
- Modify the example to start SmartConfig only when a GPIO button is pressed.
- Use another GPIO pin connected to an LED to provide feedback:
- LED OFF: Idle or connected.
- LED Blinking Slowly: SmartConfig mode active, waiting for credentials.
- LED Blinking Fast: Credentials received, attempting to connect.
- LED Solid ON: Successfully connected to WiFi.
- Remember to handle button debouncing.
- Provisioning Fallback: WPS then SmartConfig:
- Combine the knowledge from Chapter 40 (WPS) and this chapter.
- Implement a system where the ESP32 first tries WPS PBC mode for a certain duration (e.g., 2 minutes).
- If WPS fails or times out, automatically switch to SmartConfig mode.
- Provide serial log feedback about which mode is active.
- Store Credentials in NVS:
- After successfully receiving credentials via SmartConfig and connecting to the WiFi, save the SSID and password to Non-Volatile Storage (NVS).
- On the next boot, modify
initialise_wifi()
to first attempt to load credentials from NVS. - If credentials exist in NVS, try to connect using them directly.
- If no credentials are in NVS, or if connection with stored credentials fails, then initiate the SmartConfig process.
Summary
- WPS (WiFi Protected Setup) and SmartConfig are two methods for simplifying WiFi provisioning on ESP32 devices.
- WPS involves PBC (Push Button) or PIN methods, requiring interaction with the router.
- SmartConfig, an Espressif technology, uses a smartphone app to broadcast SSID/password to the ESP32, which sniffs packets to decode them.
- SmartConfig is user-friendly as it primarily involves interaction with a mobile app and doesn’t require physical access to the router for button presses.
- ESP-IDF provides
esp_smartconfig_start()
,esp_smartconfig_stop()
, andSC_EVENT
s to manage the SmartConfig process. - Key SmartConfig events include
SC_EVENT_GOT_SSID_PSWD
, which provides the credentials. - After receiving credentials,
esp_smartconfig_stop()
must be called, followed by configuring and connecting the WiFi station. - SmartConfig is supported on ESP32, ESP32-S2, ESP32-S3, ESP32-C3, and ESP32-C6. It’s not applicable to ESP32-H2 (no WiFi).
- Common issues involve phone network settings (2.4GHz vs 5GHz), router configurations (AP isolation, multicast filtering), and correct app usage.
Further Reading
- ESP-IDF SmartConfig API Reference: https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/api-reference/network/esp_smartconfig.html
- ESP-IDF WiFi Driver API Reference (for general WiFi functions): https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/api-reference/network/esp_wifi.html
- Esptouch Protocol Overview (for deeper understanding): While specific protocol documents might vary, searching for “Esptouch protocol” or “ESP-TOUCH v2 protocol” can yield more details.
- ESP-IDF Examples: Check the
$IDF_PATH/examples/wifi/smart_config
directory in your ESP-IDF installation for an official example project.
