外观
3.8 HTTP 网页配网与本地管理
这节要搞懂:设备怎么在不改代码的情况下换 WiFi,以及那个内置网页还能干什么。 需要基础:3.7
一、要解决什么问题
WiFi 密码如果写死在代码里,换个地方就得重新烧录固件 —— 带去公司、拿到朋友家、路由器换了名字,全都要重来。
配网(Provisioning)指的是:让设备在不修改代码的情况下获取 WiFi 账号密码的过程。
本工程的网页地址
设备会开启一个配网热点:
| 项目 | 值 |
|---|---|
| 热点名称 | ESP32-Clock-Setup |
| 热点密码 | 12345678 |
| 配网页面 | http://192.168.4.1/ |
| SD 卡管理页面 | http://192.168.4.1/sd |
手机或电脑连上这个热点后,打开上面的地址就能配网和管理 SD 卡。
设备已经连上路由器时,也可以让手机/电脑连同一个路由器,然后访问它的局域网 IP:
http://192.168.x.x/http://192.168.x.x/sd
局域网 IP 从串口日志里的 got ip: xxx.xxx.xxx.xxx 查看,或者去路由器后台看。
配网有两条路
除了本节讲的网页配网,工程里还可以通过蓝牙配网(3.10 第五节)—— 手机连上蓝牙,往 WiFi 特征值写 {"ssid":"...","password":"..."} 就行。
| 网页配网 | 蓝牙配网 | |
|---|---|---|
| 设备要变成热点吗 | ✅ 要 | ❌ 不用 |
| 手机要做什么 | 连热点 + 开浏览器 | 连蓝牙 + 写特征值 |
| 适合 | 普通用户 | 开发调试更快 |
二、AP 模式和 STA 模式
要理解配网,先分清 WiFi 的两种角色:
STA(Station,station 模式):设备作为客户端去连别人的路由器 —— 平时上网就是这个模式。
AP(Access Point,接入点模式):设备自己变成一个热点,让手机来连它。
| STA 模式 | AP 模式 | |
|---|---|---|
| 谁连谁 | 设备 → 路由器 | 手机 → 设备 |
| 有没有外网 | ✅ 有 | ❌ 没有 |
| 什么时候用 | 正常工作 | 配网的时候 |
配网的核心思路:设备还不知道 WiFi 密码时,先让自己变成热点,手机连上来把密码告诉它。
三、完整流程
开机 → 从 NVS 读取已保存的 WiFi
│
├── 有配置 → 尝试 STA 模式连接路由器
│ │
│ ├── 连接成功 → 同时开启 AP 热点 + HTTP 网页
│ └── 连接失败 → 开启 AP 热点 + HTTP 网页
│
└── 没有配置 → 开启 AP 热点 + HTTP 网页
手机 / 电脑连接 ESP32-Clock-Setup
↓
浏览器打开 http://192.168.4.1/
↓
选择或手动输入 WiFi 名称和密码
↓
设备尝试连接路由器
↓
连接成功 → 保存到 NVS注意:AP 热点是一直开着的
很多教程写的是"只有没配置时才开热点,连上就关掉"。
本工程不是这样 —— 不管有没有连上路由器,AP 热点和网页服务都保持开启。
这样做的好处:
- 随时能改配置,不用先把 WiFi 弄坏
- SD 卡管理页面随时可用,不依赖路由器
- 换网络环境时不用重新触发配网模式
代价:多一点功耗,以及热点一直暴露着(所以设了密码 12345678)。
这叫 AP + STA 共存模式
ESP32 支持 WIFI_MODE_APSTA —— 同时当热点和客户端。
一边连着家里的路由器上网,一边自己还开着热点让手机连,两不耽误。
代价:两个角色共用一套射频,同时用的时候吞吐会下降一些。日常配置这点数据量完全无感。
四、HTTP Server 怎么起
ESP-IDF 自带 esp_http_server,起一个服务器就几行:
c
#include "esp_http_server.h"
static httpd_handle_t s_server = NULL;
// 每个 URL 对应一个 handler
static const httpd_uri_t uri_root = {
.uri = "/",
.method = HTTP_GET,
.handler = root_get_handler, // 返回配网页面的 HTML
};
static const httpd_uri_t uri_scan = {
.uri = "/scan",
.method = HTTP_GET,
.handler = wifi_scan_handler, // 返回扫描到的 WiFi 列表
};
static const httpd_uri_t uri_connect = {
.uri = "/connect", // ⭐ 提交 WiFi 账号密码
.method = HTTP_POST,
.handler = wifi_connect_handler,
};
void http_server_start(void)
{
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.max_uri_handlers = 16; // ⭐ SD 卡还要挂十来个,默认 8 个不够
if (httpd_start(&s_server, &config) == ESP_OK) {
httpd_register_uri_handler(s_server, &uri_root);
httpd_register_uri_handler(s_server, &uri_scan);
httpd_register_uri_handler(s_server, &uri_connect);
// ... 还有 SD 卡相关的一堆,见第六节
}
}五、接收网页提交的 WiFi 配置
网页把账号密码 POST 到 /connect:
c
static esp_err_t wifi_connect_handler(httpd_req_t *req)
{
char content[256];
int len = httpd_req_recv(req, content, sizeof(content) - 1);
if (len <= 0) {
return ESP_FAIL;
}
content[len] = '\0';
char ssid[33] = {0};
char password[65] = {0};
// 从 "ssid=xxx&pass=yyy" 里取出两个字段
httpd_query_key_value(content, "ssid", ssid, sizeof(ssid));
httpd_query_key_value(content, "pass", password, sizeof(password));
app_config_save_wifi(ssid, password); // 存进 NVS(3.4)
httpd_resp_sendstr(req, "saved");
vTaskDelay(pdMS_TO_TICKS(1000));
esp_restart(); // 重启后用新配置连
return ESP_OK;
}一定要判断长度
httpd_req_recv() 返回的可能比缓冲区还大。不判断就 memcpy 会踩内存(和 3.6 解析天气 JSON 是同一个坑)。
六、同一个服务器还兼做 SD 卡管理
工程里 app_wifi.c 起的这个 HTTP Server 不只用来配网 —— 它还提供一整套 SD 卡管理接口:
| 方法 | 路径 | 干什么 |
|---|---|---|
GET | /sd | SD 卡管理页面(文件列表) |
POST | /sd/upload?name=文件名 | 上传文件 |
GET | /sd/file?name=文件名 | 下载文件 |
POST | /sd/delete | 删除文件 |
POST | /sd/show | 在屏幕上显示图片 |
POST | /sd/show-rgb565 | 显示 RGB565 格式的图片 |
POST | /sd/audio-play | 播放音频文件 |
POST | /sd/audio-pcm | 播放 PCM 裸数据 |
POST | /sd/audio-stop | 停止播放 |
POST | /sd/exit | 退出当前显示 / 播放 |
浏览器打开 http://192.168.4.1/sd 就能看到文件列表,上传音频和图片、点一下就在设备屏幕上显示或播放。
具体实现在 3.9 讲。
一个服务器挂多个 handler
不用为每个功能单开一个服务器 —— httpd_register_uri_handler() 注册多个 URL 就行,共用一个端口、一份内存。
注意 config.max_uri_handlers 默认只有 8 个 —— 光 SD 卡就要十个,加上配网的三个,必须调大,否则后面注册的会静默失败。
这个设计很实用
把"文件管理"做成网页,比通过串口命令或者拔卡拷贝方便得多:
- 换铃声:网页上传一个音频,点播放试听
- 换壁纸:上传图片,点一下就显示在屏幕上
- 看日志:直接下载 CSV 到电脑
而且不需要装任何 App,有浏览器就行。
本节要点
- STA = 设备连路由器,AP = 设备自己当热点;配网时用 AP
- ⭐ AP 热点和网页服务一直开着(APSTA 共存),不是连上就关
- 热点
ESP32-Clock-Setup/ 密码12345678,配网页192.168.4.1,SD 卡页192.168.4.1/sd - 已连上路由器时,也能用局域网 IP 访问(串口
got ip里看) - 配网接口:
GET /scan扫列表、POST /connect提交 esp_http_server起服务器,一个服务器可以挂多个 URL handler- 接收数据要判断长度,别踩内存
- 同一个服务器还挂了十个 SD 卡管理接口,
max_uri_handlers要调大 - Captive Portal 目前没实现,需要手动输 IP,是值得加的优化
操作过程
目标:不改一行代码,把设备连到一个新的 WiFi 上。
第 1 步:编译烧录
第 2 步:手机连上设备的热点
打开手机 WiFi 列表,找到:
名称:ESP32-Clock-Setup
密码:12345678手机会提示"无法访问互联网"
这是正常的 —— 这个热点本来就没有外网。选"仍然连接 / 保持连接"。
有的手机会自动切回移动数据,要在 WiFi 设置里关掉"自动切换网络"。
第 3 步:打开配网页面
浏览器输入:
http://192.168.4.1/一定要带 http://
直接输 192.168.4.1 有的浏览器会当成搜索词去百度。手动加上 http://。
第 4 步:填 WiFi 并提交
页面上选择或手动输入你家的 WiFi 名称和密码,点提交。
第 5 步:应该看到什么
串口:
I (45000) wifi: save ssid=MyHome
I (45200) wifi: connecting to AP ...
I (47800) wifi: got ip: 192.168.1.107 ← ⭐ 记下这个 IP屏幕:显示连接成功,然后进入主界面。
第 6 步:用局域网 IP 再访问一次
让电脑连上同一个路由器,浏览器打开上一步那个 IP:
http://192.168.1.107/
http://192.168.1.107/sd这一步验证了什么
说明设备连着路由器的同时,网页服务也还开着(APSTA 共存)—— 不用再切回热点就能改配置、管文件。
动手试试
- 手机连上
ESP32-Clock-Setup(密码12345678),打开http://192.168.4.1/完成一次配网。 - 打开
http://192.168.4.1/sd,看看 SD 卡里有什么文件。 - 设备连上路由器后,从串口日志里找到
got ip,用电脑访问那个 IP,验证局域网也能进。 - 在
wifi_connect_handler里打印收到的原始内容,看看浏览器提交上来的格式长什么样。 - 把
config.max_uri_handlers改成 5,观察后面注册的 handler 会怎样。