在 Arduino IDE 中为 ESP32-S3 实现 SmartConfig(一键配网)主要依赖 WiFi.h 库。以下是完整的实现方案,包含环境配置、核心代码逻辑以及关键的注意事项。
确保你的 Arduino IDE 已安装 ESP32 开发板支持:
https://espressif.github.io/arduino-esp32/package_esp32_index.jsonesp32 并安装由 Espressif Systems 提供的包。在 工具 -> 开发板 中选择 ESP32S3 Dev Module(根据你的具体模块型号选择,如 NodeMCU-32S 等也可通用,但 S3 建议选专用项以优化引脚映射)。
核心代码实现
这段代码实现了以下逻辑:
include <WiFi.h>
include <nvs_flash.h> // 用于存储Wi-Fi信息
// 定义配网超时时间 (秒)
define SMART_CONFIG_TIMEOUT 120
void setup() {
Serial.begin(115200);
// 1. 初始化 NVS (用于保存Wi-Fi凭证)
esp_err_t err = nvs_flash_init();
if (err != ESP_OK) {
nvs_flash_erase();
nvs_flash_init();
}
// 2. 尝试连接之前保存的 Wi-Fi
if (!connectToSavedWifi()) {
Serial.println("未找到已保存的Wi-Fi或连接失败,进入SmartConfig配网模式...");
startSmartConfig();
} else {
Serial.println("已成功连接到已保存的Wi-Fi网络");
}
}
void loop() {
// 主循环中可以处理其他业务逻辑
// 例如:检查网络连接状态,如果断开则重新触发配网或重连
if (WiFi.status() != WL_CONNECTED) {
// 可选:添加断线重连逻辑或再次进入配网模式的触发条件
}
delay(1000);
}
/**
* @brief 尝试从NVS读取并连接Wi-Fi
* @return true 连接成功, false 连接失败或无保存信息
*/
bool connectToSavedWifi() {
nvs_handle_t my_handle;
char ssid = {0};
char password = {0};
// 打开NVS句柄
esp_err_t err = nvs_open("wifi_cred", NVS_READONLY, &my_handle);
if (err != ESP_OK) return false;
// 读取SSID
size_t len = sizeof(ssid);
err = nvs_get_str(my_handle, "ssid", ssid, &len);
if (err != ESP_OK) {
nvs_close(my_handle);
return false;
}
// 读取Password
len = sizeof(password);
err = nvs_get_str(my_handle, "password", password, &len);
nvs_close(my_handle);
if (err != ESP_OK) return false;
Serial.print("正在连接 Wi-Fi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
// 等待连接,最多等待10秒
int timeout = 0;
while (WiFi.status() != WL_CONNECTED && timeout < 100) {
delay(100);
Serial.print(".");
timeout++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n连接成功!");
Serial.print("IP地址: ");
Serial.println(WiFi.localIP());
return true;
} else {
Serial.println("\n连接超时");
return false;
}
}
/**
* @brief 启动 SmartConfig 配网流程
*/
void startSmartConfig() {
// 设置Wi-Fi为STA模式
WiFi.mode(WIFI_STA);
Serial.println("等待手机APP发送配网信息...");
Serial.println("请使用乐鑫 ESP-Touch APP 或支持 SmartConfig 的小程序");
// 开始 SmartConfig
WiFi.beginSmartConfig();
unsigned long startTime = millis();
// 等待配网数据
while (!WiFi.smartConfigDone()) {
// 超时检查
if (millis() - startTime > SMART_CONFIG_TIMEOUT * 1000) {
Serial.println("SmartConfig 超时,请重试");
WiFi.stopSmartConfig();
return;
}
delay(500);
Serial.print(".");
}
Serial.println("\nSmartConfig 接收成功!");
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
Serial.print("Password: ");
Serial.println(WiFi.psk());
// 停止 SmartConfig 以释放资源
WiFi.stopSmartConfig();
// 连接 Wi-Fi
WiFi.begin(WiFi.SSID().c_str(), WiFi.psk().c_str());
// 等待连接
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWi-Fi 连接成功!");
Serial.print("IP地址: ");
Serial.println(WiFi.localIP());
// 保存凭证到 NVS
saveWifiCredentials(WiFi.SSID().c_str(), WiFi.psk().c_str());
}
/**
* @brief 将Wi-Fi凭证保存到NVS
*/
void saveWifiCredentials(const char* ssid, const char* password) {
nvs_handle_t my_handle;
esp_err_t err = nvs_open("wifi_cred", NVS_READWRITE, &my_handle);
if (err != ESP_OK) return;
err = nvs_set_str(my_handle, "ssid", ssid);
if (err == ESP_OK) {
err = nvs_set_str(my_handle, "password", password);
}
if (err == ESP_OK) {
err = nvs_commit(my_handle);
if (err == ESP_OK) {
Serial.println("Wi-Fi 凭证已保存");
}
}
nvs_close(my_handle);
}
如何使用与测试
上传代码:将上述代码上传到 ESP32-S3。
115200。观察结果:
. 表示正在监听。常见问题排查
配网失败/超时:
编译错误:
nvs_flash.h 找不到,请检查开发板包是否完整安装,或者尝试使用 Preferences.h 库来替代 NVS 直接操作(Arduino 风格更常用 Preferences)。替代方案(使用 Preferences 库简化存储):
如果觉得 NVS 原生 API 复杂,可以使用 Arduino 自带的 Preferences 库替换 saveWifiCredentials 和 connectToSavedWifi 中的 NVS 部分,代码会更简洁:
include <Preferences.h>
Preferences preferences;
// 保存
preferences.begin("wifi", false);
preferences.putString("ssid", ssid);
preferences.putString("password", password);
preferences.end();
// 读取
preferences.begin("wifi", true);
String ssid = preferences.getString("ssid", "");
String password = preferences.getString("password", "");
preferences.end();
通过以上步骤,你可以在 Arduino IDE 中轻松为 ESP32-S3 实现稳定的一键配网功能。
参考资料
[1] 手把手教你用ESP32实现SmartConfig一键配网(附Arduino代码与常见失败排查)-CSDN博客 - CSDN博客
[2] 智能家居入门:用Arduino IDE实现网页控制LED(含SmartConfig配网教程) - CSDN博客
[3] ESP32智能家居入门:用Arduino IDE实现网页远程控制LED(含SmartConfig配网教程)-CSDN博客 - CSDN博客
[4] ESP32 Arduino环境搭建实战:一键配网功能实现-CSDN博客 - CSDN博客
[5] 避坑指南:ESP32 SmartConfig配网总失败?这3个环境因素和2个代码细节要注意 - CSDN博客
[6] esp32s3 smartconfig 配网,手机没收到成功信息 - 博客
[7] ESP32-S3配网小程序连接失败,常见原因有哪些?_编程语言-CSDN问答 - CSDN问答
[8] esp32通过smartconfig连接wifi - CSDN博客
[9] 【Arduino】实验ESP32单片机自动配置Wifi功能(图文) - CSDN博客
[10] ESP32-S3 配网全解|蓝牙小程序配网、AP 热点配网,HTTP 服务 + DNS 劫持实现 - 奔跑的王师兄
[11] README.md · houguoxiong/esp32s3_ai_chat_baidu_appbuilder - Gitee.com - gitee.com
[12] README.md · tangyiyong/esp32s3-ai-chat - Gitee.com - gitee.com
[13] ESP32-S3-Nano物联网模块开发全攻略:从硬件解析到项目实战 - CSDN博客
[14] ESP32-S3单路继电器模块:从硬件设计到智能控制节点的完整开发指南 - CSDN博客
[15] ESP32-S3 SmartConfig一键配网 - CSDN博客
[16] ESP32 S3学习记录-wifi模块之一键配网-Smartconfig(七) - CSDN博客
[17] 第五十一章 ESP32S3 WiFi 一键配网 - CSDN博客
[18] ESP32学习笔记(基于IDF):SmartConfig一键配网 - CSDN博客
[19] 告别手动配网!用ESP32+巴法云实现智能家居设备一键配网(Arduino IDE保姆级教程) - CSDN博客
[20] esp32s3-idf使用smart_config一键配网 - CSDN博客
[21] ESP32 Smart Config一键配网原理与MicroPython实现 - CSDN博客
百度AI生成,内容仅供参考
上述NVS部分,能否加入nvs_flash_erase(),让用户选择是否彻底清除NVS内容。
在 Arduino IDE 环境下,直接调用底层的 nvs_flash_erase() 需要引入 ESP-IDF 的头文件,这可能会增加编译配置的复杂性。更推荐且符合 Arduino 风格的做法是使用 Preferences 库的 clear() 方法,或者通过一个特定的“清除标志”来触发重置逻辑。
以下是优化后的代码方案。我添加了一个物理按键触发机制(默认使用 GPIO 0,即 ESP32-S3 开发板上常见的 BOOT 键):
这种设计既满足了“用户选择是否清除”的需求,又避免了每次重启都擦除 Flash,延长了芯片寿命。
#include <WiFi.h>
#include <Preferences.h>
#include <esp_system.h> // 用于 esp_restart()
// 定义引脚:BOOT按钮通常连接到 GPIO 0
#define RESET_BUTTON_PIN 0
// 定义配网超时时间 (秒)
#define SMART_CONFIG_TIMEOUT 120
Preferences preferences;
void setup() {
Serial.begin(115200);
// 初始化按键输入
pinMode(RESET_BUTTON_PIN, INPUT_PULLUP);
// 延迟一小段时间,确保用户有机会在启动时按下按键
delay(1000);
// 检查是否按下了重置键
if (digitalRead(RESET_BUTTON_PIN) == LOW) {
Serial.println("检测到重置按键,正在清除 Wi-Fi 配置...");
clearWifiConfig();
Serial.println("配置已清除,即将重启...");
delay(2000);
esp_restart(); // 重启设备
return;
}
// 尝试连接之前保存的 Wi-Fi
if (!connectToSavedWifi()) {
Serial.println("未连接成功,进入 SmartConfig 配网模式...");
startSmartConfig();
} else {
Serial.println("已成功连接到已保存的 Wi-Fi 网络");
}
}
void loop() {
// 主循环保持运行
if (WiFi.status() != WL_CONNECTED) {
// 可以在这里添加断线重连逻辑
}
delay(1000);
}
/**
* @brief 清除 NVS 中的 Wi-Fi 配置
*/
void clearWifiConfig() {
preferences.begin("wifi_cred", false); // false 表示读写模式
preferences.clear(); // 清除该命名空间下的所有键值对
preferences.end();
Serial.println("NVS Wi-Fi 配置已清除");
}
/**
* @brief 尝试从 Preferences 读取并连接 Wi-Fi
* @return true 连接成功, false 连接失败或无保存信息
*/
bool connectToSavedWifi() {
preferences.begin("wifi_cred", true); // true 表示只读模式
String ssid = preferences.getString("ssid", "");
String password = preferences.getString("password", "");
preferences.end();
if (ssid.length() == 0) {
Serial.println("NVS 中无保存的 Wi-Fi 信息");
return false;
}
Serial.print("正在连接 Wi-Fi: ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid.c_str(), password.c_str());
// 等待连接,最多等待 15 秒
int timeout = 0;
while (WiFi.status() != WL_CONNECTED && timeout < 150) {
delay(100);
Serial.print(".");
timeout++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n连接成功!");
Serial.print("IP 地址: ");
Serial.println(WiFi.localIP());
return true;
} else {
Serial.println("\n连接超时或失败");
WiFi.disconnect();
return false;
}
}
/**
* @brief 启动 SmartConfig 配网流程
*/
void startSmartConfig() {
WiFi.mode(WIFI_STA);
WiFi.beginSmartConfig();
Serial.println("等待手机 APP 发送配网信息...");
Serial.println("请使用乐鑫 ESP-Touch APP 或支持 SmartConfig 的小程序");
Serial.println("提示:长按 BOOT 键可清除配置重新配网");
unsigned long startTime = millis();
// 等待配网数据
while (!WiFi.smartConfigDone()) {
// 超时检查
if (millis() - startTime > SMART_CONFIG_TIMEOUT * 1000) {
Serial.println("SmartConfig 超时,请重试");
WiFi.stopSmartConfig();
return;
}
delay(500);
Serial.print(".");
}
Serial.println("\nSmartConfig 接收成功!");
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// 停止 SmartConfig 以释放资源
WiFi.stopSmartConfig();
// 连接 Wi-Fi
WiFi.begin(WiFi.SSID().c_str(), WiFi.psk().c_str());
// 等待连接
int timeout = 0;
while (WiFi.status() != WL_CONNECTED && timeout < 150) {
delay(100);
Serial.print(".");
timeout++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWi-Fi 连接成功!");
Serial.print("IP 地址: ");
Serial.println(WiFi.localIP());
// 保存凭证到 Preferences
saveWifiCredentials(WiFi.SSID().c_str(), WiFi.psk().c_str());
} else {
Serial.println("\n配网后连接 Wi-Fi 失败");
}
}
/**
* @brief 将 Wi-Fi 凭证保存到 Preferences
*/
void saveWifiCredentials(const char* ssid, const char* password) {
preferences.begin("wifi_cred", false); // 读写模式
preferences.putString("ssid", ssid);
preferences.putString("password", password);
preferences.end();
Serial.println("Wi-Fi 凭证已保存至 NVS");
}
Preferences 库而非直接操作底层 NVS API,代码更简洁且兼容性好。preferences.clear() 仅清除名为 wifi_cred 的命名空间,不会影响其他可能存储的数据。esp_restart(),在清除配置后立即重启,确保系统状态干净,避免残留内存状态影响后续配网。delay(1000) 和按键状态检测,只有在上电初期持续按下才会触发清除,正常重启不会误删配置。WiFi.stopSmartConfig(),释放混杂模式占用的资源,降低功耗。connectToSavedWifi() 会自动读取并连接,实现“一次配网,永久在线”。上述NVS部分,能否加入nvs_flash_erase(),让用户选择是否彻底清除NVS内容。
共参考28篇资料
1.ESP32入门开发·SmartConfig实现配网功能-CSDN博客
2.ESP32 NVS实战:5分钟搞定WiFi密码存储与读取(附完整代码)-CSDN博客
3.esp32 smartconfig+然后保存ssid和password+tcp <----->串口通讯-CSDN博客
4.ESP32 SmartConfig配网后,如何把Wi-Fi密码‘记住’?手把手教你用NVS闪存实现-CSDN博客
5.实现ESP32来配置-CSDN博客
6.ESP32开发实战:SmartConfig配网与NVS存储的物联网应用(网页控制LED)-CSDN博客-CSDN博客
7.Arduino ESP32 对NVS数据操作测试-CSDN博客
8.ESP32存储配网信息+LED显示配网状态+按键清除配网信息(附源码) - 汉塘阿德 - 博客园-博客园
9.Arduino框架下对ESP32 NVS非易失性存储解读以及应用示例-CSDN博客
10.nvs_erase_key-博客
11.107-ESP32_SDK开发-flash数据存储nvs-腾讯云
12.Dronebridge-ESP32的数字遥测实现-腾讯云
13.《ESP32 物联网全栈实战-04》WiFi 连接——让 ESP32 上网-CSDN博客
14.ESP32-IDF开发环境搭建与Wi-Fi配网实战:从环境踩坑到量产级BLE配网方案-CSDN博客
15.3·ESP32-C3入门教程——讲透wifi模块配置(从wifi scan到smart config)-CSDN博客
16.ESP32实战指南:NVS非易失性存储的数据持久化与安全加密-CSDN博客
17.攻克ESP32存储难关:NVS、分区表与Flash操作实战指南-CSDN博客
18.esp-idf v4.0 smartconfig wifi配置信息保存在nvs_flash,实现掉电重新启动直接连入wifi(已完成)-CSDN博客
19.ESP32开发实战:基于Arduino IDE的智能配网与NVS存储应用(网页控制LED)-CSDN博客
20.【笔记2-8】ESP32:SmartConfig一键配网-CSDN博客
21.ESP32-S基于DPP-Enrollee的WiFi直连配网实战指南-CSDN博客
22.esp32通过smartconfig连接wifi-厚国兄
23.Arduino 如何烧写程序到 esp32?-微联编程
24.ESP32在尝试写入NVS时重新启动-腾讯云
25.程序运行后报错 c:/users/administrator/appdata/local/arduino15/packages/esp32/tools/riscv32-esp-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/riscv32-esp-elf/8.4.0/../../../../riscv32-esp-elf/bin/ld.exe: C:\Users\Administrator\AppData\Local\arduino\cores\60c4a54f20c83b58f77adf936afd4981\core.a(main.cpp.o): in function loopTask(void*)': C:\Users\Administrator\AppData\Local\Arduino15\packages\esp32\hardware\esp32\2.0.9\cores\esp32/main.cpp:47: undefined reference toloop()' collect2.exe: error: ld returned 1 exit status exit status 1 Compilation error: exit status 1 - CSDN文库-博客
26.Arduino密码锁实战:从硬件选型到状态机编程全解析-CSDN博客
27.UART串口回环测试:嵌入式通信调试的核心自检方法-CSDN博客
28.Arduino-ESP32 NVS存储:非易失性存储管理-CSDN博客