[RELEASE] dsmr-custom: Universal ESPHome Component for DSMR-compatible Smart Meters

Hello everyone,

I’m excited to share dsmr-custom, an enhanced ESPHome component for reading P1 port data from smart meters. It was born out of the need to reliably support Finnish meters (SESKO standard), but it has been built with flexibility in mind to support a wide range of DSMR-compatible meters, including experimental support for encrypted telegrams.

The key to this component is a diagnostics-first workflow. This guide will first show you the most stable way to discover every OBIS code your specific meter provides, and then how to build a powerful, custom configuration based on that data.


Getting Started: The 3-Step Guide

Follow these steps to get up and running reliably. This process is designed to prevent common issues like device crashes on platforms with limited memory like the ESP8266.

Step 1: Add the Component to ESPHome

You don’t need to copy any files. Simply add the following external_components block to your device’s YAML configuration. ESPHome will automatically download the component from GitHub.

external_components:
  - source:
      type: git
      url: https://github.com/nikopaulanne/dsmr-custom
      ref: v1.0.2 # Or the latest version tag
    components: [ dsmr_custom ]

Step 2: Discover Your Meter’s OBIS Codes

Next, we’ll use a minimal configuration to safely listen to your meter and print its raw data to the ESPHome logs. This is the most important step.

  1. Use the Diagnostic Configuration Below: Flash your device with this code. Its only job is to listen for one full data packet (a “telegram”) and print it to the logs.

    # In your secrets.yaml, define your WiFi credentials, etc.
    # wifi_ssid: "YourNetwork"
    # ...
    
    esphome:
      name: dsmr-diagnostics
    
    esp8266:
      board: d1_mini
    
    # Add your wifi, api, ota...
    
    logger:
      level: INFO # Necessary to see the log output
    
    uart:
      id: uart_bus
      baud_rate: 115200
      rx_pin: D7 # IMPORTANT: Change to your device's RX pin
      rx_buffer_size: 1700
    
    external_components:
      - source:
          type: git
          url: https://github.com/nikopaulanne/dsmr-custom
          ref: v1.0.2
        components: [ dsmr_custom ]
    
    dsmr_custom:
      id: dsmr_hub
      uart_id: uart_bus
    
    text_sensor:
      - platform: dsmr_custom
        dsmr_custom_hub_id: dsmr_hub
        # This confirms a connection, but the magic happens below.
        identification:
          name: "P1 Telegram Header"
        
        # This captures the full telegram internally and uses a lightweight
        # trigger to print it to the logs without crashing the device.
        telegram:
          internal: true 
          on_value:
            - logger.log:
                level: INFO
                tag: "telegram_dump"
                format: "--- FULL TELEGRAM RECEIVED ---\n%s\n-----------------------------"
                args: [x.c_str()]
    
  2. View the Logs: In Home Assistant, go to Settings > Add-ons > ESPHome, select your device, and click LOGS.

  3. Copy the Data: Wait for a telegram to arrive. You will see a block of text in the logs starting with --- FULL TELEGRAM RECEIVED ---. Copy this entire block. You now have a complete list of every data point your meter provides!

Step 3: Build Your Final Configuration

Now, create your final YAML. Remove the diagnostic on_value trigger and use the OBIS codes you copied from the log to define your own sensors.

dsmr_custom:
  id: dsmr_hub
  uart_id: uart_bus
  # ... other hub settings ...
  
  custom_obis_sensors:
    # Use the codes you discovered in Step 2!
    - code: "1-0:1.8.0"
      name: "Total Energy Import"
      type: sensor
      unit_of_measurement: "kWh"
      device_class: energy
      state_class: total_increasing

    - code: "1-0:31.7.0"
      name: "Phase Current L1"
      type: sensor
      unit_of_measurement: "A"
      device_class: current
      state_class: measurement
      accuracy_decimals: 2

Component Features & Technical Details

  • User-Defined OBIS Sensors: The core feature. You can map any OBIS code from your meter to a sensor in Home Assistant, with full control over its name, unit, icon, and other properties.

  • Broad Protocol Support: The component’s parser is modified for lenient header validation, ensuring it works with standard DSMR, Dutch smart meters, and non-standard Finnish (SESKO) meters.

  • Encrypted Telegram Support (Experimental): The component includes the necessary architecture for decrypting AES-128-GCM encrypted P1 streams, such as those used in Luxembourg. To enable it, provide the 32-character decryption key.

    dsmr_custom:
      decryption_key: "00112233445566778899AABBCCDDEEFF"
    

    Note: This feature is considered experimental and has not been tested on a live encrypted meter. Community feedback and testing are highly encouraged.

  • Buffer and Request Management:

    • Large Buffer: The rx_buffer_size is configurable to handle large telegrams from modern meters.
    • Request Pin: For meters that require a data request signal, you can define a request_pin to actively poll for data.

Call for Community Testing

While this component has been validated on Finnish hardware, community assistance is needed to confirm its functionality in other environments. Help is especially welcome for:

  • Encryption Functionality: Testing with meters from Luxembourg or other regions that use AES-128-GCM encryption.
  • M-Bus Devices: Verifying OBIS codes and parsing for gas, water, or heat meters.
  • Meter Variability: Testing with a wider range of smart meters from different manufacturers.

Please share your findings, OBIS mappings, or sanitized telegram samples via GitHub Issues.


Acknowledgments

This project would not be possible without the foundational work on DSMR parsing and integration from the ESPHome community, including contributions and inspiration from @glmnet, @matthijskooijman, @imars, and @zuidwijk.

A special thank you to the community members in the original HA thread for their testing and feedback.


GitHub Repository: nikopaulanne/dsmr-custom
Discussion: All feedback is welcome – I’m particularly interested in hearing from users with encrypted P1 streams or non-Finnish meters!

2 Likes

Example Configuration (Finnish Meter)

Here is a comprehensive example based on my own working configuration. It includes a large number of OBIS codes commonly found in Finnish Aidon meters. You can use this as a starting point and remove the sensors you don’t need.

The ESP device: Slimmelezer (https://www.zuidwijk.com/product/slimmelezer-plus/)
P1 Telegram Header: ADN9 7534

# Basic ESPHome setup
esphome:
  name: dsmr-reader

esp8266:
  board: d1_mini

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

api:
  encryption:
    key: !secret esphome_api_encryption_key

ota:
logger:

# UART configuration for the P1 port
uart:
  id: uart_bus
  baud_rate: 115200
  rx_pin: D7
  rx_buffer_size: 1700 

# --- External component from GitHub ---
external_components:
  - source:
      type: git
      url: https://github.com/nikopaulanne/dsmr-custom
      ref: v1.0.2
    components: [ dsmr_custom ]

# --- DSMR Custom Hub Configuration ---
dsmr_custom: 
  id: dsmr_hub
  uart_id: uart_bus
  max_telegram_length: 1700 
  crc_check: true
  receive_timeout: "600ms"

  # This is the main feature: define your own sensors!
  custom_obis_sensors:
    # --- Energy readings (kWh) ---
    - code: "1-0:1.8.0"
      name: "Active energy import"
      type: sensor
      unit_of_measurement: "kWh"
      state_class: total_increasing
      device_class: energy
      accuracy_decimals: 3
    - code: "1-0:2.8.0"
      name: "Active energy export"
      type: sensor
      unit_of_measurement: "kWh"
      state_class: total_increasing
      device_class: energy
      accuracy_decimals: 3
    - code: "1-0:3.8.0"
      name: "Reactive energy import"
      type: sensor
      unit_of_measurement: "kvarh"
      state_class: total_increasing
      accuracy_decimals: 3
    - code: "1-0:4.8.0"
      name: "Reactive energy export"
      type: sensor
      unit_of_measurement: "kvarh"
      state_class: total_increasing
      accuracy_decimals: 3

    # --- Power readings (kW / kvar) ---
    - code: "1-0:1.7.0"
      name: "Active power import"
      type: sensor
      unit_of_measurement: "kW"
      device_class: power
      state_class: measurement
      accuracy_decimals: 3
    - code: "1-0:2.7.0"
      name: "Active power export"
      type: sensor
      unit_of_measurement: "kW"
      device_class: power
      state_class: measurement
      accuracy_decimals: 3
    - code: "1-0:3.7.0"
      name: "Reactive power import"
      type: sensor
      unit_of_measurement: "kvar"
      state_class: measurement
      accuracy_decimals: 2
    - code: "1-0:4.7.0"
      name: "Reactive power export"
      type: sensor
      unit_of_measurement: "kvar"
      state_class: measurement
      accuracy_decimals: 2
      
    # --- Per-phase Power readings (kW / kvar) ---
    - code: "1-0:21.7.0"
      name: "Active power L1"
      type: sensor
      unit_of_measurement: "kW"
      device_class: power
      accuracy_decimals: 3
      state_class: measurement
    - code: "1-0:41.7.0"
      name: "Active power L2"
      type: sensor
      unit_of_measurement: "kW"
      device_class: power
      accuracy_decimals: 3
      state_class: measurement
    - code: "1-0:61.7.0"
      name: "Active power L3"
      type: sensor
      unit_of_measurement: "kW"
      device_class: power
      accuracy_decimals: 3
      state_class: measurement
      
    # --- Phase Voltages and Currents ---
    - code: "1-0:32.7.0"
      name: "Phase voltage L1"
      type: sensor
      unit_of_measurement: "V"
      device_class: voltage
      accuracy_decimals: 1
      state_class: measurement
    - code: "1-0:52.7.0"
      name: "Phase voltage L2"
      type: sensor
      unit_of_measurement: "V"
      device_class: voltage
      accuracy_decimals: 1
      state_class: measurement
    - code: "1-0:72.7.0"
      name: "Phase voltage L3"
      type: sensor
      unit_of_measurement: "V"
      device_class: voltage
      accuracy_decimals: 1
      state_class: measurement
    - code: "1-0:31.7.0"
      name: "Phase current L1"
      type: sensor
      unit_of_measurement: "A"
      device_class: current
      accuracy_decimals: 2
      state_class: measurement
    - code: "1-0:51.7.0"
      name: "Phase current L2"
      type: sensor
      unit_of_measurement: "A"
      device_class: current
      accuracy_decimals: 2
      state_class: measurement
    - code: "1-0:71.7.0"
      name: "Phase current L3"
      type: sensor
      unit_of_measurement: "A"
      device_class: current
      accuracy_decimals: 2
      state_class: measurement

    # --- Other info ---
    - code: "0-0:96.7.21"
      name: "Electricity failures"
      type: sensor
      icon: mdi:alert
      accuracy_decimals: 0
    - code: "0-0:96.7.19"
      name: "Long electricity failures"
      type: sensor
      icon: mdi:alert-outline
      accuracy_decimals: 0
    - code: "0-0:1.0.0"
      name: "Date and time stamp"
      type: text_sensor
      icon: mdi:clock-time-eight

# --- Recommended Text Sensors for Debugging ---
text_sensor:
  - platform: dsmr_custom
    dsmr_custom_hub_id: dsmr_hub
    
    # This sensor is highly recommended to identify your meter
    identification:
      name: "P1 Telegram Header"
      icon: mdi:barcode-scan
      
    # Use this sensor to see ALL data from your meter to find OBIS codes
    telegram:
      name: "DSMR Full Telegram"
      internal: false # IMPORTANT: Set to false to see this sensor in Home Assistant
      icon: mdi:text-box-search-outline

Please try it out and provide your feedback - happy metering!

Quickfix v1.0.2
Need to rewrite a bit of quickstart as I could not get esp->homeassistant telegram sending to work reliably. Simpler quickstart now just guides one to read manually logs from device.

And there was a little debug-log writing bug which crashed the build if was debugging. Now it should work as intended.

Happy metering!

Very interested, as I’m running into limitations with my Belgian DSMR meter.

However, two issues:
your telegram is missing an id: or name: in your example dumping config.

Second, worse, on ESPhome 2024.2.2, I get:

Compiling .pioenvs/dsmr-meter/src/esphome/components/dsmr_custom/fields.cpp.o
In file included from src/esphome/components/dsmr_custom/dsmr.cpp:36:
src/esphome/components/dsmr_custom/dsmr.h:42:14: fatal error: esphome/components/sensor/sensor.h: No such file or directory
     #include "esphome/components/sensor/sensor.h"
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.

I can try upgrading, do you expect a minimum version ?
Same problem on ESPHome 2025.6.3

@Xoliul, thank you for checking out the component. Just to clarify are you using the encrypted data in your meter?

No encrypted data.

OK, if you do have unencrypted data, let’s start debugging why you do not see data flowing from UART. 1st, did your last working version with original dsmr provided you working sensors in the HASS?

If yes, do you have same UART configuration on both original dsmr and dsmr-custom?

Uart config is like mine, but is your spesific ESP board config, below is my config for my D1 board:

uart:
  id: uart_bus
  baud_rate: 115200
  rx_pin: D7
  rx_buffer_size: 1700 

I don’t think I can even compile to debug, as I get a compilation error on sensor.h.
I’m no expert, but it seems something is wrong in your code that causes this?

@Xoliul, before going too deep into the huge code base of the component and if it is working or not in the general sense, can you please provide a bit more information of your situation as I asked in my previous post?