ESP32-C3 OTA Relay / WiFi Incident Plan

WiFi 冷启动连接失败排查与系统化修复计划

面向长时间断电后无法连接 STA 的问题,按“复现证据 → 最小诊断 → P0 修复 → 运行期恢复 → 验证矩阵”的顺序推进,避免一次性大改掩盖真实根因。

目标:冷启动 STA 稳定联网 范围:WiFi / NVS / PHY / Watchdog / SPI mutex 项目:G:\Robot_v2\DCU\ESP32_COMM

根因优先级

先处理能直接解释“长时间断电后首连失败”和“失败后不恢复”的路径。

优先级 根因 位置 影响
P0 冷启动擦 PHY 校准 + 仅 500ms 延迟 wifi_ota.cpp L1524-L1531, L340-L342 全量 PHY 校准可能需要更长时间,反复擦除会让首连更不稳定。
P0 重试耗尽标志运行中不恢复 wifi_ota.cpp L196-L208 m_staRetryExhausted=true 后可能长期阻止后续重连。
P1 listen_interval=3 偏短 wifi_ota.cpp L324 长时间空闲或 AP 策略严格时,STA 更容易被驱逐。
P1 无 IP_EVENT_STA_LOST_IP 处理 wifi_ota.cpp L228-L242 设备可能已经无 IP,但内部仍认为已连接。
P1 主循环无 WiFi 断线看门狗 wifi_ota.cpp L1679-L1707 运行期断线后缺少强制恢复策略。
P2 断线原因码未解码 wifi_ota.cpp L201 日志只有数字,难以区分认证、AP 不存在、握手超时、AP 驱逐。
P2 SpiMaster mutex 空指针风险 spi_master.cpp L288-L290 先 lock 空 mutex 再创建 mutex,属于明确初始化顺序问题。
P2 NVS 初始化错误处理不完整 wifi_ota.cpp L1492-L1508 只处理两个错误码,其他 NVS 异常缺少统一恢复路径。

复现证据

本阶段只补充诊断能力和采集日志,不改变核心连接策略。

串口日志必抓字段

  • 复位原因: POWER_ON / BROWNOUT / SOFTWARE / 其他
  • 冷启动 是否成立,是否擦除 WiFi NVS 或 PHY
  • STA 已启动、STA 已关联到 AP、STA 获取 IP
  • STA 断开 的 reason code 与可读原因
  • STA 重试已耗尽 和是否切换 AP

路由器侧同步检查

  • ESP32 MAC 是否出现在关联列表
  • 是否产生 DHCP 租约,租约 IP 是否变化
  • AP 日志中是否有 deauth / disassoc / handshake timeout
  • 路由器冷启动时 WiFi 和 DHCP 服务恢复耗时

实施阶段

从可观测性开始,再进入 P0/P1 修复,最后做覆盖测试。

01Baseline

复现与日志基线

冷启动抓 5 分钟串口日志,同时记录路由器关联和 DHCP 日志,确认失败发生在关联前、关联后取 IP、还是运行中断线。

serial_monitor.py reset reason router log
02Observe

增加最小诊断能力

解码断线 reason,补充 retry、exhausted、heap、uptime 和 WiFi API 返回值日志。

wifiReasonToStr heap uptime
03P0 Fix

冷启动与重试耗尽修复

冷启动 PHY 延迟提升到 1500ms;移除无条件 PHY 擦除;重试耗尽增加 30s 冷却恢复机制。

PHY delay conditional erase retry cooldown
04P1 Fix

运行期断线恢复

处理 LOST_IP,增大 listen_interval,配置 inactive time,并加入断线 60s 后的 WiFi 看门狗恢复。

LOST_IP listen_interval=10 watchdog
05Verify

构建与实机验证

ESP-IDF v6.0 全量构建,执行冷启动、路由器晚启动、DHCP 变化、路由器重启、弱信号与 BLE OTA 后恢复测试。

idf.py build cold boot x5 router restart x3

任务清单

勾选状态保存在当前浏览器 localStorage,便于多次打开继续跟踪。

验证矩阵

每个场景至少保留串口日志;涉及路由器的场景同步保留 AP/DHCP 日志。

场景 操作 通过标准
长时间断电后冷启动 断电足够久后上电,抓 5 分钟日志,重复 5 次。 STA 能连接并获取 IP,不依赖手动重启。
路由器晚启动 60-120s 先启动 ESP32,延迟启动路由器或 WiFi 服务。 首次失败后仍能自动恢复 STA。
DHCP 服务慢或租约变化 缩短 DHCP 租约或重启 DHCP 服务。 LOST_IP 后标记断线并重新获取 IP。
路由器重启 ESP32 在线时重启路由器,重复 3 次。 断线后自动恢复,HTTP 服务重新可访问。
WiFi 密码错误 临时配置错误密码或错误 SSID。 reason 可读,不高频无限重试。
弱信号环境 拉远距离或降低 AP 发射功率。 RSSI、断线原因、恢复动作均可观察。
BLE OTA 后 WiFi 执行 BLE OTA 流程后访问 WiFi HTTP API。 WiFi 省电模式恢复为 WIFI_PS_NONE。
SPI 初始化 启动后执行 SPI/CAN 相关 API 或中继流程。 无 mutex NULL 风险,无初始化异常。

风险与缓解

修复目标是提高恢复能力,同时避免掩盖配置错误或产生高频重试。

启动速度变慢

PHY 延迟仅冷启动生效,热启动不受影响。验证时记录冷启动总耗时。

无限重连循环

用 30s 冷却期和看门狗分级恢复控制频率,并保留错误 reason。

HTTP 连接中断

stop/start 仅在断线 60s+ 且多次强制重连失败后执行,此时 HTTP 已不可用。

功耗略增

设备为有线供电,listen_interval=10 与 inactive time 的稳定性收益优先。

执行命令

根据本机 ESP-IDF 环境调整串口号和 Python/IDF 命令入口。

# 冷启动串口日志采集
python serial_monitor.py

# 预期输出文件
G:\Robot_v2\DCU\ESP32_COMM\serial_log.txt
# ESP-IDF v6.0 构建
idf.py build

# 可选:清理后构建
idf.py fullclean
idf.py build

决策记录

以下备选方案暂不采用,除非后续日志推翻当前判断。

×
保留无条件 PHY 擦除 PHY 校准数据是环境相关积累数据,保留通常比每次冷启动擦除更可靠。
×
只增加 WIFI_STA_MAX_RETRY 单纯增加次数不能解决耗尽后恢复、运行期断线、LOST_IP 等状态闭环问题。
×
优先优化 DHCP 超时 当前总等待 30s 已覆盖多数 DHCP 慢场景,需先用日志确认是否真的卡在 DHCP。
✓
先增强诊断再修复 reason 解码和状态日志能避免把认证、信道、供电、DHCP 问题混在一起处理。