ESP32 初次开机自动配置 WiFi
1. 简介
很多物联网设备需要连接家庭 WiFi,但无法预知用户的网络名称和密码。本教程将教你如何编写一个 ESP32 程序,实现:
-
首次开机:自动进入配网模式,创建一个名为
ESP32_Config的热点,用户通过手机/电脑连接后打开网页输入 WiFi 信息。 -
保存信息:将 WiFi 信息保存到 ESP32 的 NVS(非易失性存储)中,断电不丢失。
-
后续开机:自动读取保存的 WiFi 信息并连接,如果连接失败则重新进入配网模式。
通过这种方式,用户只需配置一次,之后设备就能自动联网。
2. 准备材料
-
硬件:ESP32 开发板、USB 数据线。
-
软件:Arduino IDE,浏览器(用于配置页面)。
-
可选:LED (验证连接状态,ESP32 板载 LED 通常已集成)。
3. 代码解析
以下是完整的代码(稍后解释各部分功能):
#include <WiFi.h>
#include <WebServer.h>
#include <DNSServer.h>
#include <Preferences.h>
// 配置参数
const char* AP_SSID = "ESP32_Config"; // 配置模式下的热点名称
const char* AP_PASSWORD = ""; // 热点密码(空表示开放)
const int DNS_PORT = 53; // DNS 服务器端口
const int WEB_PORT = 80; // Web 服务器端口
const unsigned long CONNECT_TIMEOUT = 30000; // WiFi 连接超时时间(毫秒)
const unsigned long AP_TIMEOUT = 300000; // AP 模式超时时间(毫秒,5分钟),超过无配置则重启
// 全局对象
WebServer server(WEB_PORT);
DNSServer dnsServer;
Preferences preferences;
// 标志位:是否处于配网模式
bool configMode = false;
unsigned long apStartTime = 0;
// 用户 LED 引脚(可根据需要修改)
const int ledPin = 2; // 大多数 ESP32 开发板板载 LED 在 GPIO2
// 读取保存的 WiFi 凭据
bool loadWiFiCredentials(String &ssid, String &password) {
preferences.begin("wifi", false); // 命名空间 "wifi",读写模式
ssid = preferences.getString("ssid", "");
password = preferences.getString("password", "");
preferences.end();
return (ssid.length() > 0);
}
// 保存 WiFi 凭据
void saveWiFiCredentials(const String &ssid, const String &password) {
preferences.begin("wifi", false);
preferences.putString("ssid", ssid);
preferences.putString("password", password);
preferences.end();
}
// 尝试连接 WiFi
bool connectToWiFi(const String &ssid, const String &password) {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid.c_str(), password.c_str());
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
unsigned long startAttempt = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startAttempt < CONNECT_TIMEOUT) {
delay(500);
Serial.print(".");
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.println("Connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
return true;
} else {
Serial.println("Connection failed.");
return false;
}
}
// 启动 AP 模式并开启 DNS + Web 服务器
void startConfigMode() {
configMode = true;
apStartTime = millis();
WiFi.mode(WIFI_AP);
WiFi.softAP(AP_SSID, AP_PASSWORD);
IPAddress apIP = WiFi.softAPIP();
Serial.println("AP mode started");
Serial.print("AP IP address: ");
Serial.println(apIP);
// 启动 DNS 服务器,将所有域名请求指向 AP 的 IP
dnsServer.start(DNS_PORT, "*", apIP);
// 配置 Web 服务器路由
server.on("/", handleRoot);
server.on("/configure", HTTP_POST, handleConfigure);
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
}
// 处理根路径:显示配置页面
void handleRoot() {
String html = "<!DOCTYPE html><html>";
html += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
html += "<title>WiFi Config</title></head><body>";
html += "<h2>ESP32 WiFi Configuration</h2>";
html += "<form method=\"POST\" action=\"/configure\">";
html += "SSID:<br><input type=\"text\" name=\"ssid\" placeholder=\"WiFi SSID\"><br>";
html += "Password:<br><input type=\"password\" name=\"password\" placeholder=\"Password\"><br><br>";
html += "<input type=\"submit\" value=\"Save and Restart\">";
html += "</form></body></html>";
server.send(200, "text/html", html);
}
// 处理配置表单提交
void handleConfigure() {
if (server.hasArg("ssid") && server.hasArg("password")) {
String ssid = server.arg("ssid");
String password = server.arg("password");
if (ssid.length() > 0) {
saveWiFiCredentials(ssid, password);
server.send(200, "text/html", "<h2>Configuration saved. Restarting...</h2>");
delay(1000);
ESP.restart();
} else {
server.send(400, "text/html", "<h2>SSID cannot be empty</h2>");
}
} else {
server.send(400, "text/html", "<h2>Missing parameters</h2>");
}
}
// 处理未找到的路径(用于 Android/iPhone 的浏览器探测)
void handleNotFound() {
server.send(204, "text/plain", ""); // 204 No Content 让手机不弹出错误
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("\nESP32 WiFi Config Example");
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
// 尝试加载已保存的 WiFi 信息
String savedSSID, savedPassword;
bool hasCredentials = loadWiFiCredentials(savedSSID, savedPassword);
if (hasCredentials) {
Serial.println("Found saved WiFi credentials.");
if (connectToWiFi(savedSSID, savedPassword)) {
// 连接成功,执行用户主程序(此处为 LED 闪烁示例)
Serial.println("Starting user program...");
// 在主循环中执行用户逻辑(见 loop)
return; // 直接退出 setup,进入 loop
} else {
Serial.println("Saved WiFi connection failed.");
}
} else {
Serial.println("No saved WiFi credentials.");
}
// 没有凭据或连接失败,启动配网模式
startConfigMode();
}
void loop() {
if (configMode) {
// 处理 DNS 和 Web 请求
dnsServer.processNextRequest();
server.handleClient();
// 超时检查:若 AP 模式运行超过指定时间且无配置,则重启尝试重新连接
if (millis() - apStartTime > AP_TIMEOUT) {
Serial.println("AP timeout, restarting...");
ESP.restart();
}
} else {
// 正常模式:用户程序
// 示例:LED 闪烁,表示已连接 WiFi
digitalWrite(ledPin, !digitalRead(ledPin));
delay(1000);
Serial.println("Wifi连接成功,进入用户程序.");
}
}
关键代码解释
头文件与全局变量
-
WiFi.h:提供 WiFi 连接功能。 -
WebServer.h:用于建立 HTTP 服务器,处理配置页面。 -
DNSServer.h:实现 DNS 劫持,使所有域名请求指向 ESP32 的 IP。 -
Preferences.h:用于在 NVS 中保存 WiFi 信息(类似键值对存储)。
参数配置
-
AP_SSID和AP_PASSWORD:配置模式下的热点名称和密码(留空表示开放)。 -
CONNECT_TIMEOUT:连接 WiFi 的超时时间。 -
AP_TIMEOUT:AP 模式最长运行时间,避免一直占用。
Preferences 存储
-
preferences.begin("wifi", false):打开命名空间wifi(可自定义),第二个参数false表示读写。 -
putString/getString:存储和读取字符串。
连接逻辑
-
setup()中先尝试读取保存的 WiFi,如果能读到则尝试连接。 -
连接成功则进入
loop()的用户程序;失败则启动 AP 模式。 -
AP 模式下启动 DNS 和 Web 服务器,用户通过浏览器提交配置后保存并重启。
DNS 劫持
-
dnsServer.start(DNS_PORT, "*", apIP):将所有域名请求解析到 ESP32 的 AP IP(192.168.4.1)。 -
这样用户连接热点后,无论访问什么网址(如
www.baidu.com)都会跳转到 ESP32 的配置页面,提升体验。
超时重启
-
AP 模式下记录开始时间
apStartTime,若超过AP_TIMEOUT仍未收到配置,则自动重启,再次尝试连接已保存的 WiFi(如果有)。
用户程序占位
-
在
loop()的else分支中写你自己的代码,示例中是一个 LED 闪烁,代表 WiFi 已连接。
注意:不同 ESP32 开发板的板载 LED 可能连接在不同 GPIO,常见的是 GPIO2 或 GPIO5。若不确定,可查阅开发板原理图或先测试。
6. 操作步骤
6.1 上传程序
-
用 USB 线连接 ESP32 和电脑。
-
在 Arduino IDE 中选择正确的开发板(如
ESP32 Dev Module)和端口(如COM3)。 -
将上述代码复制到 IDE 中,点击上传按钮(→)。
-
等待编译和上传完成,打开串口监视器(波特率 115200),观察输出。
6.2 首次配置
-
如果 ESP32 没有保存过 WiFi 信息,它会在串口打印
未找到保存的 WiFi 凭据。并启动 AP 模式,创建名为ESP32_Config的开放热点。 -
用手机或电脑连接该热点(无需密码)。
-
连接成功后,通常会自动弹出配置页面(若未弹出,使用浏览器访问
http://192.168.4.1)。 -
在页面中输入你家 WiFi 的 SSID 和密码,点击“保存并重启”。
-
保存成功界面如下:

-
ESP32 保存信息后自动重启,尝试连接你输入的 WiFi。
6.3 正常使用
-
连接成功后,串口会显示获得的 IP 地址,LED 开始每秒闪烁一次。
且串口输出信息如下: 
-
此后每次开机,ESP32 都会自动连接上次保存的 WiFi,无需再次配置。
-
如果 WiFi 连接失败(如密码更改、路由器关闭),程序会在超时后重新进入 AP 模式,等待新配置。
7. 常见问题与解决
Q1: 连接 ESP32 热点后,没有自动弹出配置页面怎么办?
-
确保手机/电脑关闭了移动数据,并且已经连接到
ESP32_Config热点。 -
手动在浏览器输入
http://192.168.4.1访问。
Q2: 配置页面提交后,ESP32 没有重启或连接不上?
-
检查输入的 WiFi 密码是否正确。
-
查看串口监视器输出:如果保存成功,会显示
配置已保存,设备即将重启...,然后重启。如果 WiFi 名称或密码错误,重启后仍会进入 AP 模式,可再次配置。
Q3: 如何修改配置热点的名称或密码?
-
修改代码开头的
AP_SSID和AP_PASSWORD即可。 -
若希望 AP 模式有密码,可设置
AP_PASSWORD为字符串,如"12345678"(注意 WiFi 密码至少 8 位)。
Q4: 如何清除保存的 WiFi 信息?
-
可以通过串口发送命令(需自己扩展)或重新上传一个空白程序来清除 NVS。
-
快速方法:在 Arduino IDE 中,选择 工具 → ESP32 Sketch Data Upload 下方的 Erase Flash,擦除整个 Flash 后再上传程序。
Q5: 我想在用户程序中添加更多功能,比如读取传感器、控制继电器,应该怎么改?
-
在
loop()的else分支中(即configMode == false时)编写你的主逻辑即可。 -
注意:不要使用
delay()过长,以免影响 WiFi 维持连接。建议用millis()定时或改用多任务(FreeRTOS)。
8. 扩展思考
-
多网络支持:可以修改程序,保存多个 WiFi 信息,按优先级尝试连接。
-
Web 页面美化:可添加 CSS 样式,使配置界面更美观。
-
安全考虑:如果 AP 模式需要密码,务必设置复杂密码,防止他人误连。
-
远程配置:若需要远程修改 WiFi,可配合 MQTT 或 BLE 实现。
更多推荐
所有评论(0)