按键按下时WiFi连接
按键按下时WiFi连接
本节介绍物联网按钮的WiFi连接策略——仅在检测到按键按下时连接WiFi,并尽可能减少延迟和功耗。通过本节学习,你将能够:
- 实现从深度睡眠唤醒后的快速WiFi连接
- 优化WiFi连接参数以提高连接速度
- 优雅地处理连接失败
- 为生产部署配置WiFi凭证
开始本节之前,请确保:
- 已完成 04-05. 深度睡眠省电优化
- 具备WiFi网络基础知识(SSID、密码、IP)
- 已完成第01章ESP32 WiFi基础内容
WiFi连接挑战
Section titled “WiFi连接挑战”在电池供电的物联网按钮中,WiFi连接时间是能耗的主导因素:
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐│ 唤醒 │ │ 扫描 │ │ 连接 │ │ DHCP │ │ MQTT ││ 自 │─►│ WiFi │─►│ 至 │─►│ IP │─►│ 发布 ││ 深度睡眠 │ │ 网络 │ │ 接入点 │ │ 获取 │ │ │└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ 0ms 500ms 1000-2000ms 300-500ms 500ms典型连接时间:从唤醒到MQTT就绪需 2-4秒。 每增加一秒大约消耗 60 mAs(毫安秒) 的能量。
ESP32 WiFi状态
Section titled “ESP32 WiFi状态”WiFi.begin(ssid, password) ───► WL_DISCONNECTED │ ▼ WL_CONNECTING ──► WL_CONNECTED ──► IP已分配 │ ▼ WL_CONNECT_FAILED(重试或睡眠) │ ▼ WL_NO_SSID_AVAIL(未找到接入点)第一步:在Setup中建立基础WiFi连接
Section titled “第一步:在Setup中建立基础WiFi连接”由于按钮从深度睡眠唤醒后每次都会执行 setup(),因此WiFi连接逻辑放在 setup() 中:
#include <WiFi.h>#include <esp_wifi.h>
// WiFi凭证const char* WIFI_SSID = "Factory_WiFi";const char* WIFI_PASSWORD = "secure_password";
// 连接超时const unsigned long WIFI_TIMEOUT = 10000; // 最多10秒
void connectWiFi() { Serial.print("正在连接WiFi:"); Serial.println(WIFI_SSID);
WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
unsigned long startAttempt = millis();
while (WiFi.status() != WL_CONNECTED && millis() - startAttempt < WIFI_TIMEOUT) { delay(100); Serial.print("."); }
if (WiFi.status() == WL_CONNECTED) { Serial.println(); Serial.print("已连接!IP地址:"); Serial.println(WiFi.localIP()); Serial.print("连接耗时:"); Serial.print(millis() - startAttempt); Serial.println(" 毫秒"); } else { Serial.println(); Serial.println("WiFi连接失败"); }}第二步:优化WiFi连接速度
Section titled “第二步:优化WiFi连接速度”以下几种技术可以显著减少连接时间:
void optimizeWiFi() { // 1. 禁用WiFi省电模式(减少连接时间) WiFi.setSleep(false);
// 2. 明确设置为站点模式 WiFi.mode(WIFI_STA);
// 3. 使用存储的BSSID(接入点MAC)跳过扫描 // (需要首次连接获取并保存BSSID) const uint8_t bssid[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; WiFi.begin(WIFI_SSID, WIFI_PASSWORD, 0, bssid, true);
// 4. 已知信道时直接设置 WiFi.begin(WIFI_SSID, WIFI_PASSWORD, 6); // 信道6
// 5. 缩短连接超时 esp_wifi_set_timeout(5000); // 5秒超时代替默认的约15秒}连接时间对比:
| 技术 | 时间 | 节省能耗 |
|---|---|---|
| 默认连接(扫描+连接) | 3-5秒 | — |
| 跳过扫描(使用BSSID) | 1.5-2.5秒 | ~40% |
| 直接设置信道 | 1-2秒 | ~50% |
| 综合所有优化 | 0.8-1.5秒 | ~65% |
第三步:使用存储凭证快速重连
Section titled “第三步:使用存储凭证快速重连”对于按钮应用,将WiFi凭证存储在RTC内存中以在深度睡眠后保持:
// RTC_DATA_ATTR 在深度睡眠期间保留数据RTC_DATA_ATTR bool wifiConfigured = false;RTC_DATA_ATTR char storedSSID[32] = "";RTC_DATA_ATTR uint8_t storedBSSID[6] = {0};RTC_DATA_ATTR int storedChannel = 0;
void saveWiFiConfig() { wifiConfigured = true; strcpy(storedSSID, WiFi.SSID().c_str()); memcpy(storedBSSID, WiFi.BSSID(), 6); storedChannel = WiFi.channel();}
void connectWithCachedConfig() { if (wifiConfigured && storedChannel > 0) { // 使用缓存参数快速连接 WiFi.begin(storedSSID, WIFI_PASSWORD, storedChannel, storedBSSID, true); } else { // 首次:完整扫描 WiFi.begin(WIFI_SSID, WIFI_PASSWORD); }}第四步:连接失败处理
Section titled “第四步:连接失败处理”bool connectWiFiWithRetry(int maxRetries = 2) { for (int attempt = 0; attempt < maxRetries; attempt++) { if (attempt > 0) { Serial.print("重试第 "); Serial.println(attempt + 1); Serial.println(" 次"); }
connectWiFi();
if (WiFi.status() == WL_CONNECTED) { return true; }
delay(100); // 重试前短暂停顿 }
return false; // 所有尝试均失败}第五步:完整按钮WiFi逻辑
Section titled “第五步:完整按钮WiFi逻辑”void setup() { Serial.begin(115200); delay(100);
// 配置按键引脚 pinMode(BUTTON_PIN, INPUT_PULLUP);
// 检查唤醒原因 if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) { Serial.println("检测到按键按下 - 正在连接WiFi");
// 使用优化方式连接WiFi bool connected = connectWiFiWithRetry(3);
if (connected) { // 继续执行MQTT发布(第04-08节) publishButtonPress(); } else { Serial.println("WiFi连接失败 - 返回睡眠"); } } else { Serial.println("首次启动 - 正在初始化"); // 仅在首次上电时初始化 }
// 进入深度睡眠 goToDeepSleep();}- 按键按下后3秒内完成WiFi连接
- 在信号强的区域首次连接即成功
- 设备优雅处理连接失败(重试+睡眠)
- RTC内存在深度睡眠周期间保留WiFi配置
- 深度睡眠期间不会泄露WiFi凭证
问题1:WiFi连接时间过长
Section titled “问题1:WiFi连接时间过长”症状:连接时间 > 5秒
可能原因:
- 接入点不在范围内
- 自上次连接后信道已更改
- 启用了WiFi省电模式
解决方案:
// 记录连接阶段用于调试void debugWiFiConnection() { Serial.print("WiFi状态:"); switch (WiFi.status()) { case WL_NO_SSID_AVAIL: Serial.println("未找到接入点 - 请检查SSID和信号范围"); break; case WL_CONNECT_FAILED: Serial.println("密码错误"); break; case WL_IDLE_STATUS: Serial.println("连接进行中..."); break; }}问题2:按钮位置无WiFi信号
Section titled “问题2:按钮位置无WiFi信号”症状:频繁连接失败
解决方案:考虑替代架构:
- 使用WiFi Mesh或中继器扩展覆盖范围
- 实现离线优先模式,消息排队发送
- 改用ESP-NOW进行本地通信
- ✅ 将BSSID和信道存储在RTC内存中,实现快速重连
- ✅ 设置连接超时,避免在弱信号下卡住
- ✅ 最多重试2-3次以节省电量
- ✅ 记录连接时间以便监控性能
- ❌ 不要启用WiFi省电模式——它会增加延迟
- ❌ 如果已知BSSID,不要扫描网络
- WiFi连接通常需要2-4秒,经过优化可缩短至1-1.5秒
- 缓存BSSID和信道可显著减少连接时间
- 3次重试在可靠性和电池寿命之间取得平衡
- WiFi连接时耗电约60 mA——应尽量减少活动时间
- 连接失败应快速处理——重试2-3次后进入睡眠