Stromzähler (SmartMeter) mit Raspberry Pi auslesen

Das Auslesen meines Stromzählers EasyMeter Q3B war leider eine etwas zähe Geschichte. Eigentlich sollte dieses SmartMeter über die D0-Schnittstelle alle relevanten Daten bereitstellen. Als ersten Versuch habe ich nach Anleitung von Sven Jordan einen Optokoppler nachgebaut. Leider hat das so nicht funktioniert. Ich habe zwar über die serielle Schnittstelle Daten einlesen können, allerdings ohne erkennbare Struktur, schon gar nicht wie in dieser Anleitung dargestellt. Da ich nun nicht wusste, ob es an meinem selbst gebastelten Optokoppler lag, habe ich mir den von EasyMeter empfohlenen optischen Tastkopf OD400 TTL (D0) der Firma Propertools für ca. 50 € gekauft. Leider ist dieser nicht mehr verfügbar. Es gibt aber von EasyMeter neue Empfehlungen. Diese Investition lohnt sich aus meiner Sicht schon deshalb, weil diese OptoKoppler sich mit dem Magneten ganz einfach am EasyMeter in Position bringen lassen:

SmartMeter


Mein zweiter Versuch mit dem OD400 TTL war leider auch nicht auf Anhieb erfolgreich. Ich habe die serielle Schnittstelle über ein Pyton-Script ausgelesen und dabei die Schnittstellen-Parameter wie oben angegeben verwendet (9600/7/even/1). Damit konnte ich jetzt immerhin ASCII-Daten einlesen, die zumindest hin und wieder sinnvolle Informationen zu enthalten schienen. Zum einen kam in unregelmäßigen Abständen ein ESY, an einer Stelle sogar ESY Q3B, und die Zählernummer wurde als Klartext übertragen. Die restlichen Zeichen waren mir aber erst einmal ein Rätsel.

Laut Betriebanleitung des Q3B wird für die Übertragung über die optischen Datenschnittstelle das SML-Protokoll (Smart Message Language) verwendet wird.


SML-Botschaften

Als ich 2016 damit begann, den oben genannten Stromzähler auszulesen, konnte ich keine wirklich gute Dokumentation der SML-Botschaften finden. Daher habe ich die SML-Nachrichen Stück für Stück dekodiert. Das war zwar etwas mühsam, hat aber auch Speß gemacht. Die unten dargestellten Code-Beispiel in Python und C zeigen wie das gehen kann.

Eine SML-Nachricht ist ein Datenstrom in hexadezimaler Darstellung und ist durch Escape-Merkmale 0x1b1b1b1b gekennzeichnet. Der Beginn der SML-Nachricht wird durch ein solches Escape-Markmal gefolgt von einem Beginn-der-Nachricht-Merkmal 0x01010101 definiert. Am Ende einer Nachricht folgt 0x1a auf ein Escape-Merkmal, also 0x1b1b1b1b1a. Zu guter Letzt folgt noch die Prüfsumme.

Laut Dokuentation des Herstellers der EasyMeter ist die Einstellung der seriellen Kommunikation 9600/7/even/1 für die Geräte der xxD und xxS-Reihe. Die SML-Zähler (xxB und xxC) senden mit 9600/8/none/1. Also habe ich für meinen Q3B die serielle Schrittstelle entsprechend konfiguriert.

Die SML-Nachricht enthält verschiedene SML-Botschften. Eine SML-Botschaft liefert in der Regel einen einzigen Wert, zum Beispiel Enerige, Leistung, Strom oder Spannung. Welche Werte in den SML-Botschaften stehen wird durch die OBIS-Kennzahlen definiert. Auch die Einheit und der Multiplikator für den jeweiligen Wert ist in der SML-Botschaft enthalten.

Hier ein Beispiel für eine SML-Botschaft für den Stromzählerstand Bezug, OBIS-Kennzahl 1.8.0:
77 07 01 00 01 08 00 ff 64 00 00 80 01 62 1e 52 fc 59 00 00 00 05 29 4a f8 c9 01

Die SML-Botschaft beginnt mit 77 07 01. Die OBIS-Kennung für 1.8.0 in hexadezimal ist 01 08 00. 62 1e steht für die Einheit Wh. Dann folgt der Multiplikator, 52 fc steht für 1e-4, also 1/10000. Em Ende folgt der Wert für den Zählerstand, 00 00 00 05 29 4a f8 c9 entspricht dezimal 22.167.615.689. Diese Zahl muss dann mit dem Multiplikator multipliziert (bzw. hier durch 10.000 dividiert) werden, dann erhält man den aktuellen Zählerstand, hier also 2.216.761 Wh oder 2.216 kWh.

Weitere Einheiten sind: 62 23 für Volt oder 62 1b für Watt. Beim Multiplikator steht 52 fc für 1e-4, 52 fd für 1e-3, 52 fe für 1e-2, 52 ff für 1e-1, 52 00 für 1e0, 52 01 für 1e1, 52 02 für 1e2, usw.


Python-Script

Den Datenstrom der seriellen Schnittstelle interpretiere ich mit einem Python-Script nach folgendem Programmablauf:

  • Serielle Schnittstelle initialisieren
  • Zeichen in einer Schleife einlesen und zu einer hexadezimalen Zeichenfolge zusammensetzen
  • Sobald Beginn-der-Nachricht-Merkmal 1b1b1b1b01010101 einging, alle vorhergehenden Zeichen abschneiden und auf Ende-der-Nachricht-Merkmal 1b1b1b1b1a warten. Damit ist dann eine Nachricht komplett. Danach kommen allerdings noch drei weitere Byte, die letzten beiden sind die Prüfsumme nach CRC16X25. Diese wird allerdings erst in dem C-Code ausgerechnet (siehe unten), nicht schon in dem Python-Code.
  • Die vollständige erhaltene Nachricht nach OBIS-Kennungen durchsuchen und auswerten.

Im Beispiel meines EasyMeter Q3B kommen über die D0-Schnittstelle fogende Daten nach der jeweiligen Kennzahl:

  • Herstellerkennung (Kennzahl 0x81 81 c7 82 03 ff): 0x45 53 59 = ESY
  • Eigentumsnummer (0x01 00 00 00 00 ff): 0x33 31 33 34 31 32 36 31 33 = 313 412 613 (steht auf dem Zähler, aber nicht auf meinem!)
  • Summenregister Bezug (0x01 00 01 08 00 ff): 0x00 00 00 00 67 54 6f 34 = 1733586740 * 10^-4 Wh = 173358,6740 Wh = 173,3586740 kWh
  • Momentanleistung über alle Phasen (0x01 00 01 07 00 ff): 0x00 00 28 2e = 10286 * 10^-2 W = 102,86 W

Zum Auslesen der D0-Schnittstelle mit einem Raspberry Pi A+ verwende ich folgendes Python-Skript SmartMeter.py, das beim Booten des Raspberry Pi automatisch gestartet wird (sudo ./SmartMeter.py &):

Das Python-Skript liest jeden Datensatz des SmartMeters aus. Im Falle des EasyMeter Q3B bekomme ich damit alle zwei Sekunden die aktuellen Werte für Bezug (Wh) und Momentanleistung (W). Zusammen mit dem aktuellen Zeitstempel werden diese beiden aktuellen Werte einerseits in eine XML-Datei /var/www/html/SmartMeter.xml geschrieben (um via HTTP-Anfrage von einem beliebigen Computer im Netzwerk ausgelesen werden zu können). Das sieht dann zum Beispiel so aus:

<SmartMeter>
 <data name="timestamp" value="2018-03-28 22:20:25" valueunit="YYYY-MM-DD hh:mm:ss" />
 <data name="energy" value="7382589.3484" valueunit="Wh" />
 <data name="power" value="338.52" valueunit="W" />
</SmartMeter>


Alle 15 Minuten erfolgt die Auswertung der Gesamt-Leistung. Über jeweils 15 Minuten wird der minimale und maximale Wert, der Mittelwert und die Standardabweichung berechnet und in die Datei /var/www/html/SmartMeter15.xml geschrieben.

Datenübertragung und Visualisierung

Dieses Python-Script ermittelt über den Zeitraum der letzten 15 Minuten den minimalen, mittleren und maximalen Leistungswert sowie die Standardabweichung. Zusammen mit dem aktuellen Zeitstempel werden diese Werte in die XML-Datei /var/www/html/SmartMeter15.xml geschrieben. Mein zentraler Raspberry Pi fragt diese Werte vom SmartMeter regelmäßig ab und trägt die Werte in eine MySQL-Datenbank ein.

Mit diesen Daten lassen sich dann schöne Diagramme erstellen, zu. Beispiel mit amCharts. Hier als Beispiel der Leistungsverlauf von August bis Dezember:

Code für einen ESP8266

Nachdem ein Raspberry Pi seit 7.03.2016 treu seinen Dienst geleistet hatte, habe ich im Januar 2022 es nun endlich auch mal geschafft, den Python-Code nach C zu übertragen. Ein ESP8266 sollte den Job des Raspberry Pi übernehmen, so der Plan. Seit 14.01.2022 liest nun ein ESP8266 (aktuell noch ein ESP8266 NodeMCU) die Daten vom Stromzähler über die optische D0-Schnittetelle ein. Hier der Code ESP8266_SML_public.ino für einen ESP8266.

 

Also Beispiel habe ich noch eine "unbekannte" SML-Botschaft mit aufgenommen um zu zeigen, wie man das Reverse-Engineering betreiben kann. Einfach mal ein paar komplette SML-Botschaften mitschneiden, Prüfsumme vergleichen (um zu sehen, ob die SML-Botschaft auch richtig angekommen ist) und dann mal schauen, welche Bytes sich da so von einer zur anderen SML-Botschaft verändern. Auf diesem etwas steinigen Weg kann man dann die einzelnen Werte in einer SML-Botschaft erfassen. Viel Spaß dabei!

Das wichtigste zum Schluss

Das SML-Protokoll ist offensichtlich ein gängiger Standard. Ich hatte bereits zwei Stromzähler vom selben Hersteller verbaut. Die einzelnen Werte in den SML-Botschaften der Stromzähler waren unterschiedlich. Beim ersten kam der Verbrauch in Wh, beim zweiten nur noch in kWh. Beim ersten war die Leistung in Watt mit dabei, beim zweiten dann leider nicht mehr. Manche SmartMeter haben auch zwei D0-Schnittstellen, eine davon ist oft mit einem Siegel versehen. Was man so lesen kann sind die interessanten Daten wie zum Beispiel Leistung der drei Phasen, Spannung der drei Phasen und Bezug in hoher Auflösung wohl oft nur durch die D0-Schnittstellen unter dem Siegel zugänglich. Ich kann das leider bei mir also nicht überprüfen, da mein Zähler eben nur eine zugängliche D0-Schnittstelle hat. Am Ende muss wohl jeder schauen, was in der SML-Botschaft eines jeden Zählers für Werte übertragen werden.