first commit
This commit is contained in:
365
components/wifi-connect/BLOG.md
Normal file
365
components/wifi-connect/BLOG.md
Normal file
@@ -0,0 +1,365 @@
|
||||
# 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 辅助配网
|
||||
- 命令行/远程维护接口联动
|
||||
|
||||
---
|
||||
|
||||
## 结语
|
||||
|
||||
配网组件的核心价值,不是“让设备连上一次网”,而是:
|
||||
|
||||
- 功能完整
|
||||
- 异常可恢复
|
||||
- 排障可落地
|
||||
|
||||
当这三件事做好后,它才是一个能复用、能维护、能上线的基础能力组件。
|
||||
5
components/wifi-connect/CMakeLists.txt
Normal file
5
components/wifi-connect/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
idf_component_register(
|
||||
SRCS "wifi-connect.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES esp_wifi esp_timer esp_event esp_netif nvs_flash esp_http_server lwip driver
|
||||
)
|
||||
87
components/wifi-connect/Kconfig.projbuild
Normal file
87
components/wifi-connect/Kconfig.projbuild
Normal file
@@ -0,0 +1,87 @@
|
||||
menu "WiFi Connect"
|
||||
|
||||
choice WIFI_CONNECT_PROVISION_MODE
|
||||
prompt "Provisioning mode"
|
||||
default WIFI_CONNECT_PROVISION_MODE_BUTTON
|
||||
help
|
||||
Select how provisioning mode is entered.
|
||||
|
||||
config WIFI_CONNECT_PROVISION_MODE_BUTTON
|
||||
bool "Button triggered (default)"
|
||||
help
|
||||
Enter provisioning only when button long-press is detected.
|
||||
|
||||
config WIFI_CONNECT_PROVISION_MODE_ALWAYS_ON
|
||||
bool "Always-on provisioning"
|
||||
help
|
||||
Start provisioning automatically on boot and keep it running.
|
||||
Provisioning will not auto-stop after idle timeout or STA connect.
|
||||
|
||||
endchoice
|
||||
|
||||
config WIFI_CONNECT_BUTTON_GPIO
|
||||
int "Provision button GPIO"
|
||||
range 0 21
|
||||
default 9
|
||||
help
|
||||
GPIO used for entering provisioning mode.
|
||||
|
||||
config WIFI_CONNECT_BUTTON_ACTIVE_LEVEL
|
||||
int "Provision button active level"
|
||||
range 0 1
|
||||
default 0
|
||||
help
|
||||
Active level of provisioning button. 0 means active-low.
|
||||
|
||||
config WIFI_CONNECT_DEBOUNCE_MS
|
||||
int "Button debounce time (ms)"
|
||||
range 10 200
|
||||
default 40
|
||||
|
||||
config WIFI_CONNECT_LONG_PRESS_MS
|
||||
int "Button long press trigger time (ms)"
|
||||
range 500 10000
|
||||
default 2000
|
||||
|
||||
config WIFI_CONNECT_BUTTON_STARTUP_GUARD_MS
|
||||
int "Button startup guard time (ms)"
|
||||
range 0 30000
|
||||
default 5000
|
||||
help
|
||||
Ignore button long-press detection during startup guard window.
|
||||
Useful when button pin is shared with other peripherals.
|
||||
|
||||
config WIFI_CONNECT_BUTTON_RELEASE_ARM_MS
|
||||
int "Button release arm time (ms)"
|
||||
range 20 2000
|
||||
default 200
|
||||
help
|
||||
Require button to stay in released level for this duration
|
||||
before long-press detection is armed.
|
||||
|
||||
config WIFI_CONNECT_CONNECT_TIMEOUT_SEC
|
||||
int "Wi-Fi connect timeout (sec)"
|
||||
range 5 180
|
||||
default 30
|
||||
|
||||
config WIFI_CONNECT_IDLE_TIMEOUT_SEC
|
||||
int "Provisioning idle timeout (sec)"
|
||||
range 30 1800
|
||||
default 300
|
||||
|
||||
config WIFI_CONNECT_MAX_SCAN_RESULTS
|
||||
int "Maximum scan results"
|
||||
range 5 50
|
||||
default 20
|
||||
|
||||
config WIFI_CONNECT_AP_MAX_CONNECTIONS
|
||||
int "SoftAP max connections"
|
||||
range 1 10
|
||||
default 4
|
||||
|
||||
config WIFI_CONNECT_AP_GRACEFUL_STOP_SEC
|
||||
int "AP keep-alive after STA connected (sec)"
|
||||
range 0 120
|
||||
default 15
|
||||
|
||||
endmenu
|
||||
28
components/wifi-connect/QUICK_POSTER.md
Normal file
28
components/wifi-connect/QUICK_POSTER.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# BotanicalBuddy 配网四步卡(张贴版)
|
||||
|
||||
## 第 1 步:长按按键
|
||||
长按设备配网键约 2 秒,进入配网模式。
|
||||
|
||||
## 第 2 步:连接热点
|
||||
手机连接 Wi-Fi:ESP32-xxxxxx
|
||||
|
||||
## 第 3 步:打开页面
|
||||
浏览器访问:http://192.168.4.1
|
||||
|
||||
## 第 4 步:提交路由器信息
|
||||
选择家里 Wi-Fi,输入密码,点击“连接”。
|
||||
|
||||
---
|
||||
|
||||
## 失败时先做这三件事
|
||||
1. 确认访问的是 http://192.168.4.1(不是 https)
|
||||
2. 确认输入的 Wi-Fi 密码正确
|
||||
3. 路由器使用 2.4G,设备离路由器更近一点再试
|
||||
|
||||
---
|
||||
|
||||
## 二维码占位(贴纸用)
|
||||
建议制作一个二维码,内容指向:
|
||||
http://192.168.4.1
|
||||
|
||||
打印时把二维码贴在本段下方空白区域即可。
|
||||
165
components/wifi-connect/README.md
Normal file
165
components/wifi-connect/README.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# wifi-connect 组件说明
|
||||
|
||||
`wifi-connect` 是一个基于 ESP-IDF 的 Wi-Fi 配网组件,支持:
|
||||
|
||||
- 长按按键进入配网模式
|
||||
- 启动 SoftAP + Captive Portal(网页配网)
|
||||
- 手机连接热点后,通过网页扫描并选择路由器
|
||||
- 保存 Wi-Fi 凭据到 NVS
|
||||
- 下次开机自动重连
|
||||
- 支持两种配网模式:按键触发 / 常驻配网
|
||||
|
||||
面向最终用户的一页版操作说明见:`USER_GUIDE.md`
|
||||
现场打印张贴版(四步卡)见:`QUICK_POSTER.md`
|
||||
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
- `wifi-connect.c`:组件主实现(按键、APSTA、HTTP、DNS、状态机)
|
||||
- `include/wifi-connect.h`:对外 API
|
||||
- `Kconfig.projbuild`:组件配置项
|
||||
- `CMakeLists.txt`:组件构建依赖
|
||||
|
||||
---
|
||||
|
||||
## 对外 API
|
||||
|
||||
头文件:`include/wifi-connect.h`
|
||||
|
||||
- `esp_err_t wifi_connect_init(void);`
|
||||
- 初始化组件(NVS、Wi-Fi、事件、按键任务等)
|
||||
- 尝试自动连接已保存网络
|
||||
|
||||
- `esp_err_t wifi_connect_start(void);`
|
||||
- 启动配网(APSTA + HTTP + DNS)
|
||||
|
||||
- `esp_err_t wifi_connect_stop(void);`
|
||||
- 停止配网(关闭热点与相关服务)
|
||||
|
||||
- `wifi_connect_status_t wifi_connect_get_status(void);`
|
||||
- 获取当前状态:`idle / provisioning / connecting / connected / failed / timeout`
|
||||
|
||||
- `esp_err_t wifi_connect_get_config(wifi_connect_config_t *config);`
|
||||
- 读取已保存的 Wi-Fi 凭据
|
||||
|
||||
- `esp_err_t wifi_connect_clear_config(void);`
|
||||
- 清除已保存的 Wi-Fi 凭据(SSID/密码)
|
||||
|
||||
---
|
||||
|
||||
## 快速使用
|
||||
|
||||
在 `main/main.c`:
|
||||
|
||||
```c
|
||||
#include "esp_check.h"
|
||||
#include "wifi-connect.h"
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(wifi_connect_init());
|
||||
}
|
||||
```
|
||||
|
||||
运行后:
|
||||
|
||||
1. 选择配网模式:
|
||||
- 按键触发模式:长按配置按键进入配网
|
||||
- 常驻配网模式:上电自动进入配网
|
||||
2. 手机连接 `ESP32-xxxxxx` 热点
|
||||
3. 打开 `http://192.168.4.1`
|
||||
4. 选择 Wi-Fi 并输入密码提交
|
||||
5. 配网行为:
|
||||
- 按键触发模式:连接成功后按配置自动关闭热点
|
||||
- 常驻配网模式:配网热点保持开启,不自动关闭
|
||||
|
||||
如需清空历史凭据,可在配网页面点击“清除已保存”。
|
||||
|
||||
---
|
||||
|
||||
## Kconfig 配置项
|
||||
|
||||
在 `idf.py menuconfig` 中:`WiFi Connect` 菜单
|
||||
|
||||
- `Provisioning mode`:配网模式(二选一)
|
||||
- `Button triggered`:按键触发配网(默认)
|
||||
- `Always-on provisioning`:常驻配网(上电自动进入且不自动关闭)
|
||||
|
||||
- `WIFI_CONNECT_BUTTON_GPIO`:进入配网的按键 GPIO
|
||||
- `WIFI_CONNECT_BUTTON_ACTIVE_LEVEL`:按键有效电平
|
||||
- `WIFI_CONNECT_DEBOUNCE_MS`:按键去抖时间
|
||||
- `WIFI_CONNECT_LONG_PRESS_MS`:长按触发时长
|
||||
- `WIFI_CONNECT_BUTTON_STARTUP_GUARD_MS`:上电保护窗口(该时间内忽略长按检测)
|
||||
- `WIFI_CONNECT_BUTTON_RELEASE_ARM_MS`:松手解锁时间(先稳定松手再允许长按触发)
|
||||
- `WIFI_CONNECT_CONNECT_TIMEOUT_SEC`:连接路由器超时
|
||||
- `WIFI_CONNECT_IDLE_TIMEOUT_SEC`:配网页面空闲超时
|
||||
- `WIFI_CONNECT_MAX_SCAN_RESULTS`:扫描网络最大数量
|
||||
- `WIFI_CONNECT_AP_MAX_CONNECTIONS`:SoftAP 最大连接数
|
||||
- `WIFI_CONNECT_AP_GRACEFUL_STOP_SEC`:联网成功后 AP 延迟关闭秒数
|
||||
|
||||
---
|
||||
|
||||
## 日志与状态说明(中文)
|
||||
|
||||
组件会输出统一中文状态日志,例如:
|
||||
|
||||
- `【状态】wifi-connect 初始化完成`
|
||||
- `【状态】检测到按键长按:开始进入配网模式`
|
||||
- `【状态】配网已启动:配网热点已开启,SSID=...`
|
||||
- `【状态】开始连接路由器:收到配网请求,目标网络=...`
|
||||
- `【状态】联网成功:已连接 ...,获取 IP=...`
|
||||
- `【状态】配网已停止:热点已关闭,设备继续以 STA 模式运行`
|
||||
|
||||
说明:ESP-IDF 驱动层(如 `wifi:`、`esp_netif_lwip:`)仍会输出英文日志,这是框架默认行为。
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1) 手机连上热点但不自动弹出页面
|
||||
|
||||
- 手动访问:`http://192.168.4.1`
|
||||
- 确认手机没有强制使用 HTTPS
|
||||
- 查看串口是否有 `配网已启动`、`DNS 劫持服务已启动` 日志
|
||||
|
||||
### 2) 提交后连接失败
|
||||
|
||||
- 检查密码是否正确
|
||||
- 查看日志中的失败原因码(`连接失败,原因=...`)
|
||||
- 检查路由器是否禁用了新设备接入
|
||||
- 若曾保存过旧配置,可先在页面点击“清除已保存”后再重试
|
||||
|
||||
### 4) 按键未按下却误触发配网
|
||||
|
||||
- 常见原因是按键引脚与 LCD/外设复用,初始化期间电平抖动被误判为长按
|
||||
- 可增大 `WIFI_CONNECT_BUTTON_STARTUP_GUARD_MS`(如 8000~10000)
|
||||
- 可增大 `WIFI_CONNECT_BUTTON_RELEASE_ARM_MS`(如 300~500)
|
||||
- 若硬件允许,优先给配网按键使用独立 GPIO
|
||||
|
||||
### 5) 成功后热点消失是否正常
|
||||
|
||||
- 在按键触发模式下:正常,可通过 `WIFI_CONNECT_AP_GRACEFUL_STOP_SEC` 调整关闭延时
|
||||
- 在常驻配网模式下:热点不会自动关闭
|
||||
|
||||
---
|
||||
|
||||
## 依赖
|
||||
|
||||
由 `CMakeLists.txt` 声明:
|
||||
|
||||
- `esp_wifi`
|
||||
- `esp_timer`
|
||||
- `esp_event`
|
||||
- `esp_netif`
|
||||
- `nvs_flash`
|
||||
- `esp_http_server`
|
||||
- `lwip`
|
||||
- `driver`
|
||||
|
||||
---
|
||||
|
||||
## 版本建议
|
||||
|
||||
- 推荐 ESP-IDF `v5.5.x`
|
||||
- 当前项目验证环境:`esp-idf v5.5.2`(ESP32-C3)
|
||||
82
components/wifi-connect/USER_GUIDE.md
Normal file
82
components/wifi-connect/USER_GUIDE.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# BotanicalBuddy 配网操作手册(用户版)
|
||||
|
||||
> 适用对象:现场测试、家人用户、非开发人员
|
||||
> 目标:让设备快速连上家里 Wi-Fi
|
||||
|
||||
---
|
||||
|
||||
## 1. 开始前准备
|
||||
|
||||
- 手机已打开 Wi-Fi
|
||||
- 记住家里 Wi-Fi 名称和密码
|
||||
- 设备已上电
|
||||
|
||||
---
|
||||
|
||||
## 2. 进入配网模式
|
||||
|
||||
有两种工作模式,请按项目配置使用:
|
||||
|
||||
1. 按键触发模式:长按设备上的配网按键(约 2 秒)
|
||||
2. 常驻配网模式:设备上电后会自动开启配网
|
||||
3. 当看到“配网已启动”后,手机 Wi-Fi 列表会出现:`ESP32-xxxxxx`
|
||||
|
||||
---
|
||||
|
||||
## 3. 手机连接设备热点
|
||||
|
||||
1. 在手机 Wi-Fi 中连接 `ESP32-xxxxxx`
|
||||
2. 若系统自动弹出页面,直接进入下一步
|
||||
3. 若没有自动弹出,手动打开浏览器输入:
|
||||
|
||||
`http://192.168.4.1`
|
||||
|
||||
> 注意:必须是 `http`,不要用 `https`
|
||||
|
||||
---
|
||||
|
||||
## 4. 选择路由器并提交
|
||||
|
||||
1. 点击“扫描网络”
|
||||
2. 选择你家的 Wi-Fi
|
||||
3. 输入 Wi-Fi 密码
|
||||
4. 点击“连接”
|
||||
|
||||
成功后页面会提示连接成功:
|
||||
|
||||
- 按键触发模式:设备热点会在几秒后自动关闭(正常现象)
|
||||
- 常驻配网模式:设备热点保持开启(正常现象)
|
||||
|
||||
---
|
||||
|
||||
## 5. 成功后的现象
|
||||
|
||||
- 设备不再广播 `ESP32-xxxxxx`
|
||||
- 串口会显示“联网成功,获取 IP=... ”
|
||||
- 设备进入正常工作状态
|
||||
|
||||
---
|
||||
|
||||
## 6. 常见问题
|
||||
|
||||
### Q1:手机连上热点但打不开页面
|
||||
|
||||
- 手动访问:`http://192.168.4.1`
|
||||
- 关闭手机“私人 DNS / 智能网络切换 / VPN”后重试
|
||||
- 确认没有强制跳 HTTPS
|
||||
|
||||
### Q2:提示连接失败
|
||||
|
||||
- 检查 Wi-Fi 密码是否正确
|
||||
- 确认路由器 2.4G 可用(ESP32-C3 使用 2.4G)
|
||||
- 路由器信号太弱时,靠近路由器后重试
|
||||
|
||||
### Q3:配网成功后热点消失了
|
||||
|
||||
- 这是正常设计:设备连上路由器后会自动关闭配网热点
|
||||
|
||||
---
|
||||
|
||||
## 7. 一句话速记
|
||||
|
||||
长按按键 → 连 `ESP32-xxxxxx` → 打开 `http://192.168.4.1` → 选 Wi-Fi + 输密码 → 等待成功提示。
|
||||
34
components/wifi-connect/include/wifi-connect.h
Normal file
34
components/wifi-connect/include/wifi-connect.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
WIFI_CONNECT_STATUS_IDLE = 0,
|
||||
WIFI_CONNECT_STATUS_PROVISIONING,
|
||||
WIFI_CONNECT_STATUS_CONNECTING,
|
||||
WIFI_CONNECT_STATUS_CONNECTED,
|
||||
WIFI_CONNECT_STATUS_FAILED,
|
||||
WIFI_CONNECT_STATUS_TIMEOUT,
|
||||
} wifi_connect_status_t;
|
||||
|
||||
typedef struct {
|
||||
bool has_config;
|
||||
char ssid[33];
|
||||
char password[65];
|
||||
} wifi_connect_config_t;
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
1263
components/wifi-connect/wifi-connect.c
Normal file
1263
components/wifi-connect/wifi-connect.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user