3. Wi-Fi 连接与网络基础:ESP32 Station 与 AP 模式、Wi-Fi 事件处理、自动重连机制、网络状态监控
Wi-Fi 连接是 ESP32 物联网项目的基础。说白了,没有稳定的网络连接,后面那些 WebSocket 通信、前端交互都是空谈。这一章我们就把 ESP32 的 Wi-Fi 底层机制彻底讲透。
我个人习惯把 Wi-Fi 模块比作一个「网络开关」——你不仅要学会怎么打开它,还要知道它什么时候断开、为什么断开、以及如何优雅地重新连上。嗯,这里面的门道不少。
3.1 Station 模式与 AP 模式:两种角色,两种场景
ESP32 的 Wi-Fi 可以工作在两种模式下,你可以把它想象成手机:
- Station 模式(客户端):像你的手机连接家里路由器一样,ESP32 作为客户端去连接一个已有的 Wi-Fi 热点。这是最常见的物联网设备工作模式。
- AP 模式(热点):ESP32 自己变成一个 Wi-Fi 热点,其他设备(如手机)可以连接它。常用于设备配网或临时控制。
- AP+Station 共存模式:同时作为客户端和热点。我在项目中经常用这个模式——设备连上互联网的同时,还能让手机直连设备进行本地调试。
| 模式 | 角色 | 典型场景 | 注意事项 |
|---|---|---|---|
| Station | 客户端 | 传感器数据上报、远程控制 | 需要已知的 Wi-Fi SSID/密码 |
| AP | 热点 | 设备配网、本地 Web 配置页面 | 最多连接 4 个客户端,信道固定 |
| AP+Station | 双角色 | 设备既联网又提供本地接口 | 内存占用增加,需注意 IP 路由 |
配置代码其实很简单,但要注意顺序。我曾经踩过一个坑:先初始化了 AP 模式,再初始化 Station 模式,结果两个模式的 IP 地址冲突了。后来我养成了一个习惯——先配置模式,再启动 Wi-Fi。
#include <WiFi.h>
void setup() {
Serial.begin(115200);
// 设置为 Station 模式
WiFi.mode(WIFI_STA);
// 开始连接
WiFi.begin("你的SSID", "你的密码");
Serial.print("正在连接");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n连接成功!");
Serial.print("IP 地址: ");
Serial.println(WiFi.localIP());
}
WiFi.persistent(true)。这样断电重启后它会自动尝试重连上次的网络,省去每次配网的麻烦。
3.2 Wi-Fi 事件处理:别再用轮询了
很多初学者喜欢在 loop() 里不断检查 WiFi.status()。说实话,这太浪费 CPU 了。ESP32 提供了事件驱动机制——当 Wi-Fi 状态发生变化时,系统会自动触发回调函数。
为什么推荐事件驱动?你想想看,如果设备正在处理传感器数据,突然 Wi-Fi 断开了,你难道要等到下一轮 loop() 循环才发现吗?事件回调可以让你立即响应网络变化。
void onWiFiEvent(WiFiEvent_t event) {
switch (event) {
case SYSTEM_EVENT_STA_CONNECTED:
Serial.println("已连接到路由器");
break;
case SYSTEM_EVENT_STA_GOT_IP:
Serial.print("获取到 IP: ");
Serial.println(WiFi.localIP());
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("Wi-Fi 断开连接");
// 在这里触发自动重连
WiFi.reconnect();
break;
default:
break;
}
}
void setup() {
WiFi.onEvent(onWiFiEvent);
WiFi.begin("SSID", "密码");
}
delay() 或复杂的计算。它运行在 Wi-Fi 任务上下文中,阻塞太久会影响网络稳定性。我一般只在回调里设置标志位,真正的重连逻辑放在 loop() 里处理。
3.3 自动重连机制:别让设备变成「孤儿」
设备部署到现场后,Wi-Fi 断开是家常便饭。路由器重启、信号干扰、电源波动……任何一个原因都可能导致连接中断。如果没有自动重连,设备就成了一块「废铁」。
ESP32 的 WiFi.reconnect() 函数可以发起重连,但直接调用它是不够的。我曾经遇到过一个问题:设备断线后疯狂重连,每秒尝试几十次,结果把路由器搞崩溃了。后来我加了一个退避策略——重连间隔逐渐增大,避免雪崩效应。
unsigned long lastReconnectAttempt = 0;
int reconnectDelay = 1000; // 初始 1 秒
void checkWiFi() {
if (WiFi.status() != WL_CONNECTED) {
unsigned long now = millis();
if (now - lastReconnectAttempt >= reconnectDelay) {
lastReconnectAttempt = now;
Serial.println("尝试重连...");
WiFi.reconnect();
// 退避策略:每次增加 2 秒,最大 60 秒
reconnectDelay = min(reconnectDelay + 2000, 60000);
}
} else {
// 连接成功后重置延迟
reconnectDelay = 1000;
}
}
- 指数退避:重连间隔从 1 秒开始,每次翻倍,最大 60 秒
- 有限重试:尝试 10 次后仍未成功,进入深度休眠或重启
- 状态保存:重连前保存当前工作状态,避免数据丢失
3.4 网络状态监控:看得见的连接质量
光知道「连上了」还不够。在实际项目中,我们需要知道连接的质量——信号强度、丢包率、IP 地址变化等。这些信息能帮助我们诊断网络问题。
我个人习惯在设备上实现一个网络健康检查功能:定时 ping 网关或云服务器,如果连续 3 次超时,就认为网络不可用,主动触发重连。
| 监控指标 | 获取方式 | 说明 |
|---|---|---|
| RSSI(信号强度) | WiFi.RSSI() |
单位 dBm,-30 为极好,-80 以下基本不可用 |
| IP 地址 | WiFi.localIP() |
DHCP 分配的 IP,变化时需通知上层应用 |
| MAC 地址 | WiFi.macAddress() |
设备唯一标识,常用于服务器端设备识别 |
| 连接状态 | WiFi.status() |
返回 WL_CONNECTED 等枚举值 |
void printNetworkStatus() {
Serial.println("===== 网络状态 =====");
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
Serial.print("信号强度 (RSSI): ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
Serial.print("IP 地址: ");
Serial.println(WiFi.localIP());
Serial.print("MAC 地址: ");
Serial.println(WiFi.macAddress());
Serial.print("网关: ");
Serial.println(WiFi.gatewayIP());
Serial.print("子网掩码: ");
Serial.println(WiFi.subnetMask());
Serial.println("====================");
}
3.5 知识体系总览
下面这张图总结了本章的核心知识点和它们之间的关系。你可以把它当作一个快速参考地图。
WiFi.reconnect() 和 WiFi.onEvent() 中的重连逻辑,结果两个重连任务互相竞争,导致设备反复断开重连。记住:重连逻辑只在一个地方实现,要么在事件回调里,要么在 loop() 里,不要混用。
好了,这一章的内容就到这里。Wi-Fi 连接看似基础,但它是整个物联网系统的命脉。把模式配置、事件处理、自动重连和状态监控这四个环节做扎实了,你的设备才能在各种网络环境下稳定运行。