DSMR Toolkit
A set of Java based libraries and tools that should allow processing Dutch Smart Meter Requirements messages in a way that is as flexible and reusable as possible.
https://github.com/nielsbasjes/dsmr-tools
Category: Energy Systems
Sub Category: Building Energy Monitoring
Keywords
dsmr dsmr-parser iot nifi nifi-processors raspberry-pi slimme-meters slimmemeter smartmeter
Keywords from Contributors
profile feature-toggle translations charts diagram build-tools geocoder route page data-structures
Last synced: about 15 hours ago
JSON representation
Repository metadata
A java simulator/parser/toolkit for the Dutch Smart Meter Requirements (DSMR)
- Host: GitHub
- URL: https://github.com/nielsbasjes/dsmr-tools
- Owner: nielsbasjes
- License: apache-2.0
- Created: 2019-03-23T09:12:28.000Z (about 6 years ago)
- Default Branch: main
- Last Pushed: 2025-04-24T19:39:02.000Z (4 days ago)
- Last Synced: 2025-04-26T20:33:47.155Z (1 day ago)
- Topics: dsmr, dsmr-parser, iot, nifi, nifi-processors, raspberry-pi, slimme-meters, slimmemeter, smartmeter
- Language: Java
- Homepage: https://dsmr.basjes.nl
- Size: 2.4 MB
- Stars: 18
- Watchers: 4
- Forks: 4
- Open Issues: 3
- Releases: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE
README.md
DSMR Toolkit
DSMR are the Dutch Smart Meter Requirements; part of these requirements are the messages sent out via the P1 port that can be captured and processed on a computer.
Many tools already exist to do this but so far I have not found one that allows me to easily select the system the messages are to be sent to.
This is a set of Java based libraries and tools that should allow processing DSMR messages in a way that is as flexible and reusable as possible.
Parts in this toolkit:
- DSMR-Simulator
- A local application that creates a local "named pipe" which outputs data in the DSMR format. The data itself is totally fake (you get nice sine wave patterns) and is intended for tesing a pipeline on your development system.
- Stream record splitter
- A library that can read an endless UTF8 string from a file/character device and output substrings that are cut by means of a regex that describes what the end of a record looks like.
- DSMR-Parser
- A library that is able to parse a string that is in the DSMR telegram format.
- Apache Nifi UDFs
- For the both the "Stream record splitter" and the "DSMR-Parser" a Nifi Processor has been created to allow using them inside Apache Nifi.
- DSMR to InfluxDb
- MiNifi is great in terms of flexibility and bad in terms of startup time on a Raspberry Pi. So in addition I created a very simple Java application that ONLY does the DSMR to InfluxDb flow in a hard coded way (starts in 5 seconds instead of 3 minutes).
- DSMR to GraphQL service
- A service that exposes the DSMR data directly using GraphQL. This includes simply getting the latest records (it retains a bunch of them in memory ... so don't restart it) and it allows you to do a GraphQL subscription to receive the data a fraction of a second after the electicity meter has provided the data.
Project status
I am using this software at home to read my own powermeter. So it works in my setup.
I'm currently in the process of giving the software a thorough review and I expect to make some breaking changes while still in the 0.x version range.
Important system config settings
The USB serial MUST be set to the right speed (115200 in my case) and set to 'raw' or the crc checksum will NEVER match.
stty -F /dev/ttyUSB0 115200 raw
Prebuilt binaries
Several of the components have been published to maven central and can now be easily used on other applications.
Java library
<dependency>
<groupId>nl.basjes.iot</groupId>
<artifactId>stream-record-splitter</artifactId>
<version>0.6</version>
</dependency>
<dependency>
<groupId>nl.basjes.dsmr</groupId>
<artifactId>dsmr-parser</artifactId>
<version>0.6</version>
</dependency>
Apache (Mi)Nifi processors
The corresponding Nifi NAR files (built against Nifi 1.15.0 which should be compatible with MiNiFi 1.15.0) can be downloaded
from Maven central as well.
https://repo1.maven.org/maven2/nl/basjes/iot/nifi-sensor-stream-cutter/0.6/nifi-sensor-stream-cutter-0.6.nar
<dependency>
<groupId>nl.basjes.iot</groupId>
<artifactId>nifi-sensor-stream-cutter</artifactId>
<type>nar</type>
<version>0.6</version>
</dependency>
and
https://repo1.maven.org/maven2/nl/basjes/dsmr/nifi-dsmr-parser/0.6/nifi-dsmr-parser-0.6.nar
<dependency>
<groupId>nl.basjes.dsmr</groupId>
<artifactId>nifi-dsmr-parser</artifactId>
<type>nar</type>
<version>0.6</version>
</dependency>
A basic (Mi)Nifi Flow
After building and installing the processors in this project in a (local) Apache Nifi installation you can build this very simple flow which simply read and parses the data from the P1 port of the smart meter and stores everything in InfluxDb.
Using Nifi I have created a template of this (DSMR-to-InfluxDb.xml) as a testing reference:
The steps in there:
Stream splitter: Read the records from the stream
- Read from /dev/ttyUSB0
- Split stream in records using this 'DSMR CRC pattern': \r\n![0-9A-F]{4}\r\n
DSMR Parser: Parse the records
- No config needed, this just parses the input content and creates a lot of extra attributes for the flowfile.
ReplaceText: Convert into the InfluxDB "line protocol"
-
Evaluation Mode: Entire text
-
Replacement strategy: Always replace
-
Replacement value:
electricity,equipmentId=${dsmr.equipmentId},p1Version=${dsmr.p1Version} electricityReceivedLowTariff=${dsmr.electricityReceivedLowTariff},electricityReceivedNormalTariff=${dsmr.electricityReceivedNormalTariff},electricityReturnedLowTariff=${dsmr.electricityReturnedLowTariff},electricityReturnedNormalTariff=${dsmr.electricityReturnedNormalTariff},electricityTariffIndicator=${dsmr.electricityTariffIndicator}i,electricityPowerReceived=${dsmr.electricityPowerReceived},electricityPowerReturned=${dsmr.electricityPowerReturned},powerFailures=${dsmr.powerFailures}i,longPowerFailures=${dsmr.longPowerFailures}i,voltageSagsPhaseL1=${dsmr.voltageSagsPhaseL1}i,voltageSagsPhaseL2=${dsmr.voltageSagsPhaseL2}i,voltageSagsPhaseL3=${dsmr.voltageSagsPhaseL3}i,voltageSwellsPhaseL1=${dsmr.voltageSwellsPhaseL1}i,voltageSwellsPhaseL2=${dsmr.voltageSwellsPhaseL2}i,voltageSwellsPhaseL3=${dsmr.voltageSwellsPhaseL3}i,voltageL1=${dsmr.voltageL1},voltageL2=${dsmr.voltageL2},voltageL3=${dsmr.voltageL3},currentL1=${dsmr.currentL1},currentL2=${dsmr.currentL2},currentL3=${dsmr.currentL3},powerReceivedL1=${dsmr.powerReceivedL1},powerReceivedL2=${dsmr.powerReceivedL2},powerReceivedL3=${dsmr.powerReceivedL3},powerReturnedL1=${dsmr.powerReturnedL1},powerReturnedL2=${dsmr.powerReturnedL2},powerReturnedL3=${dsmr.powerReturnedL3} ${dsmr.timestamp.epochSecond}000000000
Warning about the timestamp in this replacement value!
The last field is the timestamp.
Here the time (in seconds) from the data of the energy meter is used (i.e. ${dsmr.timestamp.epochSecond}000000000 ).
The meter I have has a clock that is off by about 7 seconds, this causes nasty effects in Grafana when I try to add/substract these values form other data streams I have (like from my solar inverter).
If you have a similar situation then I recommend using this timestamp instead that uses the clock of the local system (which I have synchronized using NTP) and is rounded to the whole second: ${now():toNumber():divide(1000)}000000000
PutInfluxDB: Store into InfluxDB
- Send the data to your local InfluxDB instance.
When I then hook Grafana to this Influx Db database and make a graph I get something like this:
Running on a Raspberry Pi
I have a Raspberry Pi Model B Plus Rev 1.2 on which I have this running using Minifi 1.15.0.
In order to make it work I had to jump through some hoops.
Dependencies
Now MiNiFi is REALLY picky about versions of nar files.
Because MiNiFi 1.15.0 is build against NiFi 1.15.0 you need to download that exact version because we need some additional libraries from it.
- Copy these from nifi to the minifi lib folder:
- nifi-influxdb-nar-1.15.0.nar
- nifi-standard-services-api-nar-1.15.0.nar
- Copy the two nars from this project (also built against Nifi 1.15.0!!) to the minifi lib folder:
- nifi-sensor-stream-cutter-nar-0.6.nar
- nifi-dsmr-parser-nar-0.6.nar
There is no "disk"
The problem with Raspberry Pi systems is that they have an SD card as 'disk'.
These suffer from wearing out quite fast.
Also (Mi)NiFi writes a lot of stuff that I do not care about (like Provenance data).
To avoid disk related problems as much as possible I reduced the writing to only what is needed and created a RamDisk to run MiNiFi on.
No Provenance for MiNiFi
So after converting the flow into the MiNiFi yaml format I changed this
Provenance Repository:
provenance rollover time: 1 min
implementation: org.apache.nifi.provenance.MiNiFiPersistentProvenanceRepository
into
Provenance Repository:
provenance rollover time: 1 min
implementation: org.apache.nifi.provenance.NoOpProvenanceRepository
To avoid writing the Provenance data (which I don't need).
Create ramdisk
First create the actual directory/mount point:
mkdir /minifi
Then in /etc/fstab I added this line to define a new 10MiB Ramdisk:
tmpfs /minifi tmpfs nodev,nosuid,size=10M 0 0
and run
mount -a
Install/Run Minifi using the ramdisk
Now we put our MiNiFi setup somewhere on the SD card and we add this script as run.sh
#/bin/bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
RUNDIR=/minifi
if [ ! -e ${RUNDIR}/bin/minifi.sh ];
then
mkdir ${RUNDIR}/bin
cp ${DIR}/bin/*.sh ${RUNDIR}/bin
chmod 755 ${RUNDIR}/bin/*.sh
cp -rs ${DIR}/lib ${RUNDIR}
cp -rs ${DIR}/conf ${RUNDIR}
mkdir ${DIR}/work
ln -s ${DIR}/work ${RUNDIR}
fi
${RUNDIR}/bin/minifi.sh start
This script will effectively make MiNiFi read the 'immutable' stuff from the SD card and read/write the fast changing stuff to the ramdisk.
External references
LICENSE: Apache 2.0
Copyright (C) 2019-2024 Niels Basjes
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Owner metadata
- Name: Niels Basjes
- Login: nielsbasjes
- Email:
- Kind: user
- Description: Principal IT Architect/Inventor at @bolcom . Committer and PMC for @apache Avro. Contributor for many of the @apache "BigData" projects.
- Website: https://niels.basjes.nl
- Location: Amstelveen, NL
- Twitter: nielsbasjes
- Company: @bolcom
- Icon url: https://avatars.githubusercontent.com/u/240096?u=e72745033072825b244f3eebef9dee5c0df95ce8&v=4
- Repositories: 107
- Last ynced at: 2025-04-24T19:10:08.836Z
- Profile URL: https://github.com/nielsbasjes
GitHub Events
Total
- Watch event: 3
- Delete event: 66
- Issue comment event: 2
- Push event: 101
- Pull request event: 149
- Create event: 70
Last Year
- Watch event: 3
- Delete event: 66
- Issue comment event: 2
- Push event: 101
- Pull request event: 149
- Create event: 70
Committers metadata
Last synced: 8 days ago
Total Commits: 658
Total Committers: 4
Avg Commits per committer: 164.5
Development Distribution Score (DDS): 0.456
Commits in past year: 152
Committers in past year: 2
Avg Commits per committer in past year: 76.0
Development Distribution Score (DDS) in past year: 0.066
Name | Commits | |
---|---|---|
renovate[bot] | 2****] | 358 |
Niels Basjes | n****s@b****l | 202 |
Renovate Bot | b****t@r****m | 96 |
WoutProvost | w****t@e****m | 2 |
Committer domains:
- enovates.com: 1
- renovateapp.com: 1
- basjes.nl: 1
Issue and Pull Request metadata
Last synced: 1 day ago
Total issues: 5
Total pull requests: 384
Average time to close issues: over 1 year
Average time to close pull requests: about 15 hours
Total issue authors: 2
Total pull request authors: 1
Average comments per issue: 0.0
Average comments per pull request: 0.33
Merged pull request: 382
Bot issues: 3
Bot pull requests: 384
Past year issues: 0
Past year pull requests: 159
Past year average time to close issues: N/A
Past year average time to close pull requests: about 20 hours
Past year issue authors: 0
Past year pull request authors: 1
Past year average comments per issue: 0
Past year average comments per pull request: 0.01
Past year merged pull request: 158
Past year bot issues: 0
Past year bot pull requests: 159
Top Issue Authors
- renovate[bot] (3)
- nielsbasjes (2)
Top Pull Request Authors
- renovate[bot] (384)
Top Issue Labels
Top Pull Request Labels
Dependencies
- com.esotericsoftware:kryo ${kryo.version} provided
- org.projectlombok:lombok 1.18.24 provided
- nl.basjes.iot:stream-record-splitter 0.7-SNAPSHOT
- org.antlr:antlr4-runtime ${antlr.version}
- nl.basjes.dsmr:dsmr-parser 0.7-SNAPSHOT compile
- args4j:args4j 2.33
- nl.basjes.dsmr:dsmr-parser ${project.version}
- org.influxdb:influxdb-java 2.22
- org.slf4j:slf4j-reload4j ${slf4j.version}
- org.junit:junit-bom 5.8.2 import
- org.slf4j:slf4j-api 1.7.36
- org.slf4j:slf4j-reload4j 1.7.36
- org.junit.jupiter:junit-jupiter-engine test
- org.slf4j:slf4j-reload4j test
- org.apache.commons:commons-text 1.9
- org.slf4j:slf4j-api
- nl.basjes.dsmr:nifi-dsmr-parser-processors 0.7-SNAPSHOT
- nl.basjes.dsmr:dsmr-parser ${project.version}
- org.apache.nifi:nifi-api ${nifi.version}
- org.apache.nifi:nifi-utils ${nifi.version}
- org.apache.nifi:nifi-mock ${nifi.version} test
- org.junit.vintage:junit-vintage-engine test
- org.apache.nifi:nifi-api ${nifi.version} provided
- org.apache.nifi:nifi-framework-api ${nifi.version} provided
- org.apache.nifi:nifi-nar-utils ${nifi.version} provided
- org.apache.nifi:nifi-properties ${nifi.version} provided
- org.apache.nifi:nifi-runtime ${nifi.version} provided
- nl.basjes.iot:nifi-sensor-stream-cutter-processors 0.7-SNAPSHOT
- nl.basjes.iot:stream-record-splitter ${project.version}
- org.apache.nifi:nifi-api ${nifi.version}
- org.apache.nifi:nifi-utils ${nifi.version}
- org.apache.nifi:nifi-mock ${nifi.version} test
- org.junit.vintage:junit-vintage-engine test
- org.apache.nifi:nifi-api ${nifi.version} provided
- org.apache.nifi:nifi-framework-api ${nifi.version} provided
- org.apache.nifi:nifi-nar-utils ${nifi.version} provided
- org.apache.nifi:nifi-properties ${nifi.version} provided
- org.apache.nifi:nifi-runtime ${nifi.version} provided
- actions/cache v3 composite
- actions/checkout v3 composite
- actions/setup-java v3 composite
- codecov/codecov-action v3.1.1 composite
Score: 4.430816798843313