feat: 初始化 BotanicalBuddy 项目并集成 Wi-Fi 配网组件
- 新增 wifi-connect 组件(AP 配网、DNS 劫持、Captive Portal) - 支持长按按键进入配网,网页配置路由器 SSID/密码 - 增加清除已保存 Wi-Fi 参数能力(API + 页面按钮) - 增加中文状态日志与中文注释,优化配网交互 - 补充组件文档:README、USER_GUIDE、QUICK_POSTER、BLOG
This commit is contained in:
13
.devcontainer/Dockerfile
Normal file
13
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
ARG DOCKER_TAG=latest
|
||||||
|
FROM espressif/idf:${DOCKER_TAG}
|
||||||
|
|
||||||
|
ENV LC_ALL=C.UTF-8
|
||||||
|
ENV LANG=C.UTF-8
|
||||||
|
|
||||||
|
RUN apt-get update -y && apt-get install udev -y
|
||||||
|
|
||||||
|
RUN echo "source /opt/esp/idf/export.sh > /dev/null 2>&1" >> ~/.bashrc
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/opt/esp/entrypoint.sh" ]
|
||||||
|
|
||||||
|
CMD ["/bin/bash", "-c"]
|
||||||
19
.devcontainer/devcontainer.json
Normal file
19
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "ESP-IDF QEMU",
|
||||||
|
"build": {
|
||||||
|
"dockerfile": "Dockerfile"
|
||||||
|
},
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"settings": {
|
||||||
|
"terminal.integrated.defaultProfile.linux": "bash",
|
||||||
|
"idf.gitPath": "/usr/bin/git"
|
||||||
|
},
|
||||||
|
"extensions": [
|
||||||
|
"espressif.esp-idf-extension",
|
||||||
|
"espressif.esp-idf-web"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"runArgs": ["--privileged"]
|
||||||
|
}
|
||||||
78
.gitignore
vendored
Normal file
78
.gitignore
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Directory metadata
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Build artifacts and directories
|
||||||
|
**/build/
|
||||||
|
build/
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.out
|
||||||
|
*.exe # For any host-side utilities compiled on Windows
|
||||||
|
|
||||||
|
# ESP-IDF specific build outputs
|
||||||
|
*.bin
|
||||||
|
*.elf
|
||||||
|
*.map
|
||||||
|
flasher_args.json # Generated in build directory
|
||||||
|
sdkconfig.old
|
||||||
|
sdkconfig
|
||||||
|
|
||||||
|
# ESP-IDF dependencies
|
||||||
|
# For older versions or manual component management
|
||||||
|
/components/.idf/
|
||||||
|
**/components/.idf/
|
||||||
|
# For modern ESP-IDF component manager
|
||||||
|
managed_components/
|
||||||
|
# If ESP-IDF tools are installed/referenced locally to the project
|
||||||
|
.espressif/
|
||||||
|
|
||||||
|
# CMake generated files
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles/
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
CTestTestfile.cmake
|
||||||
|
|
||||||
|
# Python environment files
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
__pycache__/
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Virtual environment folders
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
|
env/
|
||||||
|
|
||||||
|
# Language Servers
|
||||||
|
.clangd/
|
||||||
|
.ccls-cache/
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
|
# Windows specific
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# User-specific configuration files
|
||||||
|
*.user
|
||||||
|
*.workspace # General workspace files, can be from various tools
|
||||||
|
*.suo # Visual Studio Solution User Options
|
||||||
|
*.sln.docstates # Visual Studio
|
||||||
10
.vscode/launch.json
vendored
Normal file
10
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "gdbtarget",
|
||||||
|
"request": "attach",
|
||||||
|
"name": "Eclipse CDT GDB Adapter"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
21
.vscode/settings.json
vendored
Normal file
21
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.intelliSenseEngine": "default",
|
||||||
|
"idf.openOcdConfigs": [
|
||||||
|
"board/esp32c3-builtin.cfg"
|
||||||
|
],
|
||||||
|
"idf.port": "/dev/ttyACM0",
|
||||||
|
"idf.currentSetup": "/home/beihong/esp/v5.5.2/esp-idf",
|
||||||
|
"idf.customExtraVars": {
|
||||||
|
"IDF_TARGET": "esp32c3"
|
||||||
|
},
|
||||||
|
"idf.buildPath": "/home/beihong/esp_projects/BotanicalBuddy/build",
|
||||||
|
"C_Cpp.default.compileCommands": "/home/beihong/esp_projects/BotanicalBuddy/build/compile_commands.json",
|
||||||
|
"clangd.path": "/home/beihong/.espressif/tools/esp-clang/esp-19.1.2_20250312/esp-clang/bin/clangd",
|
||||||
|
"clangd.arguments": [
|
||||||
|
"--background-index",
|
||||||
|
"--query-driver=**",
|
||||||
|
"--compile-commands-dir=/home/beihong/esp_projects/BotanicalBuddy/build"
|
||||||
|
],
|
||||||
|
"idf.flashType": "UART",
|
||||||
|
"C_Cpp.default.compilerPath": "/home/beihong/.espressif/tools/riscv32-esp-elf/esp-14.2.0_20251107/riscv32-esp-elf/bin/riscv32-esp-elf-g++"
|
||||||
|
}
|
||||||
6
CMakeLists.txt
Executable file
6
CMakeLists.txt
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
# The following five lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(BotanicalBuddy)
|
||||||
220
components/wifi-connect/BLOG.md
Normal file
220
components/wifi-connect/BLOG.md
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
# 从 0 到 1:我在 ESP32-C3 上做了一个可落地的 Wi-Fi 配网组件(含中文日志与一键清除配置)
|
||||||
|
|
||||||
|
> 项目:BotanicalBuddy
|
||||||
|
> 平台:ESP-IDF v5.5.2(ESP32-C3)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 一、为什么要自己做一个配网组件?
|
||||||
|
|
||||||
|
很多物联网项目都会遇到同一个问题:
|
||||||
|
|
||||||
|
- 设备第一次上电,怎么让用户把它连进家里 Wi-Fi?
|
||||||
|
- 配网失败时,怎么给用户清晰反馈?
|
||||||
|
- 现场调试时,日志如何快速看懂?
|
||||||
|
|
||||||
|
我这次的目标很明确:
|
||||||
|
|
||||||
|
1. **用户侧简单**:长按按键 → 连接热点 → 打开网页 → 输入密码;
|
||||||
|
2. **开发侧可维护**:接口清晰、状态可追踪、日志可读;
|
||||||
|
3. **现场可排障**:失败能看到原因,支持“一键清除历史配置”。
|
||||||
|
|
||||||
|
最终我把这些能力收敛成一个组件:`wifi-connect`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、组件能力概览
|
||||||
|
|
||||||
|
`wifi-connect` 目前实现了这些核心能力:
|
||||||
|
|
||||||
|
- 长按按键进入配网模式;
|
||||||
|
- 设备开启 SoftAP(`ESP32-xxxxxx`);
|
||||||
|
- 内置 HTTP 配网页面(扫描、提交、状态轮询);
|
||||||
|
- DNS 劫持 + Captive Portal 路径兼容(提升手机弹窗成功率);
|
||||||
|
- 配网成功后保存凭据到 NVS;
|
||||||
|
- 上电自动重连已保存网络;
|
||||||
|
- 中文状态日志(便于现场阅读);
|
||||||
|
- **清除已保存配置**(网页按钮 + API + SDK 接口)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 三、整体架构(简化)
|
||||||
|
|
||||||
|
```text
|
||||||
|
[按键任务] --长按--> [进入配网]
|
||||||
|
|
|
||||||
|
+--> APSTA 模式
|
||||||
|
+--> HTTP Server(网页)
|
||||||
|
+--> DNS 劫持服务
|
||||||
|
|
||||||
|
[网页] --POST /api/connect--> [设置 STA 参数并连接]
|
||||||
|
[网页] --GET /api/status --> [轮询状态]
|
||||||
|
[网页] --POST /api/clear --> [清除 NVS 凭据]
|
||||||
|
|
||||||
|
[Wi-Fi/IP 事件] --> [更新状态机 + 打印中文日志 + 保存凭据]
|
||||||
|
```
|
||||||
|
|
||||||
|
核心状态枚举:
|
||||||
|
|
||||||
|
- `idle`
|
||||||
|
- `provisioning`
|
||||||
|
- `connecting`
|
||||||
|
- `connected`
|
||||||
|
- `failed`
|
||||||
|
- `timeout`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、最关键的实现点
|
||||||
|
|
||||||
|
### 1)配网页面的“够用即好”设计
|
||||||
|
|
||||||
|
我没有引入前端框架,而是把 HTML/JS 直接内嵌在 C 字符串里,避免增加构建复杂度。页面只保留 3 个动作:
|
||||||
|
|
||||||
|
- 扫描网络
|
||||||
|
- 提交连接
|
||||||
|
- 清除已保存配置
|
||||||
|
|
||||||
|
这种做法的好处是:**部署轻、调试快、资源占用低**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2)手机“连上热点但不弹页面”的处理
|
||||||
|
|
||||||
|
这是配网常见痛点。为了提高兼容性,我做了两件事:
|
||||||
|
|
||||||
|
1. 注册常见探测路径(如 `/generate_204`、`/hotspot-detect.html` 等);
|
||||||
|
2. 对探测/未知 GET 请求统一返回 `302` 到 `http://192.168.4.1/`。
|
||||||
|
|
||||||
|
这样很多手机系统会更容易触发门户页面。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3)连接超时问题的根因与修复
|
||||||
|
|
||||||
|
我遇到过这样一条典型日志:
|
||||||
|
|
||||||
|
- `sta is connected, disconnect before connecting to new ap`
|
||||||
|
|
||||||
|
说明设备当时还连着旧网络,却直接尝试切到新网络,最终走到连接超时。修复方案很直接:
|
||||||
|
|
||||||
|
- 在 `esp_wifi_set_config + esp_wifi_connect` 前,先 `esp_wifi_disconnect()`;
|
||||||
|
- 若断开失败(非 `NOT_CONNECT`),记录告警日志。
|
||||||
|
|
||||||
|
这一步对稳定性提升很明显。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4)新增“清除已保存配置”能力
|
||||||
|
|
||||||
|
为了提升可恢复性,我新增了完整链路:
|
||||||
|
|
||||||
|
- SDK API:`wifi_connect_clear_config()`
|
||||||
|
- HTTP API:`POST /api/clear`
|
||||||
|
- 页面按钮:“清除已保存”
|
||||||
|
|
||||||
|
执行逻辑:
|
||||||
|
|
||||||
|
1. 清除 NVS 的 `ssid`/`pass`;
|
||||||
|
2. 清空运行时 pending 参数;
|
||||||
|
3. 若正在连接中,取消当前连接流程;
|
||||||
|
4. 在配网模式下把状态恢复为 `provisioning`,并清空旧错误文案。
|
||||||
|
|
||||||
|
这让“失败后重试”路径变得非常顺畅。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、中文日志:现场效率提升非常大
|
||||||
|
|
||||||
|
为了让非固件同学也能看懂串口,我统一了状态日志风格:
|
||||||
|
|
||||||
|
- `【状态】配网已启动:配网热点已开启,SSID=...`
|
||||||
|
- `【状态】开始连接路由器:收到配网请求,目标网络:...`
|
||||||
|
- `【状态】联网成功:已连接 ...,获取 IP=...`
|
||||||
|
- `【状态】连接路由器超时:请确认密码和路由器信号`
|
||||||
|
|
||||||
|
这类日志在现场排障时比纯英文驱动日志直观很多。
|
||||||
|
|
||||||
|
> 注:`wifi:`、`esp_netif_lwip:` 前缀日志依然是 ESP-IDF 框架默认输出。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 六、前端交互做了哪些“小而有效”的优化?
|
||||||
|
|
||||||
|
在配网页面里,我加了几项很实用的小优化:
|
||||||
|
|
||||||
|
- 连接/清除时禁用按钮,防止连点并发请求;
|
||||||
|
- 清除成功后自动清空密码框;
|
||||||
|
- 清除后自动刷新状态和扫描结果;
|
||||||
|
- 状态枚举映射成中文显示(`connecting -> 连接中`)。
|
||||||
|
|
||||||
|
这些改动代码不多,但用户体验差异非常明显。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 七、对外 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);
|
||||||
|
```
|
||||||
|
|
||||||
|
建议调用顺序:
|
||||||
|
|
||||||
|
1. 启动时调用 `wifi_connect_init()`;
|
||||||
|
2. 用户长按或业务触发时调用 `wifi_connect_start()`;
|
||||||
|
3. 成功后由组件自动收口,必要时可手动 `wifi_connect_stop()`;
|
||||||
|
4. 需要重置时调用 `wifi_connect_clear_config()`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 八、测试与验证建议
|
||||||
|
|
||||||
|
建议至少覆盖以下场景:
|
||||||
|
|
||||||
|
1. 首次配网成功;
|
||||||
|
2. 密码错误后重试成功;
|
||||||
|
3. 已连接旧网时切换到新网;
|
||||||
|
4. 清除配置后重新配网;
|
||||||
|
5. 空闲超时自动退出;
|
||||||
|
6. 断电重启后自动重连。
|
||||||
|
|
||||||
|
如果这 6 条都稳定通过,组件可用性通常已经比较高。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 九、我这次的经验总结
|
||||||
|
|
||||||
|
如果你也在做 ESP32 配网,我建议优先做好三件事:
|
||||||
|
|
||||||
|
1. **状态机清晰**:每个阶段可见、可回退;
|
||||||
|
2. **日志可读**:现场的人不一定是固件开发;
|
||||||
|
3. **失败可恢复**:必须有“清除历史配置”的入口。
|
||||||
|
|
||||||
|
很多时候,不是“功能没做出来”,而是“异常路径没兜住”。把恢复路径做顺,产品体验会提升一大截。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 十、后续可继续优化的方向
|
||||||
|
|
||||||
|
- 增加多语言页面(中/英切换);
|
||||||
|
- 增加 AP 密码与会话保护;
|
||||||
|
- 支持 BLE 辅助配网;
|
||||||
|
- 接入云端激活与设备绑定流程;
|
||||||
|
- 做更细粒度的连接错误码映射(前端可读提示)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 参考(项目内文档)
|
||||||
|
|
||||||
|
- `components/wifi-connect/README.md`
|
||||||
|
- `components/wifi-connect/USER_GUIDE.md`
|
||||||
|
- `components/wifi-connect/QUICK_POSTER.md`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
如果你正在做类似项目,希望这篇实践记录能帮你少踩一些坑。
|
||||||
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
|
||||||
|
)
|
||||||
52
components/wifi-connect/Kconfig.projbuild
Normal file
52
components/wifi-connect/Kconfig.projbuild
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
menu "WiFi Connect"
|
||||||
|
|
||||||
|
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_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
|
||||||
|
|
||||||
|
打印时把二维码贴在本段下方空白区域即可。
|
||||||
148
components/wifi-connect/README.md
Normal file
148
components/wifi-connect/README.md
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
# 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` 菜单
|
||||||
|
|
||||||
|
- `WIFI_CONNECT_BUTTON_GPIO`:进入配网的按键 GPIO
|
||||||
|
- `WIFI_CONNECT_BUTTON_ACTIVE_LEVEL`:按键有效电平
|
||||||
|
- `WIFI_CONNECT_DEBOUNCE_MS`:按键去抖时间
|
||||||
|
- `WIFI_CONNECT_LONG_PRESS_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) 提交后连接失败
|
||||||
|
|
||||||
|
- 检查密码是否正确
|
||||||
|
- 查看日志中的失败原因码(`连接失败,原因=...`)
|
||||||
|
- 检查路由器是否禁用了新设备接入
|
||||||
|
- 若曾保存过旧配置,可先在页面点击“清除已保存”后再重试
|
||||||
|
|
||||||
|
### 3) 成功后热点消失是否正常
|
||||||
|
|
||||||
|
- 正常。组件设计为连接成功后自动关闭配网热点
|
||||||
|
- 可通过 `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)
|
||||||
77
components/wifi-connect/USER_GUIDE.md
Normal file
77
components/wifi-connect/USER_GUIDE.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# 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
|
||||||
1179
components/wifi-connect/wifi-connect.c
Normal file
1179
components/wifi-connect/wifi-connect.c
Normal file
File diff suppressed because it is too large
Load Diff
3
main/CMakeLists.txt
Executable file
3
main/CMakeLists.txt
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
idf_component_register(SRCS "main.c"
|
||||||
|
INCLUDE_DIRS "."
|
||||||
|
REQUIRES wifi-connect)
|
||||||
14
main/main.c
Executable file
14
main/main.c
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_check.h"
|
||||||
|
|
||||||
|
#include "wifi-connect.h"
|
||||||
|
|
||||||
|
|
||||||
|
void app_main(void)
|
||||||
|
{
|
||||||
|
// 初始化 Wi-Fi 配网组件,支持长按按键进入配网
|
||||||
|
ESP_ERROR_CHECK(wifi_connect_init());
|
||||||
|
printf("设备启动完成:长按按键进入配网模式,手机连接 ESP32-* 后访问 http://192.168.4.1\n");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user