SML (Smart Message Language)

The SML component connects to smart meters which use the Smart Message Language (SML) protocol.

Although the SML protocol is well defined, it gives a lot of freedom to the manufacturers how to store and identify the transmitted data. Within a telegram the physical values are identified by OBIS codes (Object Identification System). If it is known which code the manufacturer assigns to the physical value, the corresponding value can be extracted.

Hardware

This component is passive, it does not transmit any data to your equipment. Usually a smart meter transmit a telegram at regular intervals (2-4 seconds) on its own. This component decodes and updates the configured sensors at the pace the data is received.

Most smart meters transmit the telegrams using an infrared optical interface. As a sensor a suitable photo transistor (e.g. BPW40) can be attached to the ESP’s UART (emitter to GND and collector to RX pin). A more mature solution can be found here (in German). There are plenty of other examples and ready to buy solutions on the web.

Configuration

As the communciation with the sensor is done using UART, you need to have the UART bus in your configuration. The interface parameters should be set to 9600/8N1 or 9600/7E1 depending on your smart meter. If you see checksum errors in the log try changing the interface parameter.

# Example configuration entry
uart:
  id: uart_bus
  rx_pin: GPIO3
  baud_rate: 9600
  data_bits: 8
  parity: NONE
  stop_bits: 1

sml:
  id: mysml
  uart_id: uart_bus
  on_data:
    - lambda: !lambda |-
        if (valid) {
          id(mqttclient).publish("gridmeter/sensor/sml/state", format_hex(bytes));
        } else {
          id(mqttclient).publish("gridmeter/sensor/sml/error", format_hex(bytes));
        }

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

text_sensor:
  - platform: sml
    name: "Manufacturer"
    sml_id: mysml
    server_id: "0123456789abcdef"
    obis_code: "129-129:199.130.3"
    format: text

Configuration variables:

SML platform

  • id (Optional, ID): Manually specify the ID used for code generation.

  • uart_id (Optional, ID): Manually specify the ID of the UART Component if you want to use multiple UART buses.

Sensor

  • obis_code (Required, string): Specify the OBIS code you want to retrieve data for from the device. The format must be (A-B:C.D.E, e.g. 1-0:1.8.0)

  • server_id (Optional, string): Specify the device’s server_id to retrieve the OBIS code from. Should be specified if more then one device is connected to the same hardware sensor component.

  • sml_id (Optional, ID): The ID of the SML platform

  • All other options from Sensor.

Text Sensor

  • obis_code (Required, string): Specify the OBIS code you want to retrieve data for from the device. The format must be (A-B:C.D.E, e.g. 1-0:1.8.0)

  • server_id (Optional, string): Specify the device’s server_id to retrieve the OBIS code from. Should be specified if more then one device is connected to the same hardware sensor component.

  • sml_id (Optional, ID): The ID of the SML platform

  • format (Optional, string): Override the automatic interpretation of the transmitted binary data value. Possible values (int, uint, bool, hex, text).

  • All other options from Text Sensor.

Automations:

on_data Trigger

This automation will be triggered when a valid SML message is received. The variable bytes (of type std::vector<uint8_t>) contains the raw sml data including start/end sequence. The variable valid (of type bool) contains the result of the checksum verification.

Getting OBIS codes and sensor ids

The physical values in the transmitted SML telegram are identified by a server id and OBIS codes. The server id identifies your smart meter. If you have only one hardware component attached to your optical sensor you usually don’t have to care about the server id and you may ommit it in your configuration.

In order to get the server id and the available OBIS codes provided by your smart meter, simply set up the SML platform and observe the log output (the log level must be set to at least debug!).

Your log output will show something like this:

../_images/sml-log.png

OBIS information in the log of the SML component

Each line represents a combination of the server id (in brackets), the OBIS code and the transmitted hex value (in square brackets).

Precision errors

Many smart meters emit very huge numbers for certain OBIS codes (like the accumulated total active energy). This may lead to precision errors for the values reported by the sensor component to ESPHome. This shows in the fact that slightly wrong numbers may be reported to HomeAssistant. This is a result from internal limitations in ESPHome and has nothing to do with the SML component.

If you cannot live with this, you can use the TextSensor with an appropriate format to transmit the value as a string to HomeAssistant. On the HomeAssistant side you can define a Template Sensor to cast the value into the appropriate format and do some scaling.

For ESPHome we have:

# ESPHome configuration file
text_sensor:
  - platform: sml
    name: "Total energy text"
    obis_code: "1-0:1.8.0"
    format: uint

The format parameter is optional. If ommited, the SML component will try to guess the correct datatype from the received SML message.

And in 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 %}

Usually the template sensor’s value would turn to 0 if the ESP device is unavailable. This results in problems when using the sensor in combination with the Utility Meter integration. The state template provided above checks for the sensor’s availability and keeps the current state in case of unavailability.

Holley DTZ541 Smart Meters

The Holley DTZ541 series of electricity meters have a faulty implementation of the SML protocol. These meters send multiple conflicting values with the OBIS code 1-0:1.8.0, the code for the meter’s energy reading. Because the first value of every package is the correct value, in order to discard the erroneous values a throttle filter of 0.5s can be applied.

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

These meters can also measure the instantaneous power usage.

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

See Also