If you're a Romande Energie customer, you likely have a Landis+Gyr E350 or E450 smart meter with an AD-FU module. This meter exposes real-time electricity data, power, energy, voltage, current on all three phases via a wired M-Bus interface on an RJ12 connector. Here's how to get that data into Home Assistant running in Docker on a Debian machine.
Reading Your Romande Energie Smart Meter (Landis+Gyr E450) with Home Assistant
What You Need
- A Landis+Gyr E350/E450 with AD-FU module
- An M-Bus slave USB dongle (FC722-based, available on AliExpress for ~€10)
- An RJ12 cable wired to the dongle's M-Bus screw terminals (pins 3 and 4)
- A Linux machine running Home Assistant in Docker
- A Mosquitto MQTT broker (Docker)
Understanding the Interface
The first thing to know is that the meter itself is the M-Bus master. Your USB dongle acts as the slave. This means you don't need to send any requests: the meter pushes data every 5 seconds automatically.
The protocol is DLMS/COSEM over HDLC, not plain M-Bus telegrams. Standard M-Bus tools like libmbus won't parse this directly. The serial parameters are:
- 2400 baud
- 8 data bits
- Odd parity (not even, as is common with standard M-Bus)
- 1 stop bit
reference: Landis Gyr E450 technical specifications
Hardware Setup
The USB dongle shows up as a Prolific PL2303 USB-to-serial adapter:
[dmesg] usb 1-1.4: Product: USB-Serial Controller
[dmesg] pl2303 converter now attached to ttyUSB1
To make the device path stable across reboots, reference it by USB serial number in Docker rather than using a udev symlink:
$ ls -la /dev/serial/by-id/
usb-Prolific_Technology_Inc._USB-Serial_Controller_BOCJb116L17-if00-port0 -> ../../ttyUSB1
The Right Tool: smartmeter-datacollector
Rather than writing a custom DLMS/HDLC parser (trust me, we tried), use smartmeter-datacollector, an open source tool funded by EKZ and specifically built for the Landis+Gyr E450 over wired M-Bus. It handles multi-frame HDLC reassembly, DLMS/COSEM parsing, and MQTT publishing out of the box.
Install it in a Python virtual environment to test (we'll use a docker container later):
python3 -m venv /opt/mbus-reader
source /opt/mbus-reader/bin/activate
pip install smartmeter-datacollector
Generate and edit the config:
smartmeter-datacollector --saveconfig
Edit datacollector.ini:
[reader0]
type = lge450
port = /dev/ttyMBUS
baudrate = 2400
key =
[sink0]
type = logger
name = DataLogger
[sink1]
type = mqtt
host = 127.0.0.1
port = 1883
tls = False
username =
password =
[logging]
default = INFO
collector = INFO
smartmeter = INFO
sink = INFO
Gotchas: 1) Do not include
client_cert_pathorclient_key_pathlines in the config — even empty, they trigger TLS mode due to a quirk in the config parser. 2)hostwill need to be updated when we'll use this configuration in the container.
Containerising the Setup
Create a smartmeter/ folder alongside your docker-compose.yml:
smartmeter/Dockerfile:
FROM python:3.13-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir smartmeter-datacollector
COPY datacollector.ini /etc/smartmeter/datacollector.ini
CMD ["smartmeter-datacollector", "--config", "/etc/smartmeter/datacollector.ini"]
smartmeter/datacollector.ini: same as above, but set host = mosquitto (Docker internal DNS).
docker-compose.yml additions:
mosquitto:
image: eclipse-mosquitto:2
container_name: mosquitto
volumes:
- ./mosquitto/config:/mosquitto/config
- ./mosquitto/data:/mosquitto/data
restart: unless-stopped
smartmeter:
build: ./smartmeter
container_name: smartmeter
restart: unless-stopped
devices:
- /dev/serial/by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller_BOCJb116L17-if00-port0:/dev/ttyMBUS
depends_on:
- mosquitto
mosquitto/config/mosquitto.conf:
listener 1883
allow_anonymous true
persistence true
persistence_location /mosquitto/data/
Build and start:
docker compose up -d --build smartmeter
MQTT Topics
Once running, smartmeter-datacollector publishes to topics like:
smartmeter/00000000/ACTIVE_POWER_P {"value": 259.0, "timestamp": 1773999751}
smartmeter/00000000/ACTIVE_POWER_N {"value": 0.0, "timestamp": 1773999751}
smartmeter/00000000/ACTIVE_ENERGY_P {"value": 13053210.0, "timestamp": 1773999751}
smartmeter/00000000/ACTIVE_ENERGY_N {"value": 0.0, "timestamp": 1773999751}
smartmeter/00000000/CURRENT_L1 {"value": 0.48, "timestamp": 1773999751}
smartmeter/00000000/CURRENT_L2 {"value": 1.66, "timestamp": 1773999751}
smartmeter/00000000/CURRENT_L3 {"value": 0.13, "timestamp": 1773999751}
smartmeter/00000000/VOLTAGE_L1 {"value": 243.0, "timestamp": 1773999751}
smartmeter/00000000/VOLTAGE_L2 {"value": 242.0, "timestamp": 1773999751}
smartmeter/00000000/VOLTAGE_L3 {"value": 244.0, "timestamp": 1773999751}
The topic prefix uses your meter's serial number (00000000). Check the smartmeter logs to find your serial number, e.g. mine:
smartmeter | INFO:DataLogger:00000000 - 2026-03-21T22:08:40.944365+00:00 - Active Energy -: 0.0 Wh
Home Assistant Configuration
First, add the MQTT integration in HA: Settings → Devices & Services → Add Integration → MQTT. Use mosquitto as the broker address.
Then add the sensors to configuration.yaml:
mqtt:
sensor:
- name: 'Power Import'
state_topic: 'smartmeter/00000000/ACTIVE_POWER_P'
value_template: '{{ value_json.value }}'
unit_of_measurement: 'W'
device_class: power
state_class: measurement
- name: 'Power Export'
state_topic: 'smartmeter/00000000/ACTIVE_POWER_N'
value_template: '{{ value_json.value }}'
unit_of_measurement: 'W'
device_class: power
state_class: measurement
- name: 'Energy Import Total'
state_topic: 'smartmeter/00000000/ACTIVE_ENERGY_P'
value_template: '{{ (value_json.value / 1000) | round(3) }}'
unit_of_measurement: 'kWh'
device_class: energy
state_class: total_increasing
- name: 'Energy Export Total'
state_topic: 'smartmeter/00000000/ACTIVE_ENERGY_N'
value_template: '{{ (value_json.value / 1000) | round(3) }}'
unit_of_measurement: 'kWh'
device_class: energy
state_class: total_increasing
- name: 'Current L1'
state_topic: 'smartmeter/00000000/CURRENT_L1'
value_template: '{{ value_json.value | round(2) }}'
unit_of_measurement: 'A'
device_class: current
state_class: measurement
- name: 'Current L2'
state_topic: 'smartmeter/00000000/CURRENT_L2'
value_template: '{{ value_json.value | round(2) }}'
unit_of_measurement: 'A'
device_class: current
state_class: measurement
- name: 'Current L3'
state_topic: 'smartmeter/00000000/CURRENT_L3'
value_template: '{{ value_json.value | round(2) }}'
unit_of_measurement: 'A'
device_class: current
state_class: measurement
- name: 'Voltage L1'
state_topic: 'smartmeter/00000000/VOLTAGE_L1'
value_template: '{{ value_json.value | round(1) }}'
unit_of_measurement: 'V'
device_class: voltage
state_class: measurement
- name: 'Voltage L2'
state_topic: 'smartmeter/00000000/VOLTAGE_L2'
value_template: '{{ value_json.value | round(1) }}'
unit_of_measurement: 'V'
device_class: voltage
state_class: measurement
- name: 'Voltage L3'
state_topic: 'smartmeter/00000000/VOLTAGE_L3'
value_template: '{{ value_json.value | round(1) }}'
unit_of_measurement: 'V'
device_class: voltage
state_class: measurement
Restart HA and head to Settings → Energy to add your meter as the grid consumption source using the Energy Import Total sensor.
Pitfalls and Lessons Learned
- Empty config values trigger TLS: in smartmeter-datacollector's config, omit
client_cert_pathandclient_key_pathentirely rather than leaving them blank. - Use
/dev/serial/by-id/: more reliable than/dev/ttyUSBxor custom udev symlinks for identifying the dongle in Docker.
Result
You now have real-time electricity data from your Romande Energie meter flowing into Home Assistant every 5 seconds, fully containerised and stable across reboots. The energy dashboard will start accumulating historical data immediately, giving you a clear picture of your consumption and any solar export.