ESP32 网页配网程序

一个零第三方库依赖的 ESP32 配网(Provisioning)固件:开机连不上 WiFi 就自动开热点, 手机连上后自动弹出配网页面,选网络、输密码、保存,设备重启入网。
适配 ESP32-WROOM-32 / DevKitC,串口 COM6(CH340)。
一、快速开始
powershell
# 1. 编译
& "$env:USERPROFILE\.platformio\penv\Scripts\pio.exe" run
# 2. 烧录(COM6)
& "$env:USERPROFILE\.platformio\penv\Scripts\pio.exe" run -t upload
# 3. 看串口日志
& "$env:USERPROFILE\.platformio\penv\Scripts\pio.exe" device monitor
PlatformIO 已装好并离线可用(espressif32 6.12.0 + Arduino-ESP32 2.0.17), 不需要联网下载任何东西。
配网操作步骤
- 给 ESP32 上电,等约 15 秒(它会先试着连上次保存的 WiFi)
- 手机打开 WiFi 列表,连接
ESP32-Setup-XXXX(开放热点,无需密码) - 一般会自动弹出配网页;没弹就手动打开浏览器访问 http://192.168.4.1
- 在列表里点选你的 WiFi,输入密码,点「保存并连接」
- 连接成功后页面显示拿到的 IP,设备 4 秒后自动重启进入正常工作模式
二、功能一览
| 功能 | 说明 |
|---|---|
| 自动重连 | 开机读取 Flash(NVS) 里保存的 WiFi,15 秒内连上就直接工作 |
| 强制门户 | DNS 劫持 + 204/Apple/Windows 探测页全劫持,手机连上自动弹窗 |
| 网络扫描 | 页面列出周围 WiFi,显示信号格数和加密状态,按信号强度排序 |
| 连接校验 | 保存前先真的连一次,密码错/信号差会明确告诉你是哪种失败 |
| 掉线重连 | 工作模式下每 2 秒检查,断线超 20 秒自动重连 |
| 网页重配 | 已联网状态下访问设备 IP 也能重新配网 |
| mDNS | 联网后可用 http://esp32.local 访问 |
| 按键复位 | 长按 BOOT 键(GPIO0) 3 秒清除配置并重新配网 |
| LED 指示 | 见下表 |
| 串口命令 | 见下表,方便调试 |
LED(GPIO2)状态含义
| 表现 | 含义 |
|---|---|
| 快闪 250ms | 配网模式,等待手机配置 |
| 慢闪 400ms | 正在连接路由器 |
| 常亮 | 已联网,正常工作 |
| 急闪 120ms | 配网失败(密码错/找不到网络) |
| 三下快闪 | 按键清除配置成功 |
如果你的板子 LED 不在 GPIO2 或极性相反,改
src/main.cpp顶部的LED_PIN和LED_ACTIVE_HIGH。
串口命令(115200 波特率)
| 命令 | 作用 |
|---|---|
help | 显示帮助 |
status | 当前模式 / SSID / IP / RSSI / 可用内存 |
scan | 扫描附近 WiFi 并打印 |
wifi <ssid> <密码> | 直接指定 WiFi 连接并保存 |
ap | 重启进入配网模式 |
reset | 清除保存的配置并重启 |
reboot | 重启设备 |
ip | 打印当前 IP |
page | 把配网页面 HTML 原样打印出来(调试排版用,不用拿手机试) |
示例:
代码块
wifi MyHome 12345678
热点名的后缀 = 本机 MAC 的最后两个字节。例如 MAC 是
C4:4F:33:08:70:69,热点就是ESP32-Setup-7069。 多块板子同时上电时靠这个后缀区分。
三、工程结构
代码块
esp32/
├── platformio.ini # PlatformIO 配置(已 pin 平台版本,串口锁定 COM6)
├── src/
│ └── main.cpp # 全部逻辑,约 990 行,中文注释
├── tools/ # 验证脚本,不参与固件编译
│ ├── monitor.py # 复位并抓串口日志
│ ├── probe.py # 抓启动日志 + 实测各条串口命令
│ ├── dump_page.py # 通过 page 命令把网页 HTML 取回来存成文件
│ └── browser_test.py # 用 headless Edge 真跑一遍页面交互逻辑
├── portal_preview.html # 从设备取回的真实页面(可双击用浏览器打开)
├── portal.png # 页面渲染截图
├── serial.log # 最近的串口日志
├── build.log / upload.log # 编译与烧录日志
└── README.md
自己重跑验证
powershell
$py = "$env:USERPROFILE\.platformio\penv\Scripts\python.exe"
& $py tools\probe.py # 复位并实测串口命令
& $py tools\dump_page.py # 把设备上的页面 HTML 抓下来
& $py tools\browser_test.py # 在真实浏览器引擎里验证点击/显隐逻辑
四、验证情况
以下都在这台机器上对真实硬件跑通了:
| 项目 | 结果 |
|---|---|
| 编译 | 通过,0 warning,RAM 14.7% / Flash 63.9% |
| 烧录 COM6 | 通过,芯片识别为 ESP32-D0WDQ6 rev1.0 |
| 串口启动日志 | 通过,无 NVS 报错 |
scan / status / ip / 未知命令 | 通过,扫到真实周边 WiFi 且按信号降序 |
| 热点启动 | 通过,ESP32-Setup-7069,地址 192.168.4.1 |
| 页面 HTML 完整性 | 通过,串口取回 7362 字节零丢失,div/form 标签全部配对 |
| 页面交互(点击选网、密码显隐、表单提交) | 通过,headless Edge 实跑 7 项断言全 PASS |
没能测的部分(如实说明):这台机器没有无线网卡(netsh wlan show interfaces 报 no wireless interface),所以「手机连上热点后系统自动弹出配网页」这一步 无法在本机验证,需要你拿手机实测。DNS 劫持和 302 重定向的代码逻辑是标准写法, 但强制门户弹窗行为因手机系统而异。
另外,「用真实路由器 + 真实密码完整走一遍配网成功流程」也没测—— 周边 WiFi 都是有密码的,我不猜密码。这一步需要你自己试。
五、常见问题
Q:手机连上热点但没自动弹配网页? 手动开浏览器访问 http://192.168.4.1。部分安卓机需要关掉「移动数据」或 在 WiFi 设置里点「保持连接」。
Q:提示「找不到该 WiFi」? ESP32 只支持 2.4GHz。如果你的路由器是双频合一,把 2.4G 单独分一个 SSID。 也确认 SSID 没有拼错、不是隐藏网络。
Q:提示「认证失败,密码很可能不正确」? 密码错了。注意大小写,以及特殊字符。
Q:烧录失败 / 找不到 COM6?
- 关掉占用串口的程序(Arduino IDE 串口监视器、其他终端)
- 按住板子 BOOT 键再点上传,出现
Connecting...后松手 - 把
platformio.ini里upload_speed从460800改成115200再试
Q:想改热点名字 / 给热点加密码? 改 src/main.cpp 顶部:
AP_SSID_PREFIX—— 热点名前缀AP_PASSWORD—— 留空是开放热点;填 ≥8 位 就会给热点加密PORTAL_TIMEOUT—— 配网页面挂机多久后重启重试
六、技术要点
- 存储:
Preferences(NVS 分区),命名空间wificfg,断电不丢。 读之前先用isKey()探测,否则键不存在时内核会打印看着像故障的nvs_get_str len fail: ... NOT_FOUND - 强制门户:
DNSServer把*全部解析到192.168.4.1; 同时劫持/generate_204、/hotspot-detect.html、/ncsi.txt等探测地址, 并由onNotFound兜底 302 重定向 - 模式管理:配网时用
WIFI_AP_STA(AP 提供页面,STA 用于验证密码); 扫描在开热点之前用纯 STA 模式做,避免扫描打断已连接的手机 - 路由复用:
registerRoutes(portal)一套页面同时服务配网模式和已联网模式, 所以设备联网后访问它的 IP 也能重新配网 - 热点名唯一性:
ESP.getEfuseMac()返回的 uint64 是把 MAC 逐字节填进低 48 位的,mac & 0xFFFF拿到的是头两字节(乐鑫 OUI,所有板子相同)。 必须取高位并重排字节序,才能得到与 MAC 书写顺序一致的后缀 - 页面里的 SSID 传递:用
data-ssid属性 +getAttribute, 而不是把 JS 字符串字面量塞进onclick—— 后者会因为内层双引号 提前闭合属性,页面照样显示正常但点击完全失效 - 内存:页面用
String::reserve()预分配,避免碎片;RAM 占用约 14.7%
本站部分内容源自互联网,仅供学习交流,如有侵权请联系我们删除。