ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

ESP32 SmartConfig智能配网:从原理到代码实战

ESP32 SmartConfig智能配网:从原理到代码实战 不知道你有没有经历过这种场景板子做好、固件烧进去USB线一拔设备就变成了一个哑巴——没有屏幕、没有键盘、没有网页配置界面用户或者你自己根本没法告诉它家里的WiFi密码是多少。这就是嵌入式联网设备最经典的一个问题配网。这一讲要聊的Smart_config也叫SmartConfig乐鑫标准的智能配网方案就是专门解决这个问题的。它配合手机App能让ESP32在几秒钟内拿到SSID和密码完成联网整个过程不需要串口线也不需要额外接任何显示设备。基于ESP-IDF和VSCode这两个开发工具我们把SmartConfig从原理到代码、从编译到踩坑完整过一遍。本文适合两类人一是刚用VSCode搭好ESP-IDF环境、正准备让ESP32从点灯走向联网的初学者二是已经跑通基础例程、想做出用户拿到就能用的稳定配网功能的开发者。看完你会得到一个能直接编译下载的工程、一份能看懂配网日志的排查思路以及几个常规文档里不会写的经验教训。1. Smart_config能解决什么问题没屏幕没键盘的板子怎么联网1.1 三种常见配网方式的取舍先聊清楚配网到底在配什么。ESP32本身是一个WiFi设备它要上网必须知道路由器的SSID和密码。但大多数IoT设备没有键盘也没有触摸屏所以要把这两个信息塞进设备就引出了不同的配网方式。目前市面上常用的大概有三种SmartConfig智能配网、SoftAP配网、BLE蓝牙配网。我做了个对比表你可以直观感受一下差别配网方式实现复杂度用户操作适合场景SmartConfig / Esptouch低乐鑫原生支持手机连上家里WiFiApp里点一下开始配网大量量产、面向普通用户的产品成本敏感SoftAP设备开热点中需要写Web/小程序页面手机先连ESP32开的热点再在网页里输WiFi信息开发调试、带屏幕或带按键的设备BLE蓝牙配网高需要额外蓝牙协议栈和App联调手机通过蓝牙连接设备App里下发WiFi信息带BLE功能的设备适合做完整App交互闭环SmartConfig最大的优势是成本最低、体验最傻瓜。用户不需要理解热点这个概念也不需要打开浏览器输入192.168.4.1整个操作就是手机连上家里的WiFi打开乐鑫官方的配网App点一下按钮等ESP32自己连上路由器。对于做智能插座、智能灯、传感器网关这类产品这是最主流的选择。1.2 SmartConfig的底层原理把WiFi密码塞进广播包的长度里知其然也要知其所以然。SmartConfig底层到底是怎么工作的我用一句不严谨但好理解的话概括手机App把SSID和密码编码成一段特殊的无线广播数据包ESP32进入混杂监听模式抓空气里的无线帧再按协议逆向解析出SSID和密码。具体来说手机在已经连上目标WiFi后会向局域网发送一组UDP广播包。普通广播包大家都会发但SmartConfig的诀窍在于它把0和1的比特信息编码进了802.11无线帧的长度字段里。比如帧长度偏长代表1偏短代表0。ESP32在初始化的时候进入一种不加解密、来什么帧都看的混杂模式promiscuous mode扫描各个信道抓取这些帧从帧头解析出长度再把长度翻译回比特最终按照乐鑫的协议重组出完整的SSID和密码。搞清楚这个原理后面很多坑你就能自己推理出来了为什么手机连着5G WiFi经常配不上因为ESP32的混杂模式工作在2.4G频段5G的广播帧它根本收不到。为什么路由器开了AP隔离会失败因为AP隔离会阻止终端之间的广播帧转发。这些坑我放到第5章统一讲这里先记住一句话SmartConfig要求手机连的是2.4G WiFi路由器不能隔离客户端ESP32才能听到手机在说什么。2. 开发环境与手机端准备少踩一半的坑都在这里2.1 VSCode里ESP-IDF环境的版本选择与路径问题这一讲默认你已经能在VSCode里编译烧录ESP32点灯例程了。但很多人在环境配置这一步就卡住了尤其是从网上下载了某个版本结果打开工程时VSCode提示The path for ESP-IDF is not valid: /tools/idf.py not found。这个错误的本质是你告诉ESP-IDF插件ESP-IDF的安装路径在这里但插件在这个路径下找不到idf.py这个入口文件。idf.py是ESP-IDF的命令行入口它通常位于ESP-IDF根目录下和tools、components、examples这些目录平级。如果你把路径指到了某个子目录或者指到了只含工具链的espressif目录就会报这个错。解决方式分两种情况如果你用的是VSCode插件自动下载安装的ESP-IDF路径一般是C:\Users\你的用户名\esp\esp-idf\v5.4.4\这种结构重点是要确认该目录下直接有idf.py文件。如果你用的是乐鑫官方离线安装包默认会装到C:\espressif各种工具链都在里面但idf.py可能在C:\espressif\frameworks\esp-idf-v5.4.4\下你需要让VSCode的ESP-IDF插件指向这个带idf.py的目录而不是C:\espressif根目录。另外我个人的建议是不要混装多个大版本。这一讲基于ESP-IDF 5.4.x编写如果你电脑上同时有5.3、5.4、6.0多个版本VSCode左下角会显示当前使用的版本编译前养成看一眼的习惯。新版ESP-IDF对老API做了不少调整比如WiFi配置结构体成员、smartconfig事件枚举等版本不对代码可能编译不过或者行为异常。2.2 手机端App和路由器频段的硬性要求乐鑫官方配网App在iOS和Android上都能搜到关键词是ESP-WIFI-Helper也可以搜乐鑫配网或Esptouch。它同时支持ESPTOUCH协议和AirKiss协议我们设备端默认用的SC_TYPE_ESPTOUCH就是它最标准的协议。手机端有两点必须提前确认手机必须已经连接目标路由器的2.4G WiFi。很多双频路由器会把2.4G和5G合并成一个SSID也叫双频合一手机自动连上后实际上是连到了5G频段。此时发配网广播ESP32收不到。解决办法要么进路由器管理页关掉双频合一要么在手机WiFi设置里手动选择2.4G那个SSID一般有2.4G后缀或者5G后缀的别选。这是配网失败第一大原因。路由器不能开AP隔离。AP隔离也叫客户端隔离或无线隔离开启后连到同一个路由器的设备之间不能直接通信广播帧也不会互相转发。SmartConfig依赖手机到ESP32之间的无线广播报文一旦被隔离ESP32什么都收不到。如果是公司网络、访客网络默认就可能开了隔离配不上网先查这一项。3. 完整代码实现一次跑通的SmartConfig配网流程3.1 工程结构抄官方例程还是自己写乐鑫官方其实已经提供了一个非常完整的SmartConfig例程在ESP-IDF的examples/wifi/smart_config目录下。如果你是第一次接触最稳的做法是在VSCode里用ESP-IDF: Show Example Projects找到smart_config直接创建一份然后在此基础上改。这样做的好处是不用自己折腾CMakeLists和依赖声明。如果用VSCode插件创建空白工程那么main/CMakeLists.txt里需要显式依赖几个组件idf_component_register( SRCS main.c INCLUDE_DIRS . REQUIRES esp_wifi esp_event esp_netif nvs_flash smartconfig )尤其是smartconfig这个组件很多人会漏掉导致编译时报esp_smartconfig_start未定义。别问我怎么知道的我当年就在这卡了半小时。3.2 配网核心代码逐段拆解在贴完整代码之前先把两个最关键的机制讲明白。第一个是事件组Event Group。SmartConfig不是一个调用一下就返回的函数它是一套异步流程ESP32要扫描信道、收到SSID密码、连接路由器、拿到IP、给手机回ACK。这些步骤通过事件回调驱动。代码里我们用两个bit来标记流程是否完成WIFI_CONNECTED_BIT拿到了IP说明配网后的WiFi连接已经成功。ESPTOUCH_DONE_BIT手机收到了ACK说明本次配网流程已经完整走完。第二个是事件处理器event handler。ESP-IDF里所有WiFi事件、IP事件、SmartConfig事件都会派发到同一个回调函数里我们需要判断事件类型分别处理。直接看代码这是完整的main.c#include string.h #include freertos/FreeRTOS.h #include freertos/task.h #include freertos/event_groups.h #include esp_wifi.h #include esp_event.h #include esp_log.h #include esp_netif.h #include nvs_flash.h #include esp_smartconfig.h static const char *TAG smartconfig_demo; static EventGroupHandle_t s_wifi_event_group; #define WIFI_CONNECTED_BIT BIT0 #define ESPTOUCH_DONE_BIT BIT1 static smartconfig_start_config_t smartconfig_start_config { 0 }; static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { if (event_base WIFI_EVENT) { switch (event_id) { case WIFI_EVENT_STA_START: ESP_LOGI(TAG, STA started, start smartconfig...); ESP_ERROR_CHECK(esp_smartconfig_start(smartconfig_start_config)); break; case WIFI_EVENT_STA_DISCONNECTED: ESP_LOGI(TAG, disconnect from AP, retry...); esp_wifi_connect(); break; default: break; } } 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)); xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } else if (event_base SC_EVENT) { switch (event_id) { case SC_EVENT_SCAN_DONE: ESP_LOGI(TAG, smartconfig: scan done); break; case SC_EVENT_FOUND_CHANNEL: ESP_LOGI(TAG, smartconfig: found channel); break; case SC_EVENT_GOT_SSID_PSWD: { smartconfig_event_got_ssid_pswd_t *evt (smartconfig_event_got_ssid_pswd_t *)event_data; wifi_config_t wifi_config { 0 }; // 注意官方例程里用了 strlen((char*)evt-ssid) // 但更稳的做法是用事件结构体自带的 ssid_len避免某些环境下找不到结束符 memcpy(wifi_config.sta.ssid, evt-ssid, evt-ssid_len); wifi_config.sta.ssid[evt-ssid_len] \0; memcpy(wifi_config.sta.password, evt-password, evt-password_len); wifi_config.sta.password[evt-password_len] \0; ESP_LOGI(TAG, got ssid: %s, password_len: %d, wifi_config.sta.ssid, evt-password_len); // 先断开当前连接再写入目标WiFi信息并连接 esp_wifi_disconnect(); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, wifi_config)); esp_wifi_connect(); break; } case SC_EVENT_SEND_ACK_DONE: ESP_LOGI(TAG, smartconfig: ack done, stop smartconfig); xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT); esp_smartconfig_stop(); break; default: break; } } } void app_main(void) { ESP_ERROR_CHECK(nvs_flash_init()); 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)); s_wifi_event_group xEventGroupCreate(); ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL)); ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_start()); // 等待两个bit都被置位再继续往下走 EventBits_t bits xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | ESPTOUCH_DONE_BIT, pdTRUE, pdFALSE, portMAX_DELAY); if (bits WIFI_CONNECTED_BIT) { ESP_LOGI(TAG, SmartConfig and WiFi connect success!); } }这里有几个关键点值得单独拎出来说。**为什么esp_smartconfig_start要放在WIFI_EVENT_STA_START事件里而不是app_main里直接调用**因为要启动SmartConfig必须先让WiFi驱动先进入STA模式并开始工作。如果在esp_wifi_start()之后立刻调用WiFi子系统的状态可能还没就绪容易失败。放在事件回调里等于告诉系统STA已经拉起来了现在可以开始配网了。这个顺序是官方例程的标准做法建议不要乱改。**为什么SC_EVENT_GOT_SSID_PSWD里拿到SSID后要memcpy而不是直接用strcpy**因为从无线帧里解析出来的字符串不保证以\0结尾。事件结构体里提供了ssid_len和password_len这就是官方留给我们的长度信息。用memcpy拷贝指定长度再手动补一个\0是最安全的方式。如果你直接对evt-ssid调用strlen可能会越界读到随机内存打印一堆乱码甚至崩溃。**为什么收到ACK之后要调用esp_smartconfig_stop()**配网成功的标志不只是ESP32连上WiFi还要让手机App知道我已经收到密码了所以ESP32会回一个ACK包手机收到ACK后事件触发SC_EVENT_SEND_ACK_DONE。此时智能配网的任务已经完成需要调用esp_smartconfig_stop()把混杂模式关掉释放无线资源。如果不关ESP32会一直处于抓包监听状态影响正常的WiFi连接性能。3.3 一个可以直接复制的工程骨架如果你不想从例程创建也可以按照下面的结构自建一个最简工程smartconfig_demo/ ├── CMakeLists.txt └── main/ ├── CMakeLists.txt └── main.c顶层CMakeLists.txt保持ESP-IDF默认内容即可这里把main/CMakeLists.txt和main.c都贴全了。主程序就是上面那130多行代码。编译之前确认一下你VSCode左下角选的芯片型号和实际板子一致比如ESP32-S3开发板对应的target就应该设为esp32s3而不是默认的esp32。设置方式在VSCode中按CtrlShiftP执行ESP-IDF: Set Espressif Device Target然后选择你的芯片型号即可。4. 编译烧录与首次实测从日志里看懂整个配网过程4.1 VSCode里编译烧录的操作流程代码写好后在VSCode里编译烧录的完整操作我已经走了无数遍给你整理成一条龙按CtrlShiftP打开命令面板执行ESP-IDF: Build your project也可以直接点底部状态栏的齿轮图标。VSCode会自动调用cmake和ninja编译整个工程。看左下角输出窗口的编译结果出现Project build complete之类的提示就说明编译过了。如果有红色错误优先看是不是第3.1节提到的依赖缺失以及芯片型号是否选对。把ESP32开发板用USB线连到电脑注意驱动。很多板载USB转串口的芯片是CP2102或CH340Windows下如果没有驱动设备管理器里会显示感叹号需要先装驱动。在VSCode里执行ESP-IDF: Flash your project或者直接按F1输入flash。烧录时会让你选择串口号一般选新出现的那个COM口。烧录完成后执行ESP-IDF: Monitor the Device打开串口监视器波特率默认115200。如果你用的是右边那个火焰图标菜单VSCode的ESP-IDF插件会提供Build、Flash、Monitor三个常用按钮操作顺序就是先Build再Flash最后Monitor不用记命令也能跑起来。4.2 一串日志看懂整个配网状态机第一次顺利跑通后串口日志大概是这个样子I (2365) smartconfig_demo: STA started, start smartconfig... I (2571) smartconfig_demo: smartconfig: scan done I (2873) smartconfig_demo: smartconfig: found channel I (3421) smartconfig_demo: got ssid: SmartConfig_Test, password_len: 8 I (3424) smartconfig_demo: disconnect from AP, retry... I (4428) smartconfig_demo: got ip: 192.168.1.104 I (4430) smartconfig_demo: smartconfig: ack done, stop smartconfig I (4430) smartconfig_demo: SmartConfig and WiFi connect success!我来逐个解释每条日志背后的状态STA started, start smartconfig...STA模式启动代码进入了WIFI_EVENT_STA_START事件主动调用了esp_smartconfig_start()。此时ESP32已经进入混杂监听模式在2.4G信道之间跳来跳去找手机发出来的广播包。scan done完整扫描完一遍信道。found channel监听器在某一个信道上发现了疑似SmartConfig广播数据锁定该信道开始持续接收。got ssid: SmartConfig_Test, password_len: 8已经解析出SSID和密码。注意我这里没有打印密码明文只打印了密码长度。原因后面第6章会说这是产品化的基本素养。disconnect from AP, retry...代码主动调用了esp_wifi_disconnect()然后马上esp_wifi_connect()去连接目标路由器。如果你看到这条日志反复出现说明连接不上要从密码是否正确、路由器是否2.4G这两个方向排查。got ip: 192.168.1.104里程碑节点说明ESP32已经成功连上路由器并拿到IP设备真正联网了。ack done, stop smartconfigESP32给手机回执的ACK发送成功SmartConfig流程结束进入正常使用阶段。从按下App按钮到看到got ip正常情况下应该在3秒到10秒之间。如果超过30秒还停在scan done大概率是手机端的问题连着5G、开了隔离、没给App权限具体排查我下面展开。5. 配网失败排查手机扫不到、超时、连上又掉的常见原因5.1 手机已经连上WiFi但ESP32毫无反应这是最高频的故障现象App点了配网ESP32串口只有scan done再也没有后续。根据我的经验排查顺序应该是确认手机连的是2.4G不是5G。前面原理部分已经解释过ESP32的混杂模式根本收不到5G频段的帧。你可以在手机WiFi设置里点开当前连接的WiFi详情看下频段信息。有些安卓手机可以直接看到连接频率2412 MHz这类字样如果是5180 MHz那就是5G肯定配不上。确认路由器没开AP隔离。登录路由器管理页在无线设置里找AP隔离、客户端隔离、访客网络全部关掉。尤其是公司网络、出租屋共用路由器基本都开了隔离。确认手机能给App相应权限。Android 6.0以上WiFi扫描需要定位权限Android 10以上部分手机还要允许附近设备权限。iOS首次打开App会弹允许查找并连接到本地网络上的设备必须点允许。权限没给App拿不到当前WiFi信息或者发不出广播现象和1一模一样。尝试更换配网协议类型。乐鑫App一般默认ESPTOUCH你可以在设备端代码里把esp_smartconfig_set_type改成SC_TYPE_AIRKISS试试有些路由器、有些手机上AirKiss反而更稳虽然理论上ESPTOUCH更主流但实测中AirKiss对部分老旧路由器的兼容性更好。如果以上都排查完了还是不行最后用杀手锏换一台手机试。我遇到过一台旧安卓手机系统版本太老WiFi扫描回调不触发换了台新手机一次就配上了。设备端的日志一直在那里没有报错问题往往在手机端。5.2 配网成功却拿不到IP或者一断开就再也连不上了配网成功标志是ESP32收到了SSID和密码并开始连接但卡在disconnect from AP, retry...循环。这时问题很可能出在路由器跟ESP32的兼容性上。最常见的原因是路由器开启了WPA3加密。SmartConfig能把密码解析出来但ESP32某些驱动版本或者某些路由器型号在WPA3/WPA2混合模式下二次握手不稳定导致不断重连。解决方法是把路由器无线加密方式临时改为WPA2-PSK实测绝大多数问题都能解决。另一种情况是ESP32能连上路由器但拿不到IP日志停在disconnect from AP或者直接没有got ip。优先检查路由器的DHCP功能是否开启、地址池是否满了、是否开启了MAC地址过滤。可以用手机也连同一个WiFi试试能不能正常上网如果手机也上不了网问题就不是ESP32的而是网络环境的。**如果你修改了代码重新烧录后发现设备居然自己连上了之前配过的WiFi别惊讶。**这说明esp_wifi_set_config(WIFI_IF_STA, wifi_config)默认会把WiFi配置写入NVS闪存设备重启后会从NVS里自动读取。这本身是个好特性但调试时也会带来困扰我明明要重新配网它怎么自己连上旧网了这个问题我现在就讲。5.3 清除配网信息的正确姿势与SDK版本差异想主动清除已保存的WiFi信息开发者圈子里最粗暴的做法是nvs_flash_erase()把整个NVS分区全部擦掉。但我不建议在量产代码里这么干因为它会把设备其他需要持久化的数据比如设备ID、用户设置、校准数据全部一起抹掉属于杀敌一千自损八百。更精准的做法是只清WiFi相关的NVS配置。ESP-IDF的WiFi驱动在初始化时会创建自己的NVS命名空间清掉它可以用下面的方式// 方式一让WiFi驱动忘掉所有已保存的配置 ESP_ERROR_CHECK(esp_wifi_restore());esp_wifi_restore()的作用是把WiFi驱动的NVS配置恢复为出厂状态已保存的SSID、密码会被清除但不会影响其他业务数据。这是我在产品代码里最推荐的方式。需要注意的是调用时机必须是在esp_wifi_init()之后、esp_wifi_start()之前否则API可能返回错误。还有一个经常被忽略的细节如果你在代码里调用过esp_wifi_set_storage(WIFI_STORAGE_RAM)WiFi配置只保存在RAM里掉电自动丢失天然就是不保存配网信息的效果。但从用户角度来说配网一次之后一般希望设备记住网络下次启动直接连所以我通常会用WIFI_STORAGE_FLASH默认也是这个然后配合一个长按按键3秒进入配网模式的交互来让设备忘记旧配置、重新配网。ESP-IDF不同版本对这块也有一些细微差别。比如在较新的ESP-IDF 6.0中WiFi配置相关的结构体和部分API命名做了整理但esp_wifi_restore()这个函数的语义没有变。建议你始终用当前SDK版本配套的API文档来核对不要直接拿老博客的代码硬套新版本编译报错倒是小事运行行为不符合预期才是大坑。5.4 双向频段与多设备同时配网的坑还有一个很多人没意识到的坑手机连着2.4G但路由器同时开了多个相同SSID的2.4G APMesh组网。在这种情况下手机可能连着客厅的APESP32放在卧室两个AP在同一个信道或不同信道广播帧可能被卧室AP的广播抑制机制挡住导致ESP32收不到。解决办法是把ESP32靠近路由器或者临时把设备放在路由器旁边配好网再挪走。多设备同时配网是另一个看似可以、实际翻车的场景。理论上手机App可以给多台ESP32同时配网因为广播是群发的但实际中多台ESP32同时收到同一个SSID和密码后会同时发起WiFi连接如果路由器性能一般容易出现部分设备一直抢不到IP、反复重连。我在批量调试10块板子时就遇到过最后只能一块一块配虽然慢但稳。6. 把配网做成可靠功能状态提示、超时重配与产品化细节6.1 用板载LED反馈配网状态如果你只是自己开发调试串口日志就够了。但如果你做的是一个用户拿到手不用接电脑的产品配网过程必须有可感知的状态反馈。最简单的方案是板载LED用不同的闪烁频率表达慢闪1秒一次等待配网中。快闪200ms一次已收到SSID正在连接。长亮或熄灭配网成功设备正常工作。实现也不复杂。在SC_EVENT_GOT_SSID_PSWD分支里点亮LED并切换为快闪在WIFI_CONNECTED_BIT被置位后切换为长亮。LED闪烁可以用一个单独的FreeRTOS任务控制设置两个全局变量来改变闪烁周期。注意在esp_smartconfig_stop()之后LED任务不要被关掉后续还要用它指示设备运行状态。6.2 超时机制与手动重新进入配网配网不可能永远等下去。如果用户迟迟没点App或者配网失败设备不能一直停留在监听状态否则正常工作流程会被堵死。我在真实产品里通常加两个机制配网超时启动SmartConfig时记录时间戳比如5分钟内没有收到SC_EVENT_GOT_SSID_PSWD就调用esp_smartconfig_stop()然后让设备进入普通STA模式——虽然没配上但还能做其他事或者重启后再次进入配网。按键触发重新配网长按设备上的按键3秒先调用esp_wifi_restore()清除已保存的WiFi配置然后调用esp_wifi_disconnect()再执行一次esp_wifi_connect()或者重启设备让固件检测到无有效WiFi配置自然进入配网模式。伪代码大致是这样void button_long_press_task(void *arg) { for (;;) { if (gpio_get_level(BUTTON_GPIO) 0) { vTaskDelay(pdMS_TO_TICKS(3000)); if (gpio_get_level(BUTTON_GPIO) 0) { ESP_LOGI(TAG, clear wifi config and re-enter smartconfig...); esp_wifi_restore(); esp_wifi_disconnect(); esp_restart(); // 最简单稳妥的方式 } } vTaskDelay(pdMS_TO_TICKS(50)); } }这里我说一下为什么最后选择esp_restart()而不是直接调用esp_smartconfig_start()。因为esp_wifi_restore()之后WiFi驱动的内部状态会发生变化直接重新启动配网流程偶尔会遇到状态不同步的问题。重启是整个系统最干净的重置方式而且速度快用户感知不到。这是我在项目里反复实验后确定的方案。6.3 生产环境里的几个细节日志脱敏、扫码引导、保留配网入口把配网做成产品除了代码逻辑还有一些看不见但非常重要的细节。日志脱敏是我踩过的一个不大不小的坑。早期我把密码长度和SSID一起打印出来觉得自己调试方便就行了结果有一次给客户远程看日志客户一眼就看到自己WiFi密码的明文被打印在屏幕上当时气氛一度很尴尬。从那以后我的所有配网日志只打SSID、不打印密码明文最多打印密码长度。这在做产品时尤其重要因为你永远不知道设备日志会被谁看到日志脱敏是基本素养。扫码引导。SmartConfig本身对用户是透明的但怎么让用户知道应该下载哪个App、怎么操作就成了新的问题。我见过很多产品在包装上印一个简单的配网二维码用户扫码后直接跳转到App下载页App里提供图文配网教程。这个体验比让用户去应用商店自己搜ESP32配网要顺滑得多。保留配网入口是最后一条建议也是血泪教训。有些产品为了让用户开箱即用把配网入口藏得很深比如只有在出厂状态才能配网一旦用户配过一次网想换网络就必须按住某个隐藏的小孔多少秒——这个设计本身没错。但如果用户长时间未操作、或者路由器换了、或者WiFi密码改了设备会陷入连不上又进不了配网模式的死循环。所以我的原则是只要设备连不上WiFi就自动周期性进入配网模式永远给用户留一个配网入口。这样设备不会变砖也不会被用户投诉说买回来一年换个WiFi就变成摆设了。回到开发本身SmartConfig这套东西你只要照着本文第3章的代码跑一遍大概率能顺利出结果。如果中途卡住回过头重点检查第2章的2.4G频段、第5章的AP隔离和手机权限这三件事十次配网失败里九次都是它们。把这些琢磨透了你不仅会调SmartConfig以后遇到任何设备收不到广播的问题排查思路也会比之前清晰很多。
返回列表