Zu dem Zweck habe ich mir eine Hardware gebastelt die die Daten auslesen kann. Dazu später mehr, in einem anderen Beitrag. Mein Zähler überträgt etwa alle zwei Sekunden einen Datensatz. Automatisch, ohne dass ich ihn darum bitten müsste. Wenn ich den auslese erhalte ich einen formschönen Haufen Hex-Code, ähnlich diesem:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
1B 1B 1B 1B 01 01 01 01 76 05 01 D3 D7 BA 62 00 62 00 72 63 01 01 76 01 01 05 00 9B F2 94 0B xx xx xx xx xx xx xx xx xx xx 01 01 63 B3 78 00 76 05 01 D3 D7 BB 62 00 62 00 72 63 07 01 77 01 0B xx xx xx xx xx xx xx xx xx xx 07 01 00 62 0A FF FF 72 62 01 65 01 8A 4D 15 77 77 07 81 81 C7 82 03 FF 01 01 01 01 04 49 53 4B 01 77 07 01 00 00 00 09 FF 01 01 01 01 0B xx xx xx xx xx xx xx xx xx xx 01 77 07 01 00 01 08 00 FF 65 00 00 01 82 01 62 1E 52 FF 59 xx xx xx xx xx xx xx xx 01 77 07 01 00 01 08 01 FF 01 01 62 1E 52 FF 59 xx xx xx xx xx xx xx xx 01 77 07 01 00 01 08 02 FF 01 01 62 1E 52 FF 59 xx xx xx xx xx xx xx xx 01 77 07 01 00 10 07 00 FF 01 01 62 1B 52 00 55 xx xx xx xx 01 77 07 81 81 C7 82 05 FF 01 01 01 01 83 xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx 01 01 01 63 C6 12 00 76 05 01 D3 D7 BC 62 00 62 00 72 63 02 01 71 01 63 EE 1A 00 1B 1B 1B 1B 1A 00 F3 C7 |
Wie man unschwer erkennt habe ich private Daten anonymisiert. Lacht nicht!
Nachdem ich da längere Zeit mit verbracht habe weiß ich mittlerweile ziemlich genau was da steht. Und damit andere einen besseren Einstieg finden schreibe ich das mal hier auf.
Die Sprache nennt sich Smart Message Language (SML). Es gibt auch Zähler die die Daten in anderen Formaten, oder direkt im ASCII-Format ausgeben. SML ist aber ein Standard, und wird von vielen Herstellern genutzt. Wie das funktioniert kann man zum Beispiel in der Technischen Richtlinie BSI TR-03109-1 beim Bundesamt für Sicherheit in der Informationstechnik nachlesen. Wenn man das tut kann man den Datensatz da oben tatsächlich lesbar machen:
1 2 |
1B 1B 1B 1B -- Start Escape 01 01 01 01 -- Start Übertragung Version 1 |
Die ersten vier Bytes sind einfach eine Markierung für den Anfang der Übertragung, in der zweiten Zeile steht dass wir Version 1 des Protokolls lesen.
Als nächstes müssen wir ein wichtiges Konzept verstehen. Das erste Byte der folgenden Nachricht lautet ’76‘. Man muss das als Nibbles sehen, und bei Hex-Zahlen bedeutet das Ziffer für Ziffer. Das erste Nibble ‚7‘ können wir auf Seite 42 (natürlich ) des oben verlinkten Dokumentes nachschlagen. Da steht eine Tabelle mit einer Zeile ‚X111LLLL‘. Jetzt matcht das binäre ‚X111‘ auf das erste Nibble, also haben wir es hier mit einer Liste zu tun. Das zweite Nibble gibt die Länge an, wir erwarten also eine Liste mit 6 Elementen.
Das erste Byte der folgenden Zeilen ist jeweils nach dem gleichen Schema aufgebaut. In der Regel steht das erste Nibble für den Datentypen, das zweite für die Länge — merkwürdigerweise bei einfachen Datentypen die Länge inclusive dieses Längen-Bytes. Datentyp 0 in Zeile 4 ist laut Seite 42 ein Octet String. Die 5 sagt dass dieser Teil einschliesslich der Längenangabe 5 Bytes umfasst, wir erwarten nach der Länge also noch vier Bytes. Auf Seite 17 des Dokumentes steht dass hier eine Transaktions-ID kommen muss.
Nachdem das Prinzip klar sein sollte werde ich nicht mehr alles haarklein entschlüsseln. Das heisst: ich habe schon. Aber an dieser Stelle überlasse ich das mal dem geneigten Leser.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
76 -- SML Message mit 6 Elementen 05 01 D3 D7 BA -- transactionId 62 00 -- groupNo 62 00 -- abortOnError 72 -- messageBody 63 01 01 -- getOpenResponse 76 -- Liste mit 6 Elementen 01 -- codepage / optional 01 -- client id / optional 05 00 9B F2 94 -- reqFileId 0B xx xx xx xx xx xx xx xx xx xx -- server Id 01 -- refTime / optional 01 -- smlVersion / optional 63 B3 78 -- CRC 00 -- End of SML message |
Man sieht durch die Einrückung ziemlich deutlich dass man sich den Datensatz gut als Liste von Listen vorstellen kann. Außen wird eine Liste mit sechs Elementen angekündigt (76), darin stehen ein Octet String (beginnt mit 0, Zeile 4), zwei Unsigned Integer (6, Zeilen 5 und 6), eine weitere Liste mit zwei Elementen (72, Zeile 7), ein weiterer Unsigned Integer (6, Zeile 16) mit der Prüfsumme und eine Markierung für das Ende der Nachricht (00, Zeile 17). Die Liste mit den zwei Elementen enthält wiederum einen Unsigned Integer (6, Zeile 8 ) und eine Liste mit sechs Elementen (76, Zeile 9). Die meisten dieser sechs Elemente sind Octet Strings die samt des Längen-Bytes eine Länge von 1 haben (01), also leere Strings. Ein String (Zeile 12) enthält eine File-ID, einer (Zeile 13) die Server-ID. Letztere kann man auch direkt auf dem Gerät lesen, die ist aufgedruckt. Beruhigend.
Jetzt wird es ernst: eine weitere Liste mit sechs Elementen (76), die ersten Zeilen entsprechen dem Block oben:
18 19 20 21 22 23 24 25 26 27 28 29 30 |
76 05 01 D3 D7 BB 62 00 62 00 72 63 07 01 -- getListResponse 77 01 -- clientId / optional 0B xx xx xx xx xx xx xx xx xx xx -- serverId 07 01 00 62 0A FF FF -- listName / optional 72 -- actSensorTime / optional 62 01 -- choice: secIndex 65 01 8A 4D 15 -- secIndex (uptime) |
Enthalten ist eine Liste mit zwei Elementen (72, Zeile 22). Der erste Octet String (Zeile 23) gibt den Typ der Nachricht an, es ist ein getListResponse. Der wiederum besteht auf sieben Elementen (77, Zeile 24). Interessant ist hier vielleicht das vierte Element (72, Zeile 28. An dieser Stelle soll die aktuelle Zeit stehen, und die kann auf verschiedene Weise angegeben werden. Erklärt ist das auf Seite 22 des BSI-Dokumentes, dementsprechend haben wir es hier durch die 01 in Zeile 29 mit einem secIndex zu tun. In Zeile 30 folgt dann der Wert. Die Zahl 0x018A4D15 entspricht in etwa der Zeit die das Gerät hier eingebaut ist, das wird also eine Art Betriebsstundenzähler sein.
Die Liste die in Zeile 31 startet ist das fünfte Element der Liste aus Zeile 24. Und hier kommt der wirklich spannende Teil: die Messdaten. Naja, und ein paar Meta-Daten. Erst das Kürzel des Herstellers Iskra (ASCII-Codes in Zeile 38), dann nochmal die bereits bekannte Server ID. Die nächsten drei Elemente enthalten die verbrauchte Energie (die Kilowattstunden), sowohl als Summe als auch aufgesplittet in zwei Tarife — wenn man denn zwei Tarife hat.
Hier kommen wir übrigens zu einem Teil den ich noch nicht verstanden habe: in Zeile 50 wird ein Status angegeben. Wenn mir jemand sagen kann was der bedeutet: immer her damit! 0x0182 ist dezimal 386, darauf kann ich mir keinen Reim machen.
Die Energiewerte muss man übrigens durch 10.000 teilen um auf die kWh zu kommen die am Gerät angezeigt werden.
In Zeile 78 steht die aktuelle Leistung, also wie viel Watt tatsächlich in diesem Moment verbraucht werden. In Zeile 86 folgt ein ‚public key‘. Der steht auch auf dem Gerät, ich nehme an der ist relevant wenn der Zähler wirklich ’nach Hause telefoniert‘. Die SML-Kommunikation funktioniert nämlich nicht nur über die Infrarot-Schnittstelle, sondern bei Bedarf auch über die Stromleitung. So kann der Anbieter Verbrauchswerte ablesen ohne dass dafür jemand zu Besuch kommen muss.
Die beiden Werte in Zeile 88 und 89 sind optional und vervollständigen so die Liste die in Zeile 24 begonnen wurde.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
77 -- valList 77 -- SML_ListEntry 07 81 81 C7 82 03 FF -- objName 01 -- status / optional 01 -- valTime / optional 01 -- unit / optional 01 -- scaler / optional 04 49 53 4B -- value -- Herstelleridentifikation (ISK) 01 -- valueSignature / optional 77 07 01 00 00 00 09 FF 01 01 01 01 0B xx xx xx xx xx xx xx xx xx xx -- Server ID 01 77 07 01 00 01 08 00 FF 65 00 00 01 82 01 62 1E 52 FF 59 xx xx xx xx xx xx xx xx -- Gesamtverbrauch 01 77 07 01 00 01 08 01 FF 01 01 62 1E 52 FF 59 xx xx xx xx xx xx xx xx -- Verbrauch Tarif 1 01 77 07 01 00 01 08 02 FF 01 01 62 1E 52 FF 59 xx xx xx xx xx xx xx xx -- Verbrauch Tarif 2 01 77 07 01 00 10 07 00 FF 01 01 62 1B 52 00 55 xx xx xx xx -- Wirkleistung total 01 77 07 81 81 C7 82 05 FF 01 01 01 01 83 02 xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx -- public key 01 01 -- listSignature / optional 01 -- actGatewayTime / optional |
Oh, noch ein interessanter Punkt zu Zeile 86: das Nibble ‚8‘ ist eigenlich eine 0, also wieder ein Octet String. Da aber das Most Significant Bit gesetzt ist wird daraus eine 8, und das bedeutet dass die Länge der folgenden Daten nicht nur durch das zweite Nibble — die 3 — angegeben wird, sondern zusätzlich durch das folgende Byte. Nützlich, denn mit nur einem Nibble könnte man maximal 15 Bytes ankündigen (nachdem eines für die Länge draufgegangen ist). So kommen wir auf 0x32 == 50 Bytes. Ausreichend also für 48 Bytes Public Key und zwei Bytes Längenangabe.
Es folgen noch eine Prüfsumme und das förmliche Ende der zweiten Nachricht:
90 91 |
63 C6 12 -- crc 00 -- end of message |
Die dritte Nachricht ist einfach nur da um das Ende der Übertragung anzukündigen.
92 93 94 95 96 97 98 99 100 101 102 103 |
76 05 01 D3 D7 BC 62 00 62 00 72 63 02 01 -- getCloseResponse 71 01 63 EE 1A -- crc 00 -- end of message 1B 1B 1B 1B -- end escape 1A 00 F3 C7 |
Zu guter Letzt folgt in Zeile 102 nochmal die vom Anfang bekannte Escape-Sequenz, dann 1A um wirklich die Nachricht abzuschließen und nochmal drei Bytes für eine Prüfsumme.
Jetzt noch was in eigener Sache: viele Blogs schließen ihre Artikel grundsätzlich mit einer Frage an die Leser, um Kommentare zu fischen. Ich finde das penetrant, und mache das in der Regel nicht. Aber nach diesem furztrockenen (!) Artikel erlaube ich mir das ausnahmsweise mal: bitte ein Handzeichen von allen die bis hier durchgehalten haben! Muss kein Lob sein, ein Hallo Welt genügt.
Super hilfreich. Danke. Hab ein paar Abende völlig planlos vor den binären Daten und der Norm vom BSI gestanden und nix kapiert. Jetzt gehts.
Super erklärt, für mich sehr hilfreich!
Danke für die Einführung.
Wir haben seit kurzem genau so einen Zähler wie Du. Und In Hinblick auf eine mögliche PV wollte ich mal für ein paar Wochen den Stomverbrauch protokollieren und in einer Grafik zu sehen, wie sich der Stromverbrauch bei uns so im Tages- und Wochenverlauf darstellt. Anscheinend zu naiv dachte ich, daß es dafür bereits 1001 fertige Lösungen zum mehr oder minder einfachen Nachbau gibt, am einfachsten etwas drauf stöpseln, nach ein paar Tagen an den PC anstöpfseln, Daten einlesen und feritg. Aber weit gefehlt. Anscheinend muß man immer das Rad erneut selbst erfinden und sich umfänglich in eine ungaubliche Menge unterschiedlichster Dinge einarbeiten, das würde ein Riesen-Pojekt und Aufwand werden. In das Volkszähler-Dingens reingeschaut und nur Bahnhof verstanden. dito bei vielen anderen Seiten. Und das alles nur um für kurze Zeit die Daten zu sammeln etc… och nee. Denn das ganze interessiert mich ja überhaupt nicht, ich will nur für einige Zet die Verbrauchswerte. Das ist doch kein Selbstzweck, warum soll ich mir ständig den Verbrauch aschauen. Die Zeit für die Neuerfindung des Rads habe ich nicht, bin ja nur Hobbyist, verdiene meine Brötchen anderweitig und muß die knappe Freizeit für Dinge verwenden, die wirklich wichtig sind und gemacht werden müssen. Schade.
Ja, das ist eher was fuer den Basteltrieb. Einfach nur um den Stromverbrauch zu sehen wird niemand so ein Projekt starten.
Ich kenne mindestens einen
Such mal nach PowerFox. Das könnte was für dich sein.
Wer eine super Lösung, die auch auf Anhieb funktioniert, für sein Smarten Stromzähler sucht, sollte mal nach dem GitHub Projekt: „sml2mqtt“ suchen.
Hm. Habe ich getan, verstehe aber nur Bahnhof. Schade.
Die Doku ist wirklich absolut grottig. Wenn man sich mit Linux und/oder Docker nicht auskennt, hat man da verloren. Zur von sml2mqtt unterstützten Hardware und wie sie angeschlossen werden soll steht auch nichts drin.
jenee, isklaa.
alles im Internet muss umsonst und gleichzeitig perfekt sein.
Hallo Ronald,
wunderbar aufgedröselt!
Vielen Dank
Die Linke zum Gruße
Dear Ronald,
Thank you for your great article. I have used this knowledge to create a battery powered Arduino (Standalone Atmega328P to be precise) that reads out the data with an Infrared sensor. After that, it looks for the start sequence for my data of interest (1B 52 00 55) and converts the „Wirkleistung Total“ to decimal, after which it gets transmitted using a 433 MHz module. Many similar devices are available on the market. I found that commercial options either did not satisfy my needs, or they were too expensive. The „Volkszaehler“ (volkszaehler.org) is a great project, but it relies on an ESP, which uses too much power as I do not have a power socket near my power meter. I can highly recommend this way. Thanks a lot for your article.
Arthur
sounds great, that’s exactly what I want to do. Do you think you would send the c-program to me?
Norbert
Danke! The this world and the „free“ Internet needs people like you!
I have to transfer your knowledge now to a Holley that needs a signal every 2 min to avoid the PIN.
Super Blog. Danke dafür!
Ich habe nur noch ein Verständnisproblem: wo finde ich in dem HEX-Stream die SML Werte z.B. 1.8.0 wieder?
Bei mir wurde ein Holley EHZ541 eingebaut. Da kann man mit eine Taschenlampe (lange/kurze Pulse) auf andere Ausgabewerte umschalten. Das müsste doch auch mit dem Sensor machbar sein. Nur die Ausgabe geht ja über /dev/ttyS0 mit 9600Baud wie soll ich da 2sek / 5sek Dauerlicht erzeugen???
OK viele Fragen, aber der Winter ist ja noch lang zum Basteln.
Danke fuer Dein Lob!
Puh, bei den Fragen kann ich Dir leider nicht weiterhelfen. Ich habe mich damals intensiv mit dem Thema beschaeftigt und was gebaut. Das funktioniert, aber seitdem habe ich das nicht weiter bearbeitet…
Und leider musste ich hier auch die Mailbenachrichtigung fuer neue Kommentare abschalten. So kann ich Dir nur raten Dich an ein passendes Forum zu wenden.
Wenn du die Kommunikation über ein Microcontrollerboard (Arduino Nano / RPi pico etc.) abwickelst, kannst du ganz einfach den Pin, an dem die Sende-LED hängt, von UART auf OUTPUT setzen und die LED explizit ein- und ausschalten.
Ich behalf mir beim Iskra MT631 damit, den optischen Tastkopf abzunehmen, mit der Taschenlampe die PIN einzugeben und „Inf“ (zusatzdaten) einzuschalten, und dann den Tastkopf wieder aufzusetzen.
Vielen Dank für die Einführung in das am Ende doch recht „simple“ Format!
Um evtl. die „Ratebasis“ auf ein etwas größeres Fundament zu setzen – die „Zeile 50“ bei uns sieht so aus:
64 00 02 80
Kann es evtl. etwas mit dem Umschaltzeitpunkt Tarif 1 / 2 zu tun haben?
Die letzten Stellen der Server-ID – zumindest bei unserem Zähler – wenn man den Hersteller-Prefix weglässt – entspricht der Zähler-ID auf dem Typenschild (Hex Dec konvertieren).
Was mir fehlt ist die „Zählernummer“ des Netzbetreibers – die hab ich auch nach mehrfachem Jonglieren der Ausgaben nicht auffinden können…
Unter https://www.sw-bb.de/fileadmin/user_upload/seitenstruktur/wir-ueber-uns/netze-pflichten/veroeffentlichungen/messstellenbetrieb/mt175-bedienungsanleitung.pdf findet sich auf S.34 folgendes zum Statuswort:
Länge: 2 Bytes. Verwendete Bits: 9, 8, 7, 1, 0 (alle anderen Bits sind 0)
Bit 9 gesetzt: OBIS Tarif 2
Bit 8 gesetzt: OBIS Tarif 1
Bit 7 gesetzt: Zähler funktioniert oberhalb der Anlaufschwelle
Bit 7 nicht gesetzt: Zähler im Leerlauf
Bit 1 gesetzt: Telegramm wurde wegen des geänderten Energieregister-Wertes generiert
Bit 1 nicht gesetzt: Telegramm ist synchron mit dem Zeitintervall generiert
Bit 0 gesetzt: Fehler im Betrieb
Bit 0 nicht gesetzt: kein Fehler
Danke, hat beim Einstieg geholfen!