跳转到内容

SML (智能消息语言)

SML 组件连接到使用 智能消息语言 (SML) 协议的智能电表。

尽管 SML 协议有明确定义,但它为制造商在存储和标识传输数据方面提供了很大的自由度。在一个报文中,物理值由 OBIS 代码(对象标识系统)来识别。如果已知制造商为某物理值分配的代码,就可以提取出对应的值。

该组件是被动的,它不会向你的设备传输任何数据。通常智能电表会自行按固定间隔(2-4 秒)发送报文。 该组件以接收数据的速度进行解码并更新已配置的传感器。

大多数智能电表使用红外光学接口发送报文。可以搭配合适的光电晶体管(例如 BPW40)连接到 ESP 的 UART(发射极到 GND,集电极到 RX 引脚)。更完善的解决方案(德语)可以在 Volkszaehler Wiki 上找到。网络上还有很多其他示例和可购买的现成方案。

由于与传感器的通信是通过 UART 进行的,你需要在配置中包含 UART 总线。接口参数应根据你的智能电表设置为 9600/8N1 或 9600/7E1。如果你在日志中看到校验和错误,可以尝试更改接口参数。

# 示例配置条目
sml:
id: mysml
uart_id: uart_bus
on_data:
- lambda: !lambda |-
char hex[512]; // Size appropriately for your data
if (valid) {
id(mqttclient).publish("gridmeter/sensor/sml/state", format_hex_to(hex, bytes));
} else {
id(mqttclient).publish("gridmeter/sensor/sml/error", format_hex_to(hex, bytes));
}
  • id (可选, ID): 手动指定用于代码生成的 ID。
  • uart_id (可选, ID): 如果你想使用多个 UART 总线,可手动指定 UART 组件 的 ID。
sensor:
- platform: sml
name: "Total energy"
sml_id: mysml
server_id: "0123456789abcdef"
obis_code: "1-0:1.8.0"
unit_of_measurement: kWh
accuracy_decimals: 1
device_class: energy
state_class: total_increasing
filters:
- multiply: 0.0001
  • obis_code (必选, string): 指定你想从设备获取数据的 OBIS 代码。格式必须为 (A-B:C.D.E,例如 1-0:1.8.0)

  • server_id (可选, string): 指定设备的 server_id 以从中提取 OBIS 代码。如果多个设备连接到同一个硬件传感器组件,则应指定此项。

  • sml_id (可选, ID): SML 平台 的 ID

  • 其他所有选项来自 Sensor。

text_sensor:
- platform: sml
name: "Manufacturer"
sml_id: mysml
server_id: "0123456789abcdef"
obis_code: "129-129:199.130.3"
format: text
  • obis_code (必选, string): 指定你想从设备获取数据的 OBIS 代码。格式必须为 (A-B:C.D.E,例如 1-0:1.8.0)

  • server_id (可选, string): 指定设备的 server_id 以从中提取 OBIS 代码。如果多个设备连接到同一个硬件传感器组件,则应指定此项。

  • sml_id (可选, ID): SML 平台 的 ID

  • format (可选, string): 覆盖对传输的二进制数据值的自动解释。可选值有 (int、uint、bool、hex、text)。

  • 其他所有选项来自 Text Sensor。

收到有效的 SML 消息时将触发该自动化。变量 bytes(类型为 std::vector<uint8_t>)包含包含起始/结束序列的原始 SML 数据。变量 valid(类型为 bool)包含校验和验证的结果。

传输的 SML 报文中的物理值由 server id 和 OBIS 代码 标识。server id 标识你的智能电表。如果你的光学传感器只连接了一个硬件组件,通常不需要关心 server id,可以在配置中省略它。

为了获取 server id 以及智能电表提供的可用 OBIS 代码,只需设置好 SML 平台 并观察日志输出(日志级别 必须至少设为 debug!)。

你的日志输出会显示如下类似的内容:

SML 组件日志中的 OBIS 信息

每一行代表 server id(方括号内)、OBIS 代码和传输的十六进制值(方括号内)的组合。

许多智能电表对某些 OBIS 代码(如累积的总有功电量)输出非常大的数字。这可能导致传感器组件上报给 ESPHome 的值存在精度误差。这表现为向 HomeAssistant 报告了略微错误的数值。这是 ESPHome 内部限制导致的结果,与 SML 组件本身无关。

如果你无法接受这种情况,可以使用 TextSensor 配合适当的格式,将值以字符串形式传输到 HomeAssistant。在 HomeAssistant 端可以定义一个 Template Sensor 将值转换为合适的格式并进行一定的缩放。

在 ESPHome 中配置如下:

# ESPHome 配置文件
text_sensor:
- platform: sml
name: "Total energy text"
obis_code: "1-0:1.8.0"
format: uint

format 参数是可选的。如果省略,SML 组件会尝试从收到的 SML 消息中猜测正确的数据类型。

在 HomeAssistant 中:

# Home Assistant 配置 (configuration.yaml)
template:
- sensor:
- name: "Total Energy Consumption"
unit_of_measurement: "kWh"
state: >
{% if states('sensor.total_energy_text') == 'unavailable' %}
{{ states('sensor.total_energy_consumption') }}
{% else %}
{{ ((states('sensor.total_energy_text') | float) * 0.0001) | round(2) }}
{% endif %}

通常,当 ESP 设备不可用时,模板传感器的值会变为 0。这会导致在配合 Utility Meter 集成使用传感器时出现问题。上面提供的状态模板会检查传感器的可用性,并在不可用时保持当前状态。

Holley DTZ541 系列电能表存在 SML 协议的有缺陷实现。这些电表使用 OBIS 代码 1-0:1.8.0(即电表电量读数对应的代码)发送多个相互冲突的值。由于每个包中的第一个值是正确值,为了丢弃错误值,可以应用 0.5s 的节流过滤器。

sensor:
- platform: sml
name: "Total energy Consumption"
sml_id: mysml
obis_code: "1-0:1.8.0"
unit_of_measurement: kWh
accuracy_decimals: 5
device_class: energy
state_class: total_increasing
filters:
- throttle: 0.5s
- multiply: 0.0001

这些电表也可以测量瞬时功率。

sensor:
- platform: sml
name: "Instantaneous power"
sml_id: mysml
obis_code: "1-0:16.7.0"
unit_of_measurement: W
accuracy_decimals: 0
device_class: power
state_class: measurement