- Zed IoT
-
2026年5月5日 -
下午1:17 -
0 评论
很多 ESPHome 设备刚刷完固件时非常稳定:传感器能上报,Home Assistant 能看到实体,自动化也能触发。真正的问题往往在几天或几周后出现:设备偶发重启、API 断开、传感器数值停住、日志里看不到明确报错,最后只能手动断电恢复。
本文的核心结论是:ESPHome 长期稳定性问题通常不是“某一行 YAML 写错”,而是内存、阻塞组件、Wi-Fi 链路、日志策略和传感器时序共同累积后的系统问题。 如果只看设备是否在线,而不记录 uptime、reset reason、free heap、最小可用 heap、fragmentation 和最后一次有效读数,就很难区分“程序泄漏”“堆碎片”“网络抖动”和“外设阻塞”。

定义块
本文所说的长期稳定性调试,是指设备在首日正常、但运行多天或多周后才出现重启、离线、卡顿或读数停滞时,通过运行时诊断实体、日志和配置边界来定位问题。它不是单次编译错误排查,也不是单个传感器接线检查。
1. 为什么“能运行一天”不代表设备稳定
ESP32 + ESPHome 的原型阶段很容易给人一种错觉:只要设备接入 Home Assistant,实体正常刷新,就可以认为固件已经完成。但长期运行会放大短测看不到的问题。
常见的长期稳定性来源有 5 类:
| 现象 | 常见根因 | 需要观察的信号 |
|---|---|---|
| 几天后自动重启 | heap 下降、碎片化、看门狗、供电波动 | uptime、reset reason、free heap、min free heap |
| 设备仍在线但读数停住 | 传感器阻塞、I2C 异常、组件 update 卡住 | 最后有效读数时间、组件日志、总线错误 |
| Home Assistant API 频繁断开 | Wi-Fi RSSI 差、路由器漫游、API keepalive 失败 | Wi-Fi 信号、连接次数、API 断开时间 |
| 运行越久越慢 | 日志过多、动态分配、Web Server 或 display 负载 | loop time、heap fragmentation、日志等级 |
| 偶发恢复后又复现 | 外设供电、线缆、湿度、现场干扰 | 重启时间与现场环境、供电记录、错误分布 |
判断句:如果一个 ESPHome 节点只暴露业务传感器,不暴露运行诊断实体,那么设备一旦在几周后失稳,排障成本会从“看一个趋势”变成“猜一个系统”。
2. 先补诊断实体,再改配置
长期稳定性调试的第一步不是重写 YAML,而是补齐能长期观察的诊断实体。最小集合建议包括:
- uptime:确认设备从什么时候开始重新计时。
- reset reason:区分软件重启、看门狗、上电复位或异常复位。
- free heap:观察当前可用内存。
- min free heap:观察运行期间曾经跌到过的最低可用内存。
- fragmentation:判断可用 heap 是否被切碎。
- Wi-Fi signal:排除弱信号和漫游导致的误判。
- last valid reading:对关键传感器记录最后一次可信更新时间。
debug:
update_interval: 60s
sensor:
- platform: uptime
name: "Node Uptime"
- platform: debug
free:
name: "Heap Free"
block:
name: "Heap Max Block"
loop_time:
name: "Loop Time"
text_sensor:
- platform: debug
reset_reason:
name: "Reset Reason"这段配置不是完整模板,而是调试思路:让设备把“自己还能不能长期健康运行”变成可观察对象。业务传感器告诉你环境发生了什么,诊断实体告诉你设备本身是否还可信。

3. 用一条诊断路径缩小问题范围
flowchart TD
A("发现设备异常"):::slate --> B("检查 uptime 是否归零"):::blue
B -->|是| C("查看 reset reason"):::cyan
B -->|否| D("检查业务读数是否停滞"):::orange
C --> E("关联 heap / Wi-Fi / 供电"):::violet
D --> F("检查组件阻塞与总线错误"):::green
E --> G("最小复现场景"):::blue
F --> G
G --> H("只改一个变量并观察 3-7 天"):::orange
classDef blue fill:#EAF4FF,stroke:#3B82F6,color:#16324F,stroke-width:2px;
classDef cyan fill:#E9FBF8,stroke:#14B8A6,color:#134E4A,stroke-width:2px;
classDef orange fill:#FFF3E8,stroke:#F08A24,color:#7C3F00,stroke-width:2px;
classDef violet fill:#F4EDFF,stroke:#8B5CF6,color:#4C1D95,stroke-width:2px;
classDef green fill:#ECFDF3,stroke:#22C55E,color:#14532D,stroke-width:2px;
classDef slate fill:#F8FAFC,stroke:#64748B,color:#1F2937,stroke-width:2px;这条路径的关键是先分清两类问题:设备是否真的重启过,还是设备没有重启但某个业务链路停住了。前者更关注 reset reason、heap、供电和看门狗;后者更关注传感器驱动、I2C / UART 总线、阻塞调用和外部服务。
不要在一次排障里同时修改 Wi-Fi、日志、采样周期、传感器配置和供电。长期稳定性问题本来就需要时间暴露,同时修改多个变量只会让下一次复现更难解释。
4. heap 不只看当前值,还要看最低点和碎片化
很多 ESP32 设备在刚启动时 free heap 看起来足够,但运行多天后会出现两类问题:
- 总可用 heap 逐渐下降,说明可能存在泄漏或缓存累积。
- 总可用 heap 仍然不少,但最大连续块变小,说明碎片化可能让大块分配失败。
这就是为什么只看当前 free heap 不够。min_free 一类最低点信号能暴露瞬时低谷,fragmentation 或最大连续块能暴露“看起来还有内存,但无法分配合适连续空间”的情况。
判断句:如果 ESP32 节点只在某些网络重连、传感器异常或显示刷新后重启,那么应优先观察 heap 最低点与最大连续块,而不是只看重启后的当前 free heap。
实际排障时,可以按下面的顺序压缩范围:
- 降低日志等级,避免长期高频日志占用串口、网络和内存。
- 暂时关闭非必要组件,例如 Web Server、display、蓝牙扫描或高频模板传感器。
- 拉长传感器
update_interval,确认是否由某个采样周期触发。 - 去掉自定义 lambda 或复杂字符串拼接,观察 heap 曲线是否变平。
- 把同一配置跑在另一块板或另一套供电上,排除硬件和电源差异。
5. Wi-Fi 和 API 断开不等于固件崩溃
ESPHome 设备在 Home Assistant 里离线,并不一定代表 MCU 重启。Wi-Fi 漫游、RSSI 差、路由器重启、API 连接数、mDNS 解析和网络阻塞都可能造成“看起来像设备挂了”的体验。
排查时先问两个问题:
- uptime 是否归零?如果没有,设备可能没有重启。
- 本地日志或串口是否仍有输出?如果有,问题可能在网络链路或 API。
如果设备安装在金属柜、配电箱、冷库、楼宇弱电间或工业现场,Wi-Fi 信号波动本身就是长期稳定性的一部分。此时不要把网络问题误修成固件问题;更合理的做法是补 Wi-Fi RSSI、连接状态和最后一次上报时间,再决定是否换天线、移动路由器、改用以太网,或把关键链路迁移到更可靠的网关。
6. 什么时候 ESPHome 不是合适抽象
ESPHome 很适合快速构建设备接入、家庭自动化节点、小型传感器网关和 Home Assistant 生态设备。但如果项目进入下面几类场景,继续只靠 YAML 叠组件可能会让系统越来越难维护:
- 需要严格实时控制、复杂状态机或安全联锁。
- 需要多线程任务调度、复杂缓存、协议栈重试和本地持久队列。
- 需要长期 OTA 灰度、远程日志回传、故障自恢复和批量运维。
- 需要对内存、任务、堆栈和外设错误做代码级治理。
更稳妥的边界是:ESPHome 负责可配置、可观察、接入成本低的边缘节点;当设备已经变成生产级网关或控制器,就应该考虑 ESP-IDF、定制固件,或把复杂逻辑上移到边缘网关和平台。
7. 参考资料
典型应用介绍


