背景我搭建了一个 ESP-NOW 门锁系统被控端电池供电ESP32-C3 裸机 C 代码deep sleep 周期性唤醒监听 30ms 后继续睡网关有线供电ESPHome ESP-NOW接收 HA 指令转发给被控端被控端有两种周期白天1s 睡 30ms 醒夜间20s 睡 30ms 醒省电网关每天早上 7:00 发送切换到白天模式命令晚上 22:00 发送切换到夜间模式命令。问题有时候早上唤醒不了被控端。不是每次都失败但从日志看大约 60~70% 的概率收不到切换命令导致全天处于夜间模式。直觉方案错误的起初我对时序问题不敏感。被控端 20s 醒来一次那只要发送窗口超过 20s 就 OK 了。于是网关配置# 每 6s 发一次, 发 11 次 66s 窗口send_day_cmd:repeat:count:11then:-espnow.send:{data:[0x04]}-delay:6s66s 20s理论上至少能命中 3 个唤醒窗口。为什么还是不灵真正的数学画个时序图就清楚了被控端醒来(30ms): |--| |--| |--| t0 t20s t40s 网关发送(6s间隔): ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ 0 6 12 18 24 30 36 42 48 54 60s问题在于发送间隔6s远大于唤醒窗口30ms。t0刚好对齐 → 可能命中 ✅t20s被控端醒 30ms但网关要等到 t24s 才发 → 错过 ❌t40s被控端醒 30ms网关要等到 t42s → 又错过 ❌单次 30ms 窗口撞上 6s 发送间隔的概率只有30ms / 6000ms 0.5%。即使窗口内醒来 3 次命中概率也不过 1.5%。我第一次配置的直觉完全错了。正确解法可靠唤醒需要同时满足两个条件条件 1发送间隔 唤醒窗口发送间隔 30ms → 每个醒来窗口必然包含至少一次发送如果反过来发送间隔 唤醒窗口窗口可能恰好落在两次发送之间。条件 2覆盖时长 睡眠周期覆盖时长 20s → 至少经历一个完整的睡→醒循环两个条件缺一不可。满足条件的配置# 25ms 间隔 30ms 窗口 ← 条件1# 840×25ms 21s 20s ← 条件2send_day_cmd:repeat:count:840then:-espnow.send:{data:[0x04]}-delay:25ms修复后的时序被控端醒来(30ms): |----30ms----| t? 网关发送(25ms间隔): ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑30ms 窗口 25ms 间隔 → 无论何时醒来窗口内必定包含发送。21s 覆盖 20s 周期 → 至少经历一次醒来。四个命令的完整配置白天命令1s 周期同理命令次数间隔覆盖目标周期开门4525ms1.125s1s关门4525ms1.125s1s夜间模式4525ms1.125s1s白天模式84025ms21s20s总结这个问题本质上是占空比错配不是对比覆盖时长 vs 睡眠周期直觉陷阱而是发送间隔 vs 唤醒窗口和覆盖时长 vs 睡眠周期两个维度的交叠画时序图是最直接的诊断方法。如果偷懒没画图很容易像我一开始那样看见 66s 20s 就觉得没问题了。通用公式保证命中 ⟺ 发送间隔 唤醒窗口 且 覆盖时长 睡眠周期如果你的低功耗设备和这个场景类似直接套这个公式就行。
ESP-NOW 低功耗设备的可靠唤醒:一个被忽视的时序问题
发布时间:2026/7/6 1:43:47
背景我搭建了一个 ESP-NOW 门锁系统被控端电池供电ESP32-C3 裸机 C 代码deep sleep 周期性唤醒监听 30ms 后继续睡网关有线供电ESPHome ESP-NOW接收 HA 指令转发给被控端被控端有两种周期白天1s 睡 30ms 醒夜间20s 睡 30ms 醒省电网关每天早上 7:00 发送切换到白天模式命令晚上 22:00 发送切换到夜间模式命令。问题有时候早上唤醒不了被控端。不是每次都失败但从日志看大约 60~70% 的概率收不到切换命令导致全天处于夜间模式。直觉方案错误的起初我对时序问题不敏感。被控端 20s 醒来一次那只要发送窗口超过 20s 就 OK 了。于是网关配置# 每 6s 发一次, 发 11 次 66s 窗口send_day_cmd:repeat:count:11then:-espnow.send:{data:[0x04]}-delay:6s66s 20s理论上至少能命中 3 个唤醒窗口。为什么还是不灵真正的数学画个时序图就清楚了被控端醒来(30ms): |--| |--| |--| t0 t20s t40s 网关发送(6s间隔): ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ 0 6 12 18 24 30 36 42 48 54 60s问题在于发送间隔6s远大于唤醒窗口30ms。t0刚好对齐 → 可能命中 ✅t20s被控端醒 30ms但网关要等到 t24s 才发 → 错过 ❌t40s被控端醒 30ms网关要等到 t42s → 又错过 ❌单次 30ms 窗口撞上 6s 发送间隔的概率只有30ms / 6000ms 0.5%。即使窗口内醒来 3 次命中概率也不过 1.5%。我第一次配置的直觉完全错了。正确解法可靠唤醒需要同时满足两个条件条件 1发送间隔 唤醒窗口发送间隔 30ms → 每个醒来窗口必然包含至少一次发送如果反过来发送间隔 唤醒窗口窗口可能恰好落在两次发送之间。条件 2覆盖时长 睡眠周期覆盖时长 20s → 至少经历一个完整的睡→醒循环两个条件缺一不可。满足条件的配置# 25ms 间隔 30ms 窗口 ← 条件1# 840×25ms 21s 20s ← 条件2send_day_cmd:repeat:count:840then:-espnow.send:{data:[0x04]}-delay:25ms修复后的时序被控端醒来(30ms): |----30ms----| t? 网关发送(25ms间隔): ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑30ms 窗口 25ms 间隔 → 无论何时醒来窗口内必定包含发送。21s 覆盖 20s 周期 → 至少经历一次醒来。四个命令的完整配置白天命令1s 周期同理命令次数间隔覆盖目标周期开门4525ms1.125s1s关门4525ms1.125s1s夜间模式4525ms1.125s1s白天模式84025ms21s20s总结这个问题本质上是占空比错配不是对比覆盖时长 vs 睡眠周期直觉陷阱而是发送间隔 vs 唤醒窗口和覆盖时长 vs 睡眠周期两个维度的交叠画时序图是最直接的诊断方法。如果偷懒没画图很容易像我一开始那样看见 66s 20s 就觉得没问题了。通用公式保证命中 ⟺ 发送间隔 唤醒窗口 且 覆盖时长 睡眠周期如果你的低功耗设备和这个场景类似直接套这个公式就行。