Home-assistant comes with a DSMR reader, but for it to work you need home-assistant installed on the same device that is connected to the DSMR meter. Alternatively, you can use a DSMR reader that send data to MQTT directly. This can be useful if you have home-assistant running on the cloud.
DSMR and LandisGyr+ E350
When you get too crazy about monitoring everything in your house, one of the first things that comes into your mind is probably the energy consumption. In the Netherlands, most of the households have already electricity or gas smart meters that comply with DSMR (Dutch Smart Meter Requirements) standard, which means that in theory you should be able to digitally read the meter.
The smart electricity meter that I have at home is LandisGyr+ E350 (DSMR 5 compatible). It comes with a serial port and an optical pulse port as well.
The easiest way to read your consumption is via the serial port using an USB RS232 cable. You can buy them from AliExpress for about 4$. Search for “ftdi ft232r usb ttl 5v to rj11 dsmr p1” or a combination of these words. The cable should look like in the image below with a ftdi rs232 chip in the USB case.
The cable needs a 1K or 2K ohm pull-up resistor soldered between 5v and RXD like in the image below.
One side of the cable goes into the LandisGyr meter’s RJ11 connector (the green port on the lower side, next to the screws). The other side you connect directly into your RaspberryPi usb. Once connected, you should have /dev/ttyUSB0 available.
Home-assistant DSMR integration
Home-assistant already has a DSMR module, but the reason I am not using it is because my home-assistant runs in the cloud and not on my RaspberryPi. Also, I prefer to keep my sensors data decoupled from home-assistant, so in case HA goes down, my metrics are still logged.
There are two projects I’ve found on github that work on decoding the DSMR telegram.
Python DSMR parser
The project foundhere is a pure Python parser. I’ve found it quite CPU intensive, especially for my RaspberryPi B+. The package can simply be installed with python pip. (see below my mqtt wrapper)
#!/usr/bin/python3from dsmr_parser import telegram_specificationsfrom dsmr_parser.clients import SerialReader, SERIAL_SETTINGS_V5from dsmr_parser.objects import CosemObject, MBusObject, Telegramfrom dsmr_parser.parsers import TelegramParserimport sysimport paho.mqtt.client as mqttimport timefrom lib.mqtt import mqttserial_reader = SerialReader( device='/dev/ttyUSB0', serial_settings=SERIAL_SETTINGS_V5, telegram_specification=telegram_specifications.V5)mqttc = mqtt()for telegram in serial_reader.read_as_object(): #print(telegram) mqttc.publish("home/electricity_usage", { "value": telegram.CURRENT_ELECTRICITY_USAGE.value, "t1": telegram.ELECTRICITY_USED_TARIFF_1.value, "t2": telegram.ELECTRICITY_USED_TARIFF_2.value, "failures": telegram.SHORT_POWER_FAILURE_COUNT.value })
C DSMR parser
The library I’m actually using is from this project. It is written C and it is much more efficient than the Python version. After you compile it, you should have a file called p1-test-p1
that you can just run to decode and print the DSMR telegram.
➜ ~ ./p1-test-p1 /dev/ttyUSB0Possible telegram found at offset 0Possible telegram end at offset 863New-style telegram with length 869Header: XXXXXXXXXXXXXXXXXXP1 version: 5.0Timestamp: 1582142991Equipment ID: XXXXXXXXXXXXXXXXXEnergy in, tariff 1: 868.963000 kWhEnergy in, tariff 2: 837.711000 kWhEnergy out, tariff 1: 0.000000 kWhEnergy out, tariff 2: 0.000000 kWhTariff: 2Power in: 0.127000 kWPower out: 0.000000 kWPower failures: 20Long power failures: 4Power failure events: 4Power failure event end time 1527235604, 580550804 sPower failure event end time 1528360113, 1124469 sPower failure event end time 1543593953, 1030 sPower failure event end time 1543598754, 4778 sVoltage sags L1: 3Voltage sags L2: 2Voltage sags L3: 3Voltage swells L1: 0Voltage swells L2: 0Voltage swells L3: 0Voltage L1: 238.000000 VVoltage L2: 236.000000 VVoltage L3: 237.000000 VCurrent L1: 0.000000 ACurrent L2: 0.000000 ACurrent L3: 0.000000 APower in L1: 0.048000 kWPower in L2: 0.077000 kWPower in L3: 0.000000 kWPower out L1: 0.000000 kWPower out L2: 0.000000 kWPower out L3: 0.000000 kWCRC: 0x626fParsing successful, data CRC 0x626f, telegram CRC 0x626f
To parse the information and send it to mqtt just pipe the output into a python script that looks like this:
#!/usr/bin/python3import sysimport paho.mqtt.client as mqttfrom lib.mqtt import mqttmqttc = mqtt()for line in sys.stdin: if line.startswith('Energy in, tariff 1: '): t1 = float(line.split(' ')[4]) if line.startswith('Energy in, tariff 2: '): t2 = float(line.split(' ')[4]) if line.startswith('Power in: '): instant = float(line.split(' ')[2]) if line.startswith('Power failures: '): failures = int(line.split(' ')[2].strip()) if line.startswith('Parsing successful'): mqttc.publish("home/electricity_usage", { "value": instant, "t1": t1, "t2": t2, "failures": failures })
And the paho-mqtt wrapper I’ve built to handle connections. Modify line 25 if you are not using websockets.
import paho.mqtt.client as mqttcimport configparserimport os, jsonimport simplejsonclass mqtt(object): # set should_loop to False when you subscribe def __init__(self, should_loop = True): self.mqtt_connect(should_loop) def get_conf(self): config = configparser.ConfigParser() # passwords.ini file # [mqtt] # user = YourMqttUserName # pass = YourPass # host = yourhost/ip # port = mqttPort # timeout = timeout-seconds config.read(os.path.dirname(os.path.abspath(__file__)) + '/../passwords.ini') return config def mqtt_connect(self, should_loop): c = self.get_conf() self.mqtt_client = mqttc.Client(transport='websockets') self.mqtt_client.tls_set() self.mqtt_client.username_pw_set(c['mqtt']['user'], c['mqtt']['pass']) if should_loop: self.mqtt_client.connect(c['mqtt']['host'], int(c['mqtt']['port']), int(c['mqtt']['timeout'])) self.mqtt_client.loop_start() def publish(self, topic, value, qos=1, retain=False): if type(value) == dict: value = simplejson.dumps(value) self.mqtt_client.publish(topic, value, qos, retain).wait_for_publish() def on_connect_subscribe(self, client, userdata, flags, rc): self.mqtt_client.subscribe(self._topic) def subscribe(self, topic, callback): c = self.get_conf() self._topic = topic self.mqtt_client.on_message = callback self.mqtt_client.on_connect = self.on_connect_subscribe self.mqtt_client.connect(c['mqtt']['host'], int(c['mqtt']['port']), int(c['mqtt']['timeout'])) self.mqtt_client.loop_forever(timeout=60)
You can now create a bash script to run this continuously. I recommend you to run it with supervisord to automatically restart it if it crashes.
#!/bin/bashcd $(dirname $0)./p1-test-p1 /dev/ttyUSB0 | ./dsmr.py
The supervisord file /etc/supervisor/conf.d/electricity.conf
[program:electricity]user=picommand=/home/pi/dsmr.shdirectory=/home/pistdout_logfile=/var/log/el.logstderr_logfile=/var/log/el.log.errautorestart=true
You can see in this dashboard the CPU usage comparison between the two implementations. The C implementation clearly wins at performance, which is extremely important when dealing with limited resources.
DSMR to InfluxDB, Home-Assistant and Grafana
Once you have all the data sent to MQTT every second, you can now show it in home assistant, save it in InfluxDB and display historical data in Grafana.
MQTT to InfluxDB
To send the data from MQTT to InfluxDb I’m using telegraf with the following configuration:
[[inputs.mqtt_consumer]] servers = ["tcp://localhost:1883"] qos = 2 # connection_timeout = "30s" # max_undelivered_messages = 1000 topics = [ "home/electricity_usage" ] persistent_session = true client_id = "electricity_usage" username = "YOUR-USERNAME" password = "YOUR-PASSWORD" data_format = "json" name_override = "electricity_usage"
Home-Assistant configuration
The configuration for home-assistant is simple. We are just going to create mqtt sensors like this:
- platform: mqtt state_topic: "home/electricity_usage" name: "Current consumption" icon: 'mdi:flash' expire_after: 30 unit_of_measurement: "kW" value_template: "{{ value_json['value'] }}"- platform: mqtt state_topic: "home/electricity_usage" name: "Electricity usage T1" icon: 'mdi:power-plug' expire_after: 30 unit_of_measurement: "kWh" value_template: "{{ value_json['t1'] }}"- platform: mqtt state_topic: "home/electricity_usage" name: "Electricity usage T2" icon: 'mdi:power-plug' expire_after: 30 unit_of_measurement: "kWh" value_template: "{{ value_json['t2'] }}"- platform: mqtt state_topic: "home/electricity_usage" name: "Power failures" icon: 'mdi:flash-off' expire_after: 30 unit_of_measurement: "" value_template: "{{ value_json['failures'] }}"
And the panel looks like this:
However, having the meter counter doesn’t mean much, but having the usage over periods of time is more useful. For this we need to create InfluxDb sensors in home assistant sensors.yaml file.
- platform: influxdb host: INFLUXDB_HOST port: INFLUXDB_PORT ssl: true verify_ssl: true username: !secret influxdb_user password: !secret influxdb_pass queries: - name: electricity_last_30d unit_of_measurement: kWh value_template: '{{ value | round() }}' group_function: ' ' where: 'time > now() - 30d' measurement: '"electricity_usage"' field: 'last("t1")+last("t2")-first("t1")-first("t2")' database: telegraf - name: electricity_last_7d unit_of_measurement: kWh value_template: '{{ value | round() }}' group_function: ' ' where: 'time > now() - 7d' measurement: '"electricity_usage"' field: 'last("t1")+last("t2")-first("t1")-first("t2")' database: telegraf - name: electricity_last_24h unit_of_measurement: kWh value_template: '{{ value | round(1) }}' group_function: ' ' where: 'time > now() - 24h' measurement: '"electricity_usage"' field: 'last("t1")+last("t2")-first("t1")-first("t2")' database: telegraf - name: electricity_last_1h unit_of_measurement: kWh value_template: '{{ value | round(2) }}' group_function: ' ' where: 'time > now() - 1h' measurement: '"electricity_usage"' field: 'last("t1")+last("t2")-first("t1")-first("t2")' database: telegraf
And the new panel:
Power usage in Grafana
For historical data, I am using Grafana backed by InfluxDb. It has a much better interface than home assistant and I can also set up there my own alerts, for example when power usage goes above a limit or if there is no sensor data coming in.
And here is my dashboard. You can find the json here
Related
You may also like:
- Integrating Matter into Home Assistant