Reading data from a smart meter speaking D0

Hi, I wanted to share my solution for reading data from a smart meter speaking D0 / OBIS. I have a Hager meter approximately 10 years old, which doesn’t speak EDL21 / SML.
I bought an infrared reader whith USB which is connected to the Raspberry Pi 4 running Home Assistant OS. The reader works perfectly as a Serial sensor:

- platform: serial
  serial_port: /dev/ttyUSB0
  baudrate: 9600
  bytesize: 7
  parity: E
  stopbits: 1
  name: smartmeter_data

The meter outputs its current state every second or so. The raw data accumulates to a useless state history very quickly, so I disabled recording for the sensor:

recorder:
  exclude:
    entities:
      - sensor.smartmeter_data

The D0 format includes carriage return + line feed to deliminate the different parts of each message. Therefore I used the following template sensors which ignore intermediate lines with other data. Moreover, my meter gives out the current consumption per phase, which have to be added up.

-platform: template
  sensors:
    smartmeter_total:
      unit_of_measurement: "kWh"
      value_template: >
        {% if states('sensor.smartmeter_data')|regex_search("1-0:1\.8\.0\*255") %}
          {{ states('sensor.smartmeter_data')|regex_findall_index("\((\d*\.\d*)\)") | float }}
        {% else %}
          {{ states('sensor.smartmeter_total') | float }}
        {% endif %}

    smartmeter_consumption_phase1:
      unit_of_measurement: "W"
      value_template: >
        {% if states('sensor.smartmeter_data')|regex_search("1-0:21\.7\.0\*255") %}
          {{ states('sensor.smartmeter_data')|regex_findall_index("\(([+-]\d*)") | float }}
        {% else %}
          {{ states('sensor.smartmeter_consumption_phase1') | float }}
        {% endif %}

    smartmeter_consumption_phase2:
      unit_of_measurement: "W"
      value_template: >
        {% if states('sensor.smartmeter_data')|regex_search("1-0:41\.7\.0\*255") %}
          {{ states('sensor.smartmeter_data')|regex_findall_index("\(([+-]\d*)") | float }}
        {% else %}
          {{ states('sensor.smartmeter_consumption_phase2') | float }}
        {% endif %}

    smartmeter_consumption_phase3:
      unit_of_measurement: "W"
      value_template: >
        {% if states('sensor.smartmeter_data')|regex_search("1-0:61\.7\.0\*255") %}
          {{ states('sensor.smartmeter_data')|regex_findall_index("\(([+-]\d*)") | float }}
        {% else %}
          {{ states('sensor.smartmeter_consumption_phase3') | float }}
        {% endif %}

    smartmeter_consumption_total:
      unit_of_measurement: "W"
      value_template: >
        {{ states('sensor.smartmeter_consumption_phase1') | float + states('sensor.smartmeter_consumption_phase2') | float + states('sensor.smartmeter_consumption_phase3') | float }}

The first regex in every template checks wether the current line contains the data for this sensor. The string searched for is the identifier from OBIS, for example ‘1-0:1.8.0*255’ is the total sum of the consumption.
The second regex reads the value between the parentheses in the line.

5 Likes

Hi,
I tried to use your configuration with my smartmeter. I am a beginner with homeassistant and struggeled a bit. Using a “modern” configuration I was able to get the reading of my smartmeter with this configuration. And I was able to use the sensors in the energy chart.

sensor:
  - platform: serial
    serial_port: /dev/ttyUSB0
    baudrate: 9600
    bytesize: 7
    parity: E
    stopbits: 1
    name: smartmeter_data
    
      
template:
  sensor:
    - name: smartmeter_import_total
      unit_of_measurement: "kWh"
      state_class: "total_increasing"
      device_class: "energy"
      state: >
        {% if states('sensor.smartmeter_data')|regex_search("1-0:1\.8\.0\*255") %}
           {{ states('sensor.smartmeter_data')|regex_findall_index("\((\d*\.\d*)\*kWh\)") | float | round(1) }}
        {% else %}
          {{ states('sensor.smartmeter_import_total') | float }}
        {% endif %}
          
    - name: smartmeter_export_total
      unit_of_measurement: "kWh"
      state_class: "total_increasing"
      device_class: "energy"
      state: >
        {% if states('sensor.smartmeter_data')|regex_search("1-0:2\.8\.0\*255") %}
          {{ states('sensor.smartmeter_data')|regex_findall_index("\((\d*\.\d*)\*kWh\)") | float | round(1) }}
        {% else %}
          {{ states('sensor.smartmeter_export_total') | float }}
        {% endif %}


I hope this might help someone else to get this working. Other readings (like consumption per phase) can be added in a similar way.

But I noticed that home assistant consumes a lot of cpu time after adding all readings. Thus I tried vzlogger / volkszaehler.org instead and cpu load decreased by a factor of more than 10. Setup is more complicated as vzlogger reports via mqtt to home assistant. I did not use any of the features to save and analyze the data. Imho it’s worth to give it a try (if you can live with a documentation written in German).

1 Like

i tried this the whole night and its not working :frowning:

maybe someone can help me

it works now :wink:

# Loads default set of integrations. Do not remove.
default_config:

# Load frontend themes from the themes folder
frontend:
  themes: !include_dir_merge_named themes

automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
sensor:
  - platform: serial
    serial_port: /dev/ttyUSB0
    parity: E
    stopbits: 1
    bytesize: 7
    scan_interval: 30
    name: smartmeter_data

  - platform: template
    sensors:
      smartmeter_total:
        unit_of_measurement: "kWh"
        value_template: >
          {% if states('sensor.smartmeter_data')|regex_search("1-0:1.8.0*") %}
            {{ states('sensor.smartmeter_data')|regex_findall_index("(\d+\.\d+)\\*kWh") }}
          {% endif %}
          
  - platform: template
    sensors:
      smartmeter_momentanverbrauch:
        unit_of_measurement: "W"
        value_template: >
          {% if states('sensor.smartmeter_data')|regex_search("1-0:16.7.0*") %}
            {{ states('sensor.smartmeter_data')|regex_findall_index("(\d+\.\d+)\\*W") }}
          {% endif %}
          
  - platform: template
    sensors:
      smartmeter_einspeisezaehler:
        unit_of_measurement: "kWh"
        value_template: >
          {% if states('sensor.smartmeter_data')|regex_search("1-0:2.8.0*") %}
            {{ states('sensor.smartmeter_data')|regex_findall_index("(\d+\.\d+)\\*kWh") }}
          {% endif %}