Arduino IDE 中为 ESP32-S3 实现 SmartConfig(一键配网)

在 Arduino IDE 中为 ESP32-S3 实现 SmartConfig(一键配网)主要依赖 WiFi.h 库。以下是完整的实现方案,包含环境配置、核心代码逻辑以及关键的注意事项。

  1. 环境准备

确保你的 Arduino IDE 已安装 ESP32 开发板支持:

  1. 打开 文件 -> 首选项。
  2. 在“附加开发板管理器网址”中添加:https://espressif.github.io/arduino-esp32/package_esp32_index.json
  3. 打开 工具 -> 开发板 -> 开发板管理器,搜索 esp32 并安装由 Espressif Systems 提供的包。
  4. 在 工具 -> 开发板 中选择 ESP32S3 Dev Module(根据你的具体模块型号选择,如 NodeMCU-32S 等也可通用,但 S3 建议选专用项以优化引脚映射)。

  5. 核心代码实现

这段代码实现了以下逻辑:

  • 上电检查:尝试连接之前保存的 Wi-Fi。
  • 自动进入配网模式:如果未连接成功,自动启动 SmartConfig 监听。
  • 状态反馈:通过串口监视器打印配网进度。
  • 持久化存储:配网成功后将 SSID 和密码存入 NVS(非易失性存储),下次重启自动连接。
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);
}
  1. 如何使用与测试

  2. 上传代码:将上述代码上传到 ESP32-S3。

  3. 打开串口监视器:波特率设置为 115200。
  4. 手机端操作:
    • 下载并安装 乐鑫 ESP-Touch APP(Android/iOS 均有)或使用微信/支付宝中支持 SmartConfig 的小程序(如“安信可配网”等)。
    • 确保手机连接到你要让 ESP32 连接的 2.4GHz Wi-Fi(ESP32-S3 不支持 5GHz Wi-Fi 配网)。
    • 在 APP 中输入 Wi-Fi 密码,点击“开始配网”。
  5. 观察结果:

    • 串口监视器会显示 . 表示正在监听。
    • 一旦手机发送成功,ESP32 会打印出 SSID 和密码,并显示“连接成功”及 IP 地址。
    • 重启 ESP32,它应该能自动连接该 Wi-Fi,无需再次配网。
  6. 常见问题排查

  7. 配网失败/超时:

    • 频段问题:务必确认手机连接的是 2.4GHz Wi-Fi,而不是 5GHz。这是最常见的失败原因。
    • 距离问题:配网时,手机尽量靠近 ESP32-S3 开发板。
    • 路由器设置:部分路由器开启了“AP隔离”或禁用了广播/组播,这会导致 SmartConfig 失败。尝试关闭这些功能或使用手机热点测试。
  8. 编译错误:

    • 确保安装了最新版的 ESP32 Arduino 核心库。
    • 如果提示 nvs_flash.h 找不到,请检查开发板包是否完整安装,或者尝试使用 Preferences.h 库来替代 NVS 直接操作(Arduino 风格更常用 Preferences)。
  9. 替代方案(使用 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 键):

  1. ‌上电检测‌:如果检测到按键被按下,则清除所有保存的 Wi-Fi 配置并重启,强制进入配网模式。
  2. ‌正常启动‌:如果未按键,则尝试连接已保存的 Wi-Fi;若失败,自动进入 SmartConfig。

这种设计既满足了“用户选择是否清除”的需求,又避免了每次重启都擦除 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");
}

代码实现特点说明

  1. ‌安全的清除机制‌:
    • 使用了 Preferences 库而非直接操作底层 NVS API,代码更简洁且兼容性好。
    • 通过 preferences.clear() 仅清除名为 wifi_cred 的命名空间,不会影响其他可能存储的数据。
    • 引入了 esp_restart(),在清除配置后立即重启,确保系统状态干净,避免残留内存状态影响后续配网。
  2. ‌用户交互设计‌:
    • ‌物理触发‌:利用 ESP32-S3 开发板上自带的 BOOT 键(GPIO 0)。上电时若按住该键,系统会识别为“恢复出厂设置”指令。
    • ‌防误触‌:加入了 delay(1000) 和按键状态检测,只有在上电初期持续按下才会触发清除,正常重启不会误删配置。
  3. ‌健壮的连接逻辑‌:
    • ‌自动 fallback‌:优先尝试连接旧配置,失败后自动进入 SmartConfig 监听,无需手动干预。
    • ‌超时保护‌:SmartConfig 和 Wi-Fi 连接均设置了超时时间,防止程序死锁在等待状态。
    • ‌资源释放‌:配网成功后立即调用 WiFi.stopSmartConfig(),释放混杂模式占用的资源,降低功耗。
  4. ‌持久化存储‌:
    • 配网成功后,SSID 和密码会被写入 Flash 中的 NVS 区域。
    • 下次断电重启后,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博客

JSRUN前端笔记, 是针对前端工程师开放的一个笔记分享平台,是前端工程师记录重点、分享经验的一个笔记本。JSRUN前端采用的 MarkDown 语法 (极客专用语法), 这里属于IT工程师。