【ESP32-IDF】网络连接开发2:Wi‑Fi 智能配网(SmartConfig)
本文介绍了ESP32的SmartConfig智能配网技术,通过手机App实现Wi-Fi信息自动传输,避免了代码硬编码的不便。文章概述了SmartConfig的工作原理和三种协议类型(ESPTouch、Airkiss和ESPTouch v2),重点讲解了ESPTouch v2的安全改进。提供了相关API说明和示例程序,演示了ESP32如何进入配网模式、接收Wi-Fi信息并自动连接。该方案适用于无屏幕
系列文章目录
持续更新…
文章目录
前言
在物联网设备开发过程中,如果将 Wi-Fi 的 SSID 和密码直接写死在程序中肯定不合理。为了解决这一问题,ESP32 提供了多种 配网方式,其中 SmartConfig 智能配网(又称“一键配网”)是一种常用且高效的方案。SmartConfig 可以让用户通过手机 App 将 Wi-Fi 网络的名称和密码发送给 ESP32 设备,从而避免在代码中硬编码 Wi-Fi 信息。本篇文章将基于最新的 ESP-IDF,介绍 Wi-Fi SmartConfig 的原理和使用方法,并重点演示 Espressif 自家的 ESPTouch 智能配网方式。
一、Wi‑Fi 智能配网概述
1.SmartConfig 简介
SmartConfig 是由德州仪器(TI)开发的一种 Wi-Fi 配网技术,用于将新的 Wi-Fi 设备连接到目标路由器。它的特点是在不建立传统网络连接的情况下,由手机等移动设备将 Wi-Fi 凭据通过广播的方式发送给待配网的设备。对于那些没有屏幕或输入接口的“无头”设备来说,SmartConfig 提供了一种简便的配网途径。利用 SmartConfig,用户无需直接在设备上输入或预先配置 Wi-Fi SSID 和密码,设备通电后进入配网模式,几分钟内即可完成网络连接。
2.SmartConfig 工作原理
SmartConfig 的实现原理是利用手机和路由器的广播机制传递 Wi-Fi 信息。在配网过程中,手机通过 App 将包含 Wi-Fi SSID 和密码的内容编码进一系列特殊的 UDP 广播数据包中,并在无线网络中发送出来。
ESP32 设备启动 SmartConfig 后,会进入 Wi-Fi 混杂模式轮循监听各个信道上的数据帧。当设备捕获到符合特定编码规则的广播包时,就能解析出其中包含的 Wi-Fi 名称和密码,并据此配置 ESP32 的 Wi-Fi STA 模式连接到对应的 AP(路由器)。如果在当前信道未能监听到有效数据,设备会切换到下一个信道继续监听,直到成功获取 Wi-Fi 信息为止。整个过程无需让手机直接与设备建立连接,避免了手动连接热点等繁琐步骤。
3.SmartConfig 协议类型
ESP32 平台目前支持三种类型的 SmartConfig 协议:Airkiss、ESPTouch 和 ESPTouch v2。其中,Airkiss 是腾讯微信推出的配网协议,常用于微信硬件平台;ESPTouch 则是乐鑫提供的官方配网协议,对应 Espressif 提供的手机 App(ESP-Touch)。开发者可以根据需求调用接口设定 SmartConfig 的类型。
需要特别说明的是 ESPTouch v2:从 SmartConfig v3.0 开始,ESP-IDF 新增了对 ESPTouch v2 的支持。相比传统的 ESPTouch,v2 版本采用了全新的算法提高了配网速度,并增加了 AES 加密传输和自定义数据字段等功能。这意味着在使用 ESPTouch v2 时,Wi-Fi 密码等敏感信息可以加密广播,提高了配网的安全性;但同时由于加密过程增加了数据传输量,在开启随机 IV(初始化向量)等安全特性时,配网所需时间可能略有增加。一般情况下,使用 ESPTouch(包括 v2)方式能满足多数应用需求。本文的示例也将采用 Espressif 官方的 ESPTouch 方法进行演示。
二、Wi‑Fi 智能配网类型定义及相关API
需包含头文件:esp_smartconfig.h:
Wi‑Fi 智能配网类型定义
/** SmartConfig 配网协议类型枚举 */
typedef enum {
SC_TYPE_ESPTOUCH = 0, // ESPTouch 配网(Espressif 官方协议)
SC_TYPE_AIRKISS, // AirKiss 配网(腾讯微信协议)
SC_TYPE_ESPTOUCH_AIRKISS,// 组合配网模式(同时兼容 ESPTouch 和 AirKiss)
SC_TYPE_ESPTOUCH_V2 // ESPTouch v2 配网(包含AES加密的改进版)
} smartconfig_type_t;
/** SmartConfig 配网过程事件枚举 */
typedef enum {
SC_EVENT_SCAN_DONE, // 已完成周围 Wi-Fi 信道扫描
SC_EVENT_FOUND_CHANNEL, // 已找到目标路由器所在信道
SC_EVENT_GOT_SSID_PSWD, // 已获取到 Wi-Fi 的 SSID 和密码
SC_EVENT_SEND_ACK_DONE // 已发送确认信息(ACK)给手机端
} smartconfig_event_t;
/* ===== GOT_SSID_PSWD 事件的数据结构 =====
* 当拿到凭据时,事件回调会携带此结构体(从中取 ssid/password/bssid 等)
*/
typedef struct {
uint8_t ssid[32]; /* 目标 AP SSID(以 '\0' 结尾) */
uint8_t password[64]; /* 对应密码(以 '\0' 结尾) */
bool bssid_set; /* 是否携带并使用 BSSID(MAC)定向入网 */
uint8_t bssid[6]; /* 目标 AP 的 BSSID(当 bssid_set = true 时有效) */
smartconfig_type_t type; /* 本次实际使用的协议类型(ESPTouch / AirKiss) */
uint8_t token; /* 与手机 App 通讯用的 token(ACK 用) */
uint8_t cellphone_ip[4]; /* 手机的 IPv4 地址(便于双向确认) */
} smartconfig_event_got_ssid_pswd_t;
/* ===== SmartConfig 启动配置 =====
* 可开启日志、ESPTouch v2 加密(需 16 字节密钥)
*/
typedef struct {
bool enable_log; /* 配网过程打印日志(默认 false) */
bool esp_touch_v2_enable_crypt; /* 开启 v2 加密(true/false) */
char *esp_touch_v2_key; /* v2 加密密钥,长度需为 16 字节 */
} smartconfig_start_config_t;
Wi‑Fi 智能配网相关API
// 获取 SmartConfig 库版本号字符串
const char *esp_smartconfig_get_version(void);
// 开始 SmartConfig 配网(Station 或 SoftAP-Sta模式下调用)
esp_err_t esp_smartconfig_start(const smartconfig_start_config_t *config);
// 停止 SmartConfig 配网并释放资源(无论成功与否都应调用)
esp_err_t esp_smartconfig_stop(void);
// 设置 SmartConfig 配网超时时间(单位秒,15~255,默认加45秒偏移,从寻找信道开始计时)
esp_err_t esp_esptouch_set_timeout(uint8_t time_s);
// 设置 SmartConfig 配网协议类型(需在 esp_smartconfig_start 之前调用)
esp_err_t esp_smartconfig_set_type(smartconfig_type_t type);
// 设置是否启用快速模式(需在 esp_smartconfig_start 之前调用)
esp_err_t esp_smartconfig_fast_mode(bool enable);
// 获取 ESPTouch v2 配网的预留数据(在 SC_EVENT_GOT_SSID_PSWD 事件后调用)
esp_err_t esp_smartconfig_get_rvd_data(uint8_t *rvd_data, uint8_t len);
三、Wi‑Fi 智能配网示例程序
本程序演示如何使用ESP-Touch智能配网功能。
让ESP32通过手机APP自动获取WiFi的SSID和密码,无需在代码中硬编码 WiFi 信息。
/*
* ESP32-S3 智能配网(SmartConfig)示例
*
* 本程序演示如何使用ESP-Touch智能配网功能,让ESP32通过手机APP
* 自动获取WiFi的SSID和密码,无需在代码中硬编码WiFi信息。
*
* 智能配网流程:
* 1. ESP32启动后进入SmartConfig模式,等待配网
* 2. 用户使用手机APP(如ESP-Touch)发送WiFi信息
* 3. ESP32接收到WiFi信息后自动连接
* 4. 连接成功后退出配网模式
*
*/
#include <string.h> // 字符串处理函数
#include "freertos/FreeRTOS.h" // FreeRTOS实时操作系统
#include "freertos/task.h" // 任务管理
#include "freertos/event_groups.h" // 事件组(用于任务间通信)
#include "esp_wifi.h" // WiFi驱动
#include "esp_event.h" // 事件处理
#include "esp_smartconfig.h" // 智能配网功能
#include "esp_netif.h" // 网络接口
#include "nvs_flash.h" // 非易失性存储
#include "esp_log.h" // 日志输出
// ======================== 事件位定义 ========================
// 使用事件组来标记不同的状态
static const int CONNECTED_BIT = BIT0; // 位0:WiFi连接成功标志
static const int ESPTOUCH_DONE_BIT = BIT1; // 位1:ESP-Touch配网完成标志
// ======================== 全局变量 ========================
static EventGroupHandle_t s_wifi_event_group; // 事件组句柄,用于任务间通信
static const char *TAG = "smartconfig"; // 日志标签
/*
* 事件处理函数 - 处理WiFi和SmartConfig相关事件
*
* 参数说明:
* - arg: 用户数据(本例中未使用)
* - event_base: 事件类型(WIFI_EVENT、IP_EVENT、SC_EVENT等)
* - event_id: 具体的事件ID
* - event_data: 事件携带的数据
*
* 这个函数会在WiFi状态或SmartConfig状态发生变化时自动被调用
*/
static void event_handler(void *arg, // 用户参数(未使用)
esp_event_base_t event_base, // 事件基础类型
int32_t event_id, // 事件ID
void *event_data) // 事件数据
{
// 处理WiFi STA启动事件
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
{
esp_wifi_connect(); // WiFi启动后立即尝试连接
ESP_LOGI(TAG, "WiFi STA启动,开始连接...");
}
// 处理WiFi断开连接事件
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
{
esp_wifi_connect(); // 断开后自动重连
ESP_LOGI(TAG, "WiFi断开连接,正在重连...");
}
// 处理获取IP地址事件
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;
char ip[16];
esp_ip4addr_ntoa(&event->ip_info.ip, ip, sizeof(ip));
ESP_LOGI(TAG, "🎉 WiFi连接成功!获取到IP地址: %s", ip);
xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT); // 设置连接成功标志
}
// 处理SmartConfig扫描完成事件
else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE)
{
ESP_LOGI(TAG, "SmartConfig扫描完成");
}
// 处理SmartConfig找到信道事件
else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL)
{
ESP_LOGI(TAG, "SmartConfig找到目标信道");
}
// 处理SmartConfig获取SSID和密码事件
else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD)
{
ESP_LOGI(TAG, "SmartConfig获取到WiFi信息");
// 获取SmartConfig传递的WiFi信息
smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
wifi_config_t wifi_config; // WiFi配置结构体
bzero(&wifi_config, sizeof(wifi_config)); // 清零配置结构体
// 复制SSID和密码到WiFi配置中
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
ESP_LOGI(TAG, "SSID: %s", wifi_config.sta.ssid);
ESP_LOGI(TAG, "密码: %s", wifi_config.sta.password);
// 先断开当前连接,然后应用新的WiFi配置
esp_wifi_disconnect(); // 断开当前连接
esp_wifi_set_config(WIFI_IF_STA, &wifi_config); // 设置新的WiFi配置
esp_wifi_connect(); // 使用新配置连接WiFi
}
// 处理SmartConfig发送确认完成事件
else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE)
{
ESP_LOGI(TAG, "✅ SmartConfig配网完成");
xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT); // 设置配网完成标志
}
}
/*
* SmartConfig任务函数
*
* 这个任务负责:
* 1. 启动ESP-Touch智能配网
* 2. 等待WiFi连接成功或配网完成
* 3. 配网完成后停止SmartConfig并删除自己
*
* 参数:parm - 任务参数(未使用)
*/
static void smartconfig_task(void *parm) // 任务参数(未使用)
{
EventBits_t uxBits; // 用于接收事件位的变量
ESP_LOGI(TAG, "启动SmartConfig配网任务");
// 配置SmartConfig参数
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT(); // 使用默认配置
esp_smartconfig_set_type(SC_TYPE_ESPTOUCH); // 设置配网类型为ESP-Touch
esp_smartconfig_start(&cfg); // 启动SmartConfig
ESP_LOGI(TAG, "请使用ESP-Touch手机APP进行配网");
ESP_LOGI(TAG, "等待手机发送WiFi配置信息...");
// 主循环:等待事件
while (1)
{
// 等待事件位:WiFi连接成功 或 ESP-Touch配网完成
uxBits = xEventGroupWaitBits(s_wifi_event_group, // 事件组句柄
CONNECTED_BIT | ESPTOUCH_DONE_BIT, // 等待的事件位
true, // 读取后清除事件位
false, // 只要有一个事件位被设置就返回
portMAX_DELAY); // 无限等待
// 检查WiFi是否连接成功
if (uxBits & CONNECTED_BIT)
{
ESP_LOGI(TAG, "WiFi连接成功!");
}
// 检查ESP-Touch配网是否完成
if (uxBits & ESPTOUCH_DONE_BIT)
{
ESP_LOGI(TAG, "ESP-Touch配网流程完成");
esp_smartconfig_stop(); // 停止SmartConfig
ESP_LOGI(TAG, "SmartConfig已停止");
vTaskDelete(NULL); // 删除当前任务(自我删除)
}
}
}
/*
* WiFi初始化函数
*
* 这个函数完成以下工作:
* 1. 初始化网络栈和事件循环
* 2. 创建WiFi STA接口
* 3. 初始化WiFi驱动
* 4. 创建事件组
* 5. 注册事件处理函数
* 6. 设置WiFi模式并启动
*/
static void wifi_init(void)
{
ESP_LOGI(TAG, "🔧 开始初始化WiFi系统");
// 第1步:初始化网络接口层
ESP_ERROR_CHECK(esp_netif_init()); // 初始化TCP/IP网络栈
// 第2步:创建默认事件循环
ESP_ERROR_CHECK(esp_event_loop_create_default()); // 创建默认事件循环
// 第3步:创建默认WiFi STA接口
esp_netif_create_default_wifi_sta(); // 创建STA网络接口
// 第4步:初始化WiFi驱动
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); // 使用默认WiFi配置
ESP_ERROR_CHECK(esp_wifi_init(&cfg)); // 初始化WiFi驱动
// 第5步:创建事件组(用于任务间通信)
s_wifi_event_group = xEventGroupCreate(); // 创建事件组
// 第6步:注册事件处理函数
// 注册WiFi事件处理器
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, // 事件类型:WiFi事件
ESP_EVENT_ANY_ID, // 事件ID:所有WiFi事件
&event_handler, // 事件处理函数
NULL, // 用户数据
NULL)); // 事件处理器实例
// 注册IP事件处理器
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, // 事件类型:IP事件
IP_EVENT_STA_GOT_IP, // 事件ID:获取IP地址
&event_handler, // 事件处理函数
NULL, // 用户数据
NULL)); // 事件处理器实例
// 注册SmartConfig事件处理器
ESP_ERROR_CHECK(esp_event_handler_instance_register(SC_EVENT, // 事件类型:SmartConfig事件
ESP_EVENT_ANY_ID, // 事件ID:所有SC事件
&event_handler, // 事件处理函数
NULL, // 用户数据
NULL)); // 事件处理器实例
// 第7步:设置WiFi模式并启动
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); // 设置为STA(客户端)模式
ESP_ERROR_CHECK(esp_wifi_start()); // 启动WiFi
ESP_LOGI(TAG, "✅ WiFi系统初始化完成");
}
/*
* 程序主入口函数
*
* 这是ESP32程序的起始点,完成以下工作:
* 1. 初始化NVS存储
* 2. 清除之前保存的WiFi配置(可选)
* 3. 初始化WiFi系统
* 4. 创建SmartConfig配网任务
*/
void app_main(void)
{
ESP_LOGI(TAG, "ESP32 SmartConfig智能配网程序启动");
// 第1步:初始化NVS存储
esp_err_t ret = nvs_flash_init(); // 初始化NVS
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
{
ESP_ERROR_CHECK(nvs_flash_erase()); // 如果有问题就擦除
ESP_ERROR_CHECK(nvs_flash_init()); // 重新初始化
}
ESP_LOGI(TAG, "✅ NVS存储初始化完成");
// 第2步:清除之前保存的WiFi配置(强制重新配网)
// 注意:如果您希望保留之前的WiFi配置,请注释掉下面这行
ESP_ERROR_CHECK(nvs_flash_erase_partition("nvs"));
ESP_ERROR_CHECK(nvs_flash_init());
ESP_LOGI(TAG, "已清除之前的WiFi配置,强制重新配网");
// 第3步:初始化WiFi系统
wifi_init(); // 调用WiFi初始化函数
// 第4步:创建SmartConfig配网任务
xTaskCreate(smartconfig_task, // 任务函数
"smartconfig_task", // 任务名称
4096, // 任务堆栈大小(字节)
NULL, // 任务参数
3, // 任务优先级
NULL); // 任务句柄
ESP_LOGI(TAG, "SmartConfig任务已创建");
ESP_LOGI(TAG, "系统已准备就绪,等待配网...");
}
总结
通过本篇内容,我们了解了 SmartConfig 智能配网的原理和使用方法。在 ESP32 上利用 SmartConfig,可以让设备在运行时通过手机快速获取 Wi-Fi 凭据,实现 开箱即用 的联网体验。文中介绍了 ESPTouch 和 Airkiss 两种主要协议及其区别,并基于最新 ESP-IDF 提供的 API 展示了如何在代码中集成 SmartConfig 功能。希望通过本文的讲解,开发者可以熟练运用 SmartConfig,为自己的 ESP32 项目实现更加灵活友好的网络配置功能。
更多推荐
所有评论(0)