Files

365 lines
9.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ESP32 配网组件设计实践:聚焦功能与实现,而不是项目绑定
很多 ESP32 设备在开发阶段都把“配网”当成一个小功能,但真正落地后会发现:
- 用户第一次接入要顺畅
- 失败后要能恢复
- 日志要便于现场排障
这篇文章只讲配网组件本身,聚焦能力设计和实现思路,不依赖具体业务项目。
---
## 一、目标能力定义
一个可落地的配网组件,建议至少包含以下能力:
- 按键触发配网
- 常驻配网模式(可选)
- SoftAP + Web Portal 配网
- DNS 劫持与常见 Captive Portal 兼容
- 凭据持久化NVS与重启自动重连
- 清除历史配置API + Web
- 状态机与可读日志
这几项组合起来,才能覆盖“首次成功 + 失败恢复 + 现场维护”三个关键场景。
图示(整体功能目标关联):
```mermaid
flowchart TD
A[按键任务/业务触发] --> B[进入 provisioning]
B --> C[启动 SoftAP]
B --> D[启动 HTTP Server]
B --> E[启动 DNS Hijack]
D --> F[/api/scan]
D --> G[/api/connect]
D --> H[/api/status]
D --> I[/api/clear]
G --> J[设置 STA 参数]
J --> K[发起 esp_wifi_connect]
K --> L{Wi-Fi/IP 事件}
L -->|成功| M[状态=connected]
L -->|失败| N[状态=failed]
I --> O[清除 NVS 凭据]
O --> P[清空运行态缓存]
P --> B
```
---
## 二、组件架构(通用)
```text
[按键任务] --> [进入配网]
|
+--> SoftAP + HTTP Server + DNS Hijack
[Web] -- /api/scan --> Wi-Fi 扫描
[Web] -- /api/connect --> 设置 STA 并发起连接
[Web] -- /api/status --> 轮询状态
[Web] -- /api/clear --> 清除已保存配置
[Wi-Fi/IP 事件] --> 更新状态机 + 打印日志 + 保存凭据
```
推荐状态机:
- `idle`
- `provisioning`
- `connecting`
- `connected`
- `failed`
- `timeout`
图示(状态机):
```mermaid
stateDiagram-v2
[*] --> idle
idle --> provisioning: wifi_connect_start()
provisioning --> connecting: POST /api/connect
connecting --> connected: GOT_IP
connecting --> failed: AUTH_FAIL / NO_AP / ...
connecting --> timeout: connect timeout
failed --> provisioning: POST /api/clear
timeout --> provisioning: POST /api/clear
connected --> provisioning: 常驻配网继续开放入口(可选)
connected --> idle: stop provisioning(按策略)
```
上图展示了组件的主要数据流与恢复路径。
---
## 三、对外 API 设计建议
推荐保持“少而稳”的接口:
```c
esp_err_t wifi_connect_init(void);
esp_err_t wifi_connect_start(void);
esp_err_t wifi_connect_stop(void);
wifi_connect_status_t wifi_connect_get_status(void);
esp_err_t wifi_connect_get_config(wifi_connect_config_t *config);
esp_err_t wifi_connect_clear_config(void);
```
设计原则:
- `init` 只做初始化和基础恢复
- `start/stop` 控制配网生命周期
- `get_status` 作为 UI/接口层统一读取入口
- `clear_config` 提供失败恢复通道
可以展示一段“典型调用顺序”代码:
```c
ESP_ERROR_CHECK(wifi_connect_init());
// 按键触发或业务触发时
ESP_ERROR_CHECK(wifi_connect_start());
// UI 侧轮询状态
wifi_connect_status_t st = wifi_connect_get_status();
// 需要恢复出厂配网时
ESP_ERROR_CHECK(wifi_connect_clear_config());
```
图示API 生命周期时序):
```mermaid
sequenceDiagram
participant App as 应用层
participant WC as wifi-connect
participant WiFi as esp_wifi
participant Web as 配网页面
App->>WC: wifi_connect_init()
WC-->>App: ESP_OK
App->>WC: wifi_connect_start()
WC->>WiFi: 开启 APSTA / 事件注册
WC-->>App: ESP_OK
Web->>WC: POST /api/connect(ssid,pass)
WC->>WiFi: esp_wifi_disconnect()
WC->>WiFi: esp_wifi_set_config()
WC->>WiFi: esp_wifi_connect()
WiFi-->>WC: WIFI_EVENT / IP_EVENT
alt 获取到 IP
WC-->>Web: status=connected
else 连接失败或超时
WC-->>Web: status=failed|timeout
end
Web->>WC: POST /api/clear
WC-->>Web: status=provisioning
```
上图对应完整 API 生命周期init -> start -> connecting -> connected/failed -> clear
---
## 四、关键实现点
### 1) Web 配网页面保持轻量
不一定要引入前端框架。对于资源受限设备,内嵌简洁 HTML/JS 往往更稳定。
建议页面只保留核心动作:
- 扫描网络
- 提交连接
- 查看状态
- 清除配置
### 2) Captive Portal 兼容是体验关键
仅提供首页 URL 通常不够。建议额外处理:
- 常见探测路径(如 `generate_204` 等)
- 未知路径统一 302 到配网页
这样手机系统弹门户页面成功率会明显提高。
示例代码(伪代码):
```c
static esp_err_t captive_redirect_handler(httpd_req_t *req)
{
httpd_resp_set_status(req, "302 Found");
httpd_resp_set_hdr(req, "Location", "http://192.168.4.1/");
return httpd_resp_send(req, NULL, 0);
}
// 注册常见探测路径
httpd_register_uri_handler(server, &uri_generate_204);
httpd_register_uri_handler(server, &uri_hotspot_detect);
httpd_register_uri_handler(server, &uri_ncsi);
```
可直接使用以下流程图(对应 Captive Portal 重定向路径):
```mermaid
flowchart LR
A[手机连接设备 AP] --> B[访问任意域名]
B --> C[DNS Hijack 返回 192.168.4.1]
C --> D[HTTP 探测路径请求<br/>/generate_204 等]
D --> E[302 Location: http://192.168.4.1/]
E --> F[打开配网页面]
F --> G[扫描 / 连接 / 清除配置]
```
### 3) 连接前主动断开旧连接
这是一个高频坑:设备已有 STA 连接时,直接连接新 AP 可能导致超时或异常状态。
建议在 `esp_wifi_set_config + esp_wifi_connect` 前先执行 `esp_wifi_disconnect()`,并对异常返回做日志记录。
示例代码:
```c
esp_err_t err = esp_wifi_disconnect();
if (err != ESP_OK && err != ESP_ERR_WIFI_NOT_CONNECT) {
ESP_LOGW(TAG, "disconnect before reconnect failed: %s", esp_err_to_name(err));
}
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &cfg));
ESP_ERROR_CHECK(esp_wifi_connect());
```
### 4) “清除配置”必须打通全链路
建议同时提供:
- SDK API`wifi_connect_clear_config()`
- HTTP API`POST /api/clear`
- 页面按钮:`清除已保存`
这样现场人员无需改固件即可恢复设备。
建议把清除动作写成“存储层 + 运行态”两段:
```c
esp_err_t wifi_connect_clear_config(void)
{
// 1) 清 NVS 凭据
ESP_RETURN_ON_ERROR(nvs_erase_key(nvs, "ssid"), TAG, "erase ssid failed");
ESP_RETURN_ON_ERROR(nvs_erase_key(nvs, "pass"), TAG, "erase pass failed");
ESP_RETURN_ON_ERROR(nvs_commit(nvs), TAG, "nvs commit failed");
// 2) 清内存态并回到 provisioning
memset(&s_ctx.pending_cfg, 0, sizeof(s_ctx.pending_cfg));
s_ctx.status = WIFI_CONNECT_STATUS_PROVISIONING;
return ESP_OK;
}
```
可直接使用以下流程图(对应 clear 后状态回到 provisioning
```mermaid
flowchart TD
A[开始清除配置] --> B[擦除 NVS:ssid]
B --> C[擦除 NVS:pass]
C --> D[nvs_commit]
D --> E[清空 pending 配置缓存]
E --> F[清空错误原因/中间状态]
F --> G[状态切回 provisioning]
G --> H[前端轮询显示 可重新配网]
```
---
## 五、日志策略(非常重要)
建议日志遵循“状态 + 原因”格式,例如:
- `【状态】配网已启动热点已开启SSID=...`
- `【状态】开始连接路由器:目标网络=...`
- `【状态】联网成功:获取 IP=...`
- `【状态】连接失败:原因=...`
这样做的收益是:
- 开发调试快
- 测试可直接定位阶段
- 现场人员无需先理解底层驱动日志
可展示一个统一日志函数风格:
```c
static void log_state_i(const char *title, const char *detail)
{
ESP_LOGI(TAG, "【状态】%s%s", title, detail ? detail : "-");
}
```
如需补充非 Mermaid 图,建议仅放一张关键串口日志截图(启动配网、连接中、成功/失败重试)。
---
## 六、常见问题与排障思路
### 问题 1手机连上 AP 但页面不弹
排查:
- 手动访问 `http://192.168.4.1`
- 检查 DNS 劫持和门户探测路径是否启用
- 检查 HTTP 服务是否启动成功
### 问题 2提交密码后长时间连接失败
排查:
- 是否先断开旧 STA
- 是否正确处理了连接超时和重试
- 失败原因是否上报到状态机和前端
### 问题 3配网失败后无法恢复
排查:
- NVS 清除逻辑是否真正执行
- 内存态缓存是否同时清空
- 配网状态是否回到 `provisioning`
---
## 七、测试清单(可复用)
建议每次迭代最少覆盖:
1. 首次配网成功
2. 密码错误后重试成功
3. 连接旧网状态下切换新网成功
4. 清除配置后重新配网成功
5. 重启后自动重连
6. 空闲超时与手动停止路径可用
这 6 条通过后,组件稳定性通常会显著提升。
---
## 八、可继续增强的方向
- 配网页面安全增强(鉴权/会话)
- 多语言提示
- 更细粒度错误码映射
- BLE 辅助配网
- 命令行/远程维护接口联动
---
## 结语
配网组件的核心价值,不是“让设备连上一次网”,而是:
- 功能完整
- 异常可恢复
- 排障可落地
当这三件事做好后,它才是一个能复用、能维护、能上线的基础能力组件。