构建一个只读的 ESPHome 扫描器,可探测所有 256 个 OpenTherm 数据 ID
大多数 ESPHome OpenTherm 项目仅读取组件已暴露的寄存器。这引发了一个显而易见的问题:锅炉还能提供哪些其他信息?
OpenTherm 协议使用 8 位数据 ID 字段,可提供 256 种可能的寄存器编号。官方规格文档仅覆盖了其中一部分,而制造商可能会在上面实现自己的私有寄存器。为了准确了解我的锅炉所暴露的所有信息,我将 ESPHome 修改为一个寄存器扫描器,依次查询所有可能的 OpenTherm 数据 ID。
实验使用我自己的维斯曼Vitodens 100设备,通过运行ESPHome的ESP32作为OpenTherm主控。该扫描技术本身适用于任何由ESPHome OpenTherm组件支持的OpenTherm接口。
为什么要扫描整个地址空间?
灵感源于一个简单的观察:Viessmann移动应用会报告累计燃气消耗量。但我在阅读OpenTherm规范后发现,该规范中并没有关于累计燃气使用量的标准数据ID——没有任何内容提及这一信息。那么,如果应用程序知道这个数值,它又是从哪里获取的呢?
有三种可能性:
•标准范围内制造商专用的注册信息
•一个完全未记录的、大于127的寄存器,或
•另一个完全不同的沟通渠道。
唯一能决定前两者是否可行的方法,就是向锅炉询问每一个可能的档位。
OpenTherm 注册布局
该协议分配了一个8位寄存器标识符,因此分为两个部分:
•ID 0–127 — 覆盖的范围。其中大多数是标准寄存器(如流量温度、压力、调制、设定值等),ESPHome 组件已将其映射。此外,还有一些由制造商保留的空隙,这些在规范中未作定义。
•ID 128–255 — 完全超出官方规范范围。是部分制造商用于自身私有寄存器的未被认领空间。
大多数软件从不访问保留寄存器或上半部分寄存器。ESPHome 通常只轮询你明确在 YAML 中配置的实体,因此任何未配置实体的内容将不会被请求。
构建扫描仪
ESPHome 提供了一个非常实用的钩子函数 before_send,允许你在发送每个 OpenTherm 请求之前对其进行修改。我不仅请求配置好的传感器数据,而是用递增的计数器替换 outgoing Data-ID,并通过 OpenTherm 消息类型对每个响应进行分类处理。
Yaml
每条回复均按以下分类:
•READ_ACK → 支持
•UNKNOWN_DATAID → 不支持
•未回复 → 已忽略(超时)。
扫描仪仅执行 OpenTherm 读取请求,从不向锅炉写入数据,因此整个实验为只读模式,可在正常运行的系统上安全运行。发布的配置包含两项改进:它在 before_send 之前提前推进计数器,以防止超时的 ID 延迟扫描;同时,它会将每个上半部分的响应与对应的下半部分(ID 减去 128)进行镜像比对,以检测那些静默地将 ID 转换为 7 位的堆叠情况。在我的设备上,没有发生这种掩码现象——该组件确实发送了全部 256 个 ID。
一次完整的0–255扫描大约需要4到5分钟,因此建议运行10到15分钟,以捕捉那些仅间歇响应的寄存器。
结果
扫描完此锅炉的完整 0–255 地址空间后:
•25 个支持的寄存器
•22 已经由 ESPHome 显示
•3 个未记录的 OEM 寄存器
•0 个未记录的寄存器,值大于127
发现的三个原厂注册号为:
ID
价值
93
9.34
94
23.19
95
16.21
这些数值会随着时间缓慢漂移,但显然并不代表气体消耗量。对于此特定锅炉,128至255之间的每个请求均返回“Unknown-DataId”——包括ID 162,至少有一个大金(Daikin)实现版本使用该ID作为其生活热水(DHW)设定值。
读取未文档化的寄存器
发现隐藏的寄存器只是第一步。ESPHome 没有针对厂商特定数据 ID 的实体,但仍然可以监控这些数据。它不会持续进行完整扫描,而是通过在几十帧之间“借用”一个采样周期,用请求寄存器 93、94 或 95 来替代,并将获取的值发布到一个普通的模板传感器中。
Yaml
从 Home Assistant 的角度来看,这些未记录的寄存器会变成普通的传感器,可以进行绘图和日志记录。由于你无法预先知道保留寄存器的数据类型,建议使用 x.f88() 进行定点数处理,以及 x.u16() / x.s16() 处理整数,并保留能产生合理数值的那一种。
有趣的观察
测试过程中,一些细节变得显而易见:
•部分已记录的OpenTherm ID为只读类型,因此正确读取时会返回“Unknown-DataId”——这是正常现象,并非缺少支持。CH设定值(ID 1)就是一个典型例子:读取时显示为未知,但写入后锅炉仍能正常运行。
•整数寄存器不能被解码为F8.8。诸如排气温度(33)和风扇转速(35)之类的ID是普通整数;将其以定点数形式解码会产生无意义的结果。
•制造商确实使用自定义数据ID,但并非所有锅炉都使用地址空间的上半部分——我的设备除外。
•不同供应商可能会将相同功能放置在完全不同的ID上(例如,将DHW设定值设为162,而不是56)。
结论
这项实验最有用的结果并非发现隐藏的锅炉数据,而是建立了一种可重复使用的探索方法,用于研究任何OpenTherm实现。
在我的Viessmann Vitodens 100上,通过OpenTherm无法获取隐藏的燃气表。我找到的是三个未记录的、特定于制造商的寄存器,ESPHome通常无法访问这些寄存器。
因为整个扫描器只是一个小型的ESPHome钩子,任何使用支持的OpenTherm接口的人都可以在自己的锅炉上重复实验并比较结果。不同制造商提供的协议子集各不相同,因此最有趣的发现很可能来自对更广泛硬件的测试。
本文编译自hackster.io





