NEWS
M-Bus Wasserzähler und Gaszähler auslesen
-
Hallo zusammen,
hier ist eine kleine Beschreibung wie ich meinen Elster Gaszähler und Diehl Wasserzähler auslesen kann das ist noch etwas work-in-progress - aber ich verwende den Beitrag hier auch für mich als Gedächtnisstütze, evtl. hilft's ja auch anderen Usern
An Hardware hab ich mir bei meinem Energieversorger beim Wasserzählertausch einen Zähler mit M-Bus (Wire, nicht Wireless) einbauen lassen (~100EUR Aufpreis). Dabei hab ich mir dann auch noch ein Interface für den Gaszähler anbringen lassen (auch M-Bus) (~30EUR). Um das ganze dann auszulesen wollte ich ursprünglich eine Schaltung nachbauen, die dann mit einem 24V-Netzteil gespeist wird. Das hab ich aber bleiben lassen und mir jetzt endlich einen USB M-Bus-Master bestellt (bei AliExpress, ~25EUR), der direkt am rPi hängt und von diesem gespeist wird. Vorsicht bei den Adaptern - man braucht einen M-Bus Master (ich hab mir zunächst einen USB M-Bus Slave bestellt …)
An Software läuft auf dem rPi die libmbus von rscada ( https://github.com/rscada/libmbus ). Dabei braucht man die beiden Tools mbus-serial-scan um zu sehen ob die Zähler erkannt werden und welche primäre Adresse voreingestellt ist und mbus-serial-request-data zum Auslesen. Bei mir waren beide Zähler mit primärer Adresse 0 voreingestellt. Das gab dann eine Kollision und ich hab mit dem Windows-Tool mbconf von Relay ( http://www.relay.de/de/produkte/software/mbconf.html ) die Adresse auf 1 für den Wasserzähler und 2 für den Gaszähler verändert.
Da ich den rPi auch für ebusd verwende und damit die Daten meiner Heizung via MQTT gepusht bekomme, verwende ich den mosquitto-Server auf dem rPi auch als Vehikel um die Daten des M-Bus an iobroker zu senden. Dazu hab ich folgendes Bash-Skript gebastelt, das mir die Daten der M-Bus-Zähler gibt - abgelegt hab's übrigens genauso wie die libmbus-Binaries in /usr/local/bin :
#!/bin/bash # # Simple script to read M-Bus meter values from a connected # smart meter and send the value to an MQTT broker # # usage: mbus_mqtt.sh PRIMARY_ADDRESS # # The orimary address needs to be given on the command line. # For unconfigured meters this is typically "0" # # Update tour crontab to run this command reagularly, e.g. # */15 * * * * /usr/local/bin/mbus_mqtt.sh 1 to read meter 1 every 15min # # Author: Hoich # # Credits: http://stackoverflow.com/a/24088031 for XML parsing if [ "$#" -ne 1 ] ; then echo "usage: $0 PRIMARY_ADDRESS" >&2 exit 1 fi PRIMARY_ADDRESS=$1 TMPFILE=/tmp/mbus_pa${PRIMARY_ADDRESS}.xml # Read data from M-Bus mbus-serial-request-data -b 2400 /dev/ttyUSB1 $PRIMARY_ADDRESS > ${TMPFILE} # Parse Id=($(grep -oP '(?<=Id>)[^<]+' ${TMPFILE})) Manufacturer=($(grep -oP '(?<=Manufacturer>)[^<]+' ${TMPFILE})) Medium=($(grep -oP '(?<=Medium>)[^<]+' ${TMPFILE})) Values=($(grep -oP '(?<=Value>)[^<]+' ${TMPFILE} )) sleep 2 oIFS=$IFS; IFS=/r>\n' Units=($(grep -oP '(?<=Unit>)[^<]+' ${TMPFILE} )) IFS=$oIFS unset oIFS echo "Primary Address: $PRIMARY_ADDRESS" echo "Id: ${Id}" echo "Manufacturer: ${Manufacturer}" echo "Medium: ${Medium}" # Send to MQTT broker (not needed regularly, actually, but we do it nevertheless) mosquitto_pub -t "mbus/${PRIMARY_ADDRESS}/PrimaryAddress" -m "$PRIMARY_ADDRESS" mosquitto_pub -t "mbus/${PRIMARY_ADDRESS}/Id" -m ${Id} mosquitto_pub -t "mbus/${PRIMARY_ADDRESS}/Manufacturer" -m ${Manufacturer} mosquitto_pub -t "mbus/${PRIMARY_ADDRESS}/Medium" -m ${Medium} # Do the same for all dynamic values - that's the interesting part for visualization etc. for i in ${!Values[@]} do echo "$i" "${Values[$i]}" "${Units[$i]}" mosquitto_pub -t "mbus/${PRIMARY_ADDRESS}/${i}/Value" -m "${Values[$i]}" echo "${Units[$i]}" | mosquitto_pub -t "mbus/${PRIMARY_ADDRESS}/${i}/Unit" -l done # EOF
In meiner crontab auf dem rPi hab ich dann folgende Einträge (Gaszähler alle 15m, Wasserzähler jede Stunde):
0 * * * * /usr/local/bin/mbus_mqtt.sh 1 > /dev/null */15 * * * * /usr/local/bin/mbus_mqtt.sh 2 > /dev/null
Die Einträge sollten in mqtt.1.mbus.1.0.Value und mqtt.1.mbus.2.0.Value jetzt reinpurzeln - wenn man dann noch den History-Adapter verwendet sollte eigentlich Alles da sein um lustige Dinge anzustellen
Viel Spaß beim Nachbau
-
Hallo Hoich,
vielen Dank für Deine Arbeit. Ich habe nun nach vielen Stunden Bastelei (muss mich in Linux erst noch einarbeiten) es geschafft, dass ich meine beiden Wärmemengenzähler über das Skript im Terminal abfragen kann, die Daten werden dann mittels MQTT auf meinen iobroker übertragen. Soweit so geil. Allerdings habe ich das Problem, dass die mbus_pa.xml nicht gefüllt wird, wenn ich mbus_mqtt.sh über einen Cronjob alle paar Minuten starten lasse.
Woran könnte das liegen, bin ratlos?
Grüße
Eric
-
Sorry, woran das liegt kann ich leider so aus der Ferne schwer beantworten. Evtl. das fehlende Argument welche M-Bus ID abgefragt wird?
Aber noch als Hilfestellung wie man mit den Werten umgehen kann hab ich mir noch ein script auf iobroker gebastelt (abgekupftert von einem anderen Thread hier irgendwo - nur leider vergessen, woher) mit dem ich alles plotten kann:
var idGasAbs = 'mqtt.1.mbus.2.0.Value'; var idWasserAbs = 'mqtt.1.mbus.1.0.Value'; var idGasRel = 'Gas'; var idWasserRel = 'Wasser' createState(idGasRel, 0, { // Datenpunkt für Leistung type: 'number', desc: 'Gasverbrauch l / h', unit: 'l/h', def: 0, // min: 0, // max: 30, read: true, write: true }); createState(idWasserRel, 0, { // Datenpunkt für Leistung type: 'number', desc: 'Wasserverbrauch l / h', unit: 'l/h', def: 0, // min: 0, // max: 30, read: true, write: true }); var faktor = 3600000; // Umrechnungsfaktor (bitte anpassen) function updateGas(dp) { var actval = dp.state.val; // aktueller Energiewert var lastval = dp.oldState.val; // letzter Energiewert var acttime = dp.state.lc; // aktuelle Zeit in ms var lasttime = dp.oldState.lc; // Zeitpunkt zu letztem Energiewert in ms var power = faktor * (actval - lastval) / (acttime - lasttime); // Leistung setState(idGasRel, power); } on(idGasAbs, function(dp) { // triggert bei jeder Wertänderung updateGas(dp); }); on(idWasserAbs, function(dp) { // triggert bei jeder Wertänderung var actval = dp.state.val; // aktueller Energiewert var lastval = dp.oldState.val; // letzter Energiewert var acttime = dp.state.lc; // aktuelle Zeit in ms var lasttime = dp.oldState.lc; // Zeitpunkt zu letztem Energiewert in ms var power = 10 * faktor * (actval - lastval) / (acttime - lasttime); // Leistung setState(idWasserRel, power); });
-
Hey All,
seit heute gibts es einen neuen Adapter für MBus. "Unter der Haube" läuft auch die libmbus nur schön verpackt.
freue mich über Tester!