ESP32 网页配网程序

发布于 2026-10-01 阅读 13 分类:程序源码

一个零第三方库依赖的 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), 不需要联网下载任何东西。

配网操作步骤

  1. 给 ESP32 上电,等约 15 秒(它会先试着连上次保存的 WiFi)
  2. 手机打开 WiFi 列表,连接 ESP32-Setup-XXXX(开放热点,无需密码)
  3. 一般会自动弹出配网页;没弹就手动打开浏览器访问 http://192.168.4.1
  4. 在列表里点选你的 WiFi,输入密码,点「保存并连接」
  5. 连接成功后页面显示拿到的 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%
资源下载
ESP32一键配网程序.zip
网盘链接
提取码:96d2
访问网盘