Stromzähler auslesen

Posted on Di 17 Oktober 2023 in Computer & Electronics

In meinem Verteilerkasten hängt ein Stromzähler. Und zwar so ein moderner digitaler. Wobei modern irgendwie relativ ist, denn statt einer anständigen, Schnittstelle, wie USB, UART, RS232, RS485 oder was weiß ich, hat man eine klobige optische Schnittstelle erdacht, die ungefähr so praktisch ist wie ein Loch im Knie. Gefunkt wird hier mit zwei IR-Elementen – eins zum Senden, eins als Empfänger. Darüber wird dann seriell übertragen. Auf dem Photo sieht man die Schnittstelle deutlich – sie sieht aus wie eine Schweinenase:

Natürlich war kein Lesekopf dabei. Aber zum Glück bin ich nicht der Erste, den das aufregt und so gibt es z.B. das Projekt Volkszähler das sich damit befasst, Strom-, Gas und andere Verbrauchszähler in einem zentralen System zu vereinen, das man selber hosten kann – z.B. auf einem Raspberry Pi. An der Software bin ich nicht so interessiert, weil ich das eher in den Homeassistant einbinden will, aber man findet auf deren Seiten auch Schaltpläne und Stücklisten für Leseköpfe. Z.B. diesen hier. So kann man seinen eigenen Lesekopf bauen. Aber ich war faul und habe das Löten diesmal jemand anderem überlassen und einfach einen solchen Lesekopf bestellt. Da mein Homeserver direkt neben dem Sicherungskasten sein Zuhause hat, habe ich die Variante mit USB-Interface genommen.

Damit das auch funktioniert, brauchte ich zunächstmal ein Loch im Verteilerkasten und ein weiteres in der Trockenbauwand, die das Ganze verkleidet. Das war wegen der engen räumlichen Verhältnisse zwar etwas fummelig, aber auch kein Hexenwerk. Die scharfen Kanten des Lochs im Verteilerkasten habe ich dann noch entgratet und mit vielen schmalen Gewebebandstreifen abgedeckt, damit das Kabel keinen Schaden nimmt. Dafür gibt es auch so Gummidurchführungen, aber sowas habe ich nicht da. Vielleicht rüste ich das später nach.

Erster Test

Also nun das eine Endes des Kabels (Mini-USB) in den Lesekopf und das andere in den Server einstecken und dann voller Spannung schauen, ob wir ihn sehen können:

> lsusb
[...]
Bus 001 Device 006: ID 0403:6015 Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)
[...]

Da isser ja – sehr schön!

Als nächstes stellt sich nun die Frage, wie herum der Lesekopf auf den Stromzähler gehört. Erster Versuch – Kabel unten:

Und dann schauen wir mal, ob wir etwas empfangen. Also auf dem Server an dem der Lesekopf hängt:

> cu -l /dev/ttyUSB0
connected.
�bbrevb
       ��

         APA��rbe
                 ��c��vbbrew

                            APA��tw`2APA w`�1APA0193464322�ebRir%�bRicEOvbbreqcI�Y�bbrevb
   ��

     APA��rbe
             ��cJ�vbbrew

                        APA��tw`2APA w`�1APA0193464322�ebRir%�bRicEOvbbreqcI�

OK – das ist zwar Gibberish, aber es kommt was. Immerhin kann ich schon die Zähler-Seriennummer erkennen (APA0193464322, von mir verfremdet). Dass nicht alles glasklar ist liegt daran, dass der Stromzähler ein Binärprotokoll verwendet (SML: Smart Message Language). D.h. wir erwarten garnicht, dass hier schön lesbare Werte kommen. In jedem Fall aber wissen wir, dass der Kopf richtig herum installiert ist, denn sonst würden wir garnichts sehen.

sml2mqtt

Als nächstes müssen wir nun sehen, wie wir diese Daten interpretiert bekommen und zum Homeassistant senden.

Teil 1 der Aufgabe wird von SmlLib erfüllt. Und Teil 2 könnte man z.B. mit paho-mqtt erledigen. Aber netterweise gibt es das Ganze schon fertig gebündelt: sml2mqtt. Das Tool übernimmt das Lesen und Parsen der SML-Pakete und schickt den Inhalt dann an unseren MQTT Server. Und von dort können wir dann in HASSIO darauf zugreifen.

Also installieren wir es zunächst:

# become root
sudo -i
# Install sml2mqtt under /opt/
cd /opt/
python3 -m venv sml2mqtt
source sml2mqtt/bin/activate
pip install sml2mqtt

Und dann brauchen wir noch ein config file config.yml:

# sml2mqtt config for optical head on norax 3d energy meter

logging:
  level: INFO
  file: sml2mqtt.log

ports:
- url: /dev/ttyUSB0
  baudrate: 9600
  byte size: 8
  parity: 'None'
  stop bits: 1
  timeout: 3

mqtt:
  connection:
    client id: sml2mqtt
    host: localhost
    port: 1883
    user: 'phil'
    password: 'VerySecretPassword'
    tls: false
    tls insecure: false

  defaults:
    qos: 0
    retain: false
  topic prefix: sml2mqtt

  last will:
    topic: status

general:
  Wh in kWh: true       # Automatically convert Wh to kWh
  republish after: 120    # Republish automatically after this time

... und können dann loslegen.

Auf dem Laptop starten wir mal einen MQTT-client um zu lauschen:

mosquitto_sub -h hal -u phil -P VerySecretPassword -t 'sml2mqtt/#' -v

Und dann auf dem Server sml2mqtt:

sml2mqtt -c config.yml -v

Und schon bekommen wir Werte auf dem Laptop:

sml2mqtt/1APA0193464322/010060320101 41504120
sml2mqtt/1APA0193464322/0100010800ff 29248.0
sml2mqtt/1APA0193464322/0100020800ff 1.0

sml2mqtt ist unser topic prefix, wie wir es in config.yml gesetzt hatten. 1APA0193464322 ist die ID unseres Stromzählers und das Zahlenwerk am Ende sind sogenannte OBIS Codes gefolgt von Werten. Und die wollen wir mal übersetzen und ein wenig recherchieren, was sie bedeuten:

  • 01 00 60 32 01 01 1-0:96.50.1*1 : Hersteller-Identifikation
  • 01 00 01 08 00 ff 1-0:1-8.0*255 : Stromzählerstand Gesamt [kWh]
  • 01 00 02 08 00 ff 1-0:2-8.0*255 : Stromzählerstand Einspeisung Gesamt [kWh]

Perfekt, das funktioniert offenbar, auch wenn ich mir nicht wirklich erklären kann, wie ich eine kWh Strom ins Netz eingespeist haben soll – Aber gut.

Jetzt wo wir das wissen können wir unser config.yml file um folgendes ergänzen:

devices:
  1APA0193464322:
    mqtt:
      topic: energy_meter
    values:
      0100010800ff:
        mqtt:
          topic: total_energy_consumed
      0100020800ff:
        mqtt:
          topic: total_energy_returned

Und so sehen dann die MQTT messages viel aufgeräumter aus:

sml2mqtt/energy_meter/total_energy_consumed 29248.0
sml2mqtt/energy_meter/total_energy_returned 1.0

Das macht es einfacher nachher damit umzugehen.

SML2MQTT Service einrichten

Damit das dauerhaft klappt, müssen wir sml2mqtt nun als service einrichten. Dazu schreiben wir ein kleines service file (/etc/systemd/system/sml2mqtt.service):

[Unit]
Description=sml2mqtt
Documentation=https://github.com/spacemanspiff2007/sml2mqtt
StartLimitIntervalSec=10
After=syslog.target network.target

[Service]
Type=simple
User=sml2mqtt
Group=sml2mqtt
Restart=on-failure
RestartSec=30s
WorkingDirectory=/opt/sml2mqtt/
ExecStart=/opt/sml2mqtt/bin/sml2mqtt -c config.yml

# View with: sudo journalctl -f -u sml2mqtt -o cat
SyslogIdentifier=sml2mqtt

[Install]
WantedBy=multi-user.target

Im config file verwenden wir den user sml2mqtt – den müssen wir noch anlegen:

adduser --no-create-home --disabled-password sml2mqtt

Und damit das auch als user sml2mqtt laufen kann sollten wir noch prüfen, ob dieser User auch die nötigen Permissions hat. Oder besser – gleich alles ihm übergeben:

chown -R sml2mqtt:sml2mqtt /opt/sml2mqtt
adduser sml2mqtt dialout

Und mal als dieser User testen:

sudo -u sml2mqtt /opt/sml2mqtt/bin/sml2mqtt -c /opt/sml2mqtt/config.yml

Ob Daten gesendet werden, prüfen wir wieder mit mosquitto_sub wie oben. Wenn das funktioniert aktivieren wir den entsprechenden Service:

systemctl enable sml2mqtt.service

... und starten ihn:

systemctl start sml2mqtt.service

Kurz nachschauen, ob er wirklich läuft:

> systemctl status sml2mqtt.service 
● sml2mqtt.service - sml2mqtt service
     Loaded: loaded (/etc/systemd/system/sml2mqtt.service; enabled; preset: enabled)
     Active: active (running) since Sun 2023-10-15 18:24:26 CEST; 3s ago
   Main PID: 204540 (sml2mqtt)
      Tasks: 2 (limit: 19068)
     Memory: 20.2M
        CPU: 277ms
     CGroup: /system.slice/sml2mqtt.service
             └─204540 /opt/sml2mqtt/bin/python3 /opt/sml2mqtt/bin/sml2mqtt -c config.yaml

Top! Nun sicherheitshalber ein letztes mal prüfen, ob wir auch Daten empfangen:

mosquitto_sub -h hal -u phil -P VerySecretPassword -t 'sml2mqtt/#' -v

Ich sehe erneut Daten – top!

Einbinden in HASSIO

Nun ist es an der Zeit, die Daten in HASSIO zu bekommen. Als erstes legen wir mal einen mqtt sensor an indem wir auf dem Server das configuration.yaml file von HASSIO dies schreiben:

mqtt:
  sensor:
    - name: "Energy Consumed"
      state_topic: "sml2mqtt/energy_meter/total_energy_consumed"
      unit_of_measurement: "kWh"
      device_class: "Energy"
      state_class: total_increasing

Als nächstes müssen wir dem Energy Dashboard mitteilen, dass wir einen Stromzähler haben. Dazu gehen wir nach Settings > Dashboards > Energy und klicken unter Electricity grid auf Add Consumption. Tragen in das Device Feld unseren Energy Consumption Sensor ein – fertig.

Nun gilt es, eine ganze Weile zu warten, bis der Stromverbrauch endlich auftaucht. Das passiert erst, wenn HASSIO eine Änderung im Zählerstand erkennt.

Sehr gut.

Bonusmaterial: norax 3d Erweiterter Betrieb

Soweit hatte das ja nun alles gut funktioniert. Aber ein Punkt hat mich noch gefuchst: Die Auflösung des übermittelten Zählerstands ist 1.0 kWh. D.h. ich bekomme keine brauchbare Kurve über den Tag, weil der Zählerstand halt alle 1-4 Stunden mal um eine kWh steigt. Ich würde aber gerne Ereignisse wie "Herd eingeschaltet" im Stromverbrauch sehen können. Dazu brauche ich entweder mehr Auflösung, oder besser, die Momentanleistung, also wieviel Watt gerade insgesamt gezogen werden. Also habe ich nach einem Handbuch für den Stromzähler gegoogelt und es mehrfach gelesen. Offenbar kann der Zähler in einen "Erweiterten Betriebsmodus" geschaltet werden, um detailierte Werte über die optische Schnittstelle zu senden. Leider war die Beschreibung nicht so 100% verständlich, aber letztlich habe ich es herausgefunden und halte es hier für die Nachwelt fest.

Um den Erweiterten Betriebsmodus zu aktivieren braucht Ihr normalerweise die PIN des Zählers. Ich hatte einfach eine freundliche Email an meinen Stromversorger geschrieben und sie dann problemlos bekommen. Am Stromzähler sind dann die folgenden Schritte nötig:

  1. ◀ Taste für 5s gedrückt halten. Dann geht der Zähler in den LCD-Test Modus und verlässt ihn nach ein paar Sekunden von selber wieder.
  2. Nun wird man zur Eingabe der PIN aufgefordert (außer man hat das früher schon deaktiviert.)
  3. PIN eingeben: Der Zähler zeigt nun die erste Ziffer zur PIN-Eingabe an (0---). Durch mehrfaches Drücken der ◀ Taste kann man die gerade aktive Ziffer schrittweise hochzählen. Also wenn diese 0 sein soll garnichts tun und abwarten, bzw. wenn da 3 stehen soll, dreimal die Taste betätigen und dann warten bis das Display die nächste Stelle anzeigt (30--) – usw. Nach der Letzten Ziffer einfach abwarten.
  4. Sobald das Display umgesprungen ist, kann man mit der ◀ Taste durch die ganzen verschiedenen Anzeigen blättern.
  5. Nun so oft die ◀ Taste drücken, bis im Display Inf off steht. Das ist der Menüpunkt in dem man den Erweiterten Betrieb (erweiterte Info) einstellen kann.
  6. ◀ Taste 5s lang gedrückt halten. Nun steht im Display Inf on.
  7. ◀ Taste so oft drücken, bis im Display PIN on steht. ◀ Taste 5s gedrückt halten bis das Display PIN off anzeigt. Nun ist der PIN-Schutz deaktiviert.
  8. Zählerschrank schließen. Fertig.

Nun zurück an den Computer und schauen, ob wir nun mehr Daten bekommen:

❯ mosquitto_sub -h hal -u phil -P VerySecretPassword -t 'sml2mqtt/#' -v
sml2mqtt/energy_meter/total_energy_consumed 29258.578
sml2mqtt/energy_meter/0100200700ff 222.4
sml2mqtt/energy_meter/01001f0700ff 1.25
sml2mqtt/energy_meter/0100330700ff 1.04
sml2mqtt/energy_meter/0100470700ff 0.16
sml2mqtt/energy_meter/010051070fff -31
sml2mqtt/energy_meter/0100100700ff 444
sml2mqtt/energy_meter/0100200700ff 222.3
sml2mqtt/energy_meter/0100340700ff 219.6
sml2mqtt/energy_meter/0100480700ff 222.4
sml2mqtt/energy_meter/0100330700ff 1.05
sml2mqtt/energy_meter/0100200700ff 222.2
sml2mqtt/energy_meter/010051071aff -58
sml2mqtt/energy_meter/010051071aff -57
sml2mqtt/energy_meter/0100100700ff 445
sml2mqtt/energy_meter/0100200700ff 222.1
sml2mqtt/energy_meter/0100340700ff 219.7
sml2mqtt/energy_meter/0100330700ff 1.04
sml2mqtt/energy_meter/0100100700ff 444
sml2mqtt/energy_meter/0100340700ff 219.9
sml2mqtt/energy_meter/0100480700ff 222.6
sml2mqtt/energy_meter/01001f0700ff 1.24
sml2mqtt/energy_meter/0100330700ff 1.05
sml2mqtt/energy_meter/0100100700ff 446
sml2mqtt/energy_meter/0100480700ff 222.7
sml2mqtt/energy_meter/0100100700ff 445
sml2mqtt/energy_meter/0100200700ff 222.2
sml2mqtt/energy_meter/01001f0700ff 1.25
sml2mqtt/energy_meter/0100330700ff 1.04

Cool!

Bleibt noch, die Bedeutung der ganzen OBIS Codes zu recherchieren. Der für die Momentanleistung lautet nach der Betriebsanleitung 1.0:16.7.0*255 oder 0100100700ff. Aktuell also 445W.

Und wer genau hingeschaut hat wird auch erkennen, dass die Angabe für total_energy_consumed nun Nachkommastellen hat! Und das sieht man auch sofort im Homeassistant, denn nun wird der Zählerstand viel gleichförmiger aktualisiert. Sehr gut!

An dieser Stelle könnte man aufhören, aber wir wollen noch schnell die momentane Gesamtleistung in den config Files nachziehen.

Zunächst für sml2mqtt (config.yml)

devices:
  1APA0193645225:
    mqtt:
      topic: energy_meter
    values:
      0100010800ff:
        mqtt:
          topic: total_energy_consumed
      0100020800ff:
        mqtt:
          topic: total_energy_returned
      0100100700ff:
        mqtt:
          topic: momentary_power

Service neu starten nicht vergessen:

systemctl restart sml2mqtt.service

Und dann im homeassistant (configuration.yaml):

mqtt:
  sensor:
    - name: "Energy Consumed"
      state_topic: "sml2mqtt/energy_meter/total_energy_consumed"
      unit_of_measurement: "kWh"
      device_class: "Energy"
      state_class: total_increasing
    - name: "Momentary Power"
      state_topic: "sml2mqtt/energy_meter/momentary_power"
      unit_of_measurement: "W"
      device_class: "Power"

Und auch diesen neu starten (Settings > System > ⏻). Und schon ist alles eingebunden. Wenn ich irgendwann Lust habe, mache ich das evtl. auch noch für die übrigen OBIS codes, aber für den Moment bin ich völlig zufrieden.