Build a smartmeter reading head for 1€

Derzeit werden in Deutschland Stromzähler durch “Smartmeter” ausgetauscht. Die Smartmeter sind gerade smart genug, den Momentanverbrauch anzuzeigen. Damit sie das auch tun, muss man mit einer Taschenlampe eine PIN (PIN gibt es per Post vom Netzbetreiber) in das Smartmeter leuchten. Keine Ahnung, wer sich das Verfahren ausgedacht hat, Viel billiger als eine Folientastatur für eine Pin kann das kaum sein und es ist definitiv weniger smart. Vorne am Smartmeter gibt es eine Infrarotschnittstelle, über die man den Momentanverbrauch und den aktuellen Zählerstand gefahrlos (=Galvanisch getrennt) digital auslesen kann, nachdem die Pin eingegeben wurde.

Leider sind typische Leseköpfe für ihren Inhalt schweineteuer. Ein mit 45€ noch vergleichsweise günstiger kommt z.B. von Weidmann Elektronic. Typischerweise ist in so einem Lesekopf aber auch nur ein USB-Seriell Wandler und je nach Ausführung ein Fototransistor und eine IR-LED oder sogar nur ein Fototransistor verbaut.

Wenn man schon eine serielle Schnittstelle hat (z.B. USB-Seriell Wandler herumliegen oder einen Raspberry Pi…) kann man den Lesekopf auch für wenig Geld selbst bauen. Ich habe mich von diesem Post inspirieren lassen.

Einkaufsliste

  • BPW 40 Fototransistor
  • Kabel (lang genug um vom Lesenden Gerät bis zum Smartmeter zu gehen. Bei mir steht der Raspberry PI direkt unterm Stromzähler)

Aufbau des Sensors:

Der BPW40 kann direkt zwischen GND und RXD des an den GPIOs eines Raspberry Pi (oder eines USB-Seriell-Wandlers) angeschlossen werden. Für Raspberry Pi 3 sollte man erstmal im Vorfeld das Bluetooth-Modul deaktivieren, da dieses auch am seriellen Port angeschlossen ist.

Bei der Richtung des Fototransistors kann man nicht viel falsch machen: Ich habe den Sensor gleich mal versehentlich falsch herum angeschlossen, dem Raspberry Pi schadet das nicht, da schlimmstenfalls RxD auf GND gezogen wird (und dafür ist RxD ausgelegt). Auch der Sensor sollte vom schwachen Pullup an RxD nicht kaputt gehen können. Ist der Sensor falsch herum angeschlossen, empfängt man halt natürlich nix.

Verdrahtung des BPW40 mit dem Raspberry Pi

Anbringen am Stromzähler

Bei mir steht der Raspberry eh in der Nähe des Stomzählers. Den BPW40 habe ich am Kabel festgelötet und mit etwas Isolierband an einem kleinen Magneten befestigt. Die Metallscheibe am Stromzähler bei der Infrarotschnittstelle ist magnetisch, damit man den “Lesekopf” auf diese Weise dort anbringen kann. Hier ein paar Bilder des Aufbaus:

Anschluss des BPW40 auf dem Raspberry Pi
Seitenansicht “Lesekopf”: Isolierband verbindet BPW40 mit Haltemagnet. Dazu etwas Schaumstoff um die Pins gerade zu halten.
Draufsicht BPW40 mit Magnet am Stromzähler befestigt.

 

Ausblick: Setup auf dem Raspberry Pi

Um den Lesekopf zu aktivieren, muss man erstmal den seriellen Port nutzbar machen. Für Rasberry Pi 2 heißt das: raspi-config konsolenprogramm ausführen, darin folgende Schritte: Interfacing Options -> Serial: Would you like a login shell to be accessible over serial: NO -> Would you like the serial hardware port to be enabled: YES. Für Raspberry Pi 3 sollte man zusätzlich im Vorfeld das Bluetooth-Modul deaktivieren

Nach dem Reboot kann man dann mit cat /dev/ttyAMA0 mit etwas Glück die ersten Daten reintröpfeln sehen, wenn man den Lesekopf vor die Sendediode des Stromzählers hält. Falls nicht, lohnt es sich ein Terminalprogramm aufzurufen und dort die richtige Baudrate, den richtigen Port und den richtigen Übertragungsmodus zu wählen (typischerweise 9600 8n1). Ich habe minicom verwendet, das kann mit apt install minicom installiert werden, z.B. hier gibt es eine Kurzanleitung.

In einem weiteren Schritt braucht man dann eine Software, die das Binärkauderwelsch aus dem Stromzähler dekodieren kann, ich habe node-red zusammen mit dem node-red-contrib-smartmeter-Modul verwendet, um die Daten in ein bereits laufendes graphite backend zu füttern und mit Grafana zu visualisieren. Am Ende bekommt man schöne Grafen des Stromverbrauchs. Man sieht gut dass unsere Grundlast mit um die hundert Watt ziemlich hoch ist. Die hohen Spikes sind der Backofen.

Wenn ich dazu komme mache ich noch einen Post über das Setup von nodered und graphite/grafana.

Stromverbrauch über 24 h

11 thoughts on “Build a smartmeter reading head for 1€

  1. Hi, Super Anleitung.

    Ist es auch möglich über node red an eine IR LED ein Signal zu schicken damit der Zähler zu senden beginnt?
    Ist bei meinem Iskra Zähler nötig…

  2. Funktioniert am MT681 in so einfach leider nicht. Es wird ein HEX-Protokoll ausgegeben, dieses ist leider in ioBroker mit dem smartmeter Adapter nicht auswertbar. Im Code ist die Startsequenz 1b1b1b1b nicht vorhanden.

    1. Hallo, mittlerweile habe ich auch einen MT681. Hier musste ich noch eine IR-LED für die TX-Verbindung anlöten (ich habe “IRL 81 A” verwendet, mit einem 1kOhm vorwiederstand direkt an TX). Danach ging es mit dem nodered-smartmetermodul.

  3. Hallo,
    ich habe einen Holley DTS541 und bekomme es leider nicht hin.
    Die LED am Zähler leuchtet quasi dauerhaft und blinkt hin und wieder mal.
    Liegt es eventuell daran?

    1. Holley DTS541 braucht evtl. eine bidirektionale Verbindung. Google sagt er arbeitet evtl mit dem Protokoll IEC 62056-21. Was ich bei Wikipedia gefunden habe suggeriert dass man hier um mit dem Meter zu reden selbst auch senden muss. In dem Fall müsstest du noch eine ir LED ant TX deines seriellen Ports anschließen und vor dem Phototransistor des Lesers platzieren. Ich würde an deiner Stelle aber erstmal googlen ob jemand diesen Leser schon erfolgreich auslesen kann.

  4. Hallo,
    gibt es eine Möglichkeit zwei BPW40 anzuschließen um zwei Zähler auszulesen? Ich hab eine Photovoltaikanlage mit einem eigenen Zähler hier…

    Danke!
    Michael

    1. Hallo Michael,

      Jeder BPW40 braucht seine eigene Serielle Schnittstelle, der Raspi hat aber so weit ich weiß nur eine Hardware-Schnittstelle. Du kannst es für den zweiten BPW40 mit einem USB-Serial adapter probieren. Bei uns kommt auch bald eine Photovoltaikanlage aufs dach, evtl. steh ich dann vor dem gleichen Problem. Falls ich es löse werd ich es verblogen.

      Viele Grüße,
      Paul

    2. Der Raspberry Pi 4 hat zusätzliche serielle Schnittstellen. Lies mal hier: https://www.raspberrypi.org/forums/viewtopic.php?f=107&t=244827 Dort ist beschrieben, wie man diese aktiviert.
      Hier kann man nachlesen welche GPIOs sich zu seriellen Ports machen lassen: https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2711/rpi_DATA_2711_1p0_preliminary.pdf

      Auf dem Raspberry selbst findet man in der Datei /boot/overlays/README auch die Auflistung der GPIOs für uart2-uart5.
      Bei uart 2 ist TDX2 auf GPIO0 und RDX2 auf GPIO1. (auf GPIO 2 und 3 sind CTS2 und RTS2, wenn man sie benötigt und aktiviert)

  5. Hallo,

    ich versuche verzweifelt die Daten von unseren Easymeter Q3B zu bekommen (BPW40 am Raspberry). Es kommen Daten, aber nicht die ich erwarte. Irgendwie passt da was nicht.
    Mittels folgenden Kommando habe ich die Schnittstelle eingestellt: stty -F /dev/ttyAMA0 9600 cs8 -parenb -ixon -cstopb -echo
    Dann wird folgendes geliefert:

    hexdump -C /dev/ttyAMA0
    00000000 00 00 20 00 00 00 20 00 00 00 10 18 00 00 00 18 |.. … ………|
    00000010 00 00 00 00 00 00 18 00 00 00 18 00 00 00 18 00 |…………….|
    00000020 00 00 3f 00 18 00 00 00 3b 00 20 00 00 00 00 00 |..?…..;. …..|
    00000030 20 00 00 00 20 00 00 00 10 18 00 00 00 18 00 00 | … ………..|
    00000040 00 00 00 7f 00 18 00 00 00 18 00 00 00 18 00 00 |…………….|
    00000050 00 00 18 00 00 00 3b 00 20 00 00 00 00 20 00 00 |……;. …. ..|
    00000060 00 20 00 00 00 10 18 00 00 00 18 00 00 00 00 00 |. …………..|
    00000070 00 18 00 00 00 18 00 00 00 18 00 00 00 00 18 00 |…………….|
    00000080 00 3b 00 20 00 60 00 00 00 20 00 00 00 00 20 00 |.;. .`… …. .|
    00000090 00 00 10 18 00 00 00 18 00 00 00 00 00 10 00 18 |…………….|
    000000a0 00 00 00 18 00 00 00 18 00 00 00 00 18 00 00 00 |…………….|
    000000b0 3b 00 20 00 00 00 00 00 20 00 00 00 00 00 20 00 |;. ….. ….. .|
    000000c0 00 00 12 20 64 06 00 00 00 18 00 00 00 00 00 18 |… d………..|
    000000d0 00 00 00 18 00 00 00 18 00 00 00 18 00 00 00 33 |……………3|
    000000e0 00 20 00 00 00 00 00 20 00 00 00 20 00 00 00 10 |. ….. … ….|
    000000f0 18 00 00 00 18 00 00 00 00 00 18 00 00 00 18 00 |…………….|
    00000100 00 00 18 00 00 00 00 18 00 00 33 00 20 00 00 00 |……….3. …|
    00000110 00 20 00 00 08 00 00 20 00 00 00 10 18 00 00 00 |. ….. ……..|
    00000120 18 00 00 00 00 00 00 00 18 00 00 00 18 00 00 00 |…………….|
    00000130 18 00 00 00 00 18 00 00 00 33 00 20 00 3c 00 00 |………3. .<..|
    00000140 00 20 00 00 00 00 20 00 00 08 10 3b 06 00 00 00 |. …. ….;….|
    00000150 18 00 00 00 00 00 18 00 00 00 18 00 00 00 18 00 |…………….|
    00000160 00 00 00 18 00 00 00 32 00 20 00 00 00 20 00 00 |…….2. … ..|
    00000170 06 00 00 20 00 00 10 20 64 06 00 00 00 18 00 00 |… … d…….|
    00000180 00 00 00 02 00 18 00 00 00 18 00 00 00 18 00 00 |…………….|
    00000190 00 08 00 18 00 00 00 3b 00 20 00 12 00 00 00 00 |…….;. ……|
    000001a0 20 00 02 00 00 00 20 00 02 00 00 40 48 18 00 00 | ….. ….@H…|

    Was könnte hier falsch sein?

    Gruß und Danke
    Jörg

  6. Hallo Jörg,
    ich hatte ein ähnliches Problem. Ich habe mir so geholfen:
    (mit python 3)

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import serial, time, rrdtool
    kennung_zaehlerstand="0100010800ff"
    # weil nach dem OBIS-Kennung weitere Zeichen kommen, die aussortiert werden müssen:
    kennung2="ff56"
    string = ''
    teil = []
    zaehlerstand=''
    pos=''
    start=0
    dif=0
    letzter_wert=0

    if __name__ == "__main__":
    ser = serial.Serial("/dev/serial0", 9600, timeout=1)
    if (ser.isOpen() == False):
    ser.open()

    while True:
    # Puffer löschen, weil sonst „nicht aktuelle“ Werte eingelesen werden
    ser.flushInput()
    string = ser.readline().hex()
    print("|", string, "|")
    if kennung_zaehlerstand not in string:
    pass
    else:
    pos=string.find(kennung_zaehlerstand)
    teil=string.split(kennung_zaehlerstand)
    string = teil.pop(1)
    teil=[]
    teil=string.split(kennung2,2)
    string=teil.pop(1)
    # print(string)
    zaehlerstand=string[0:10]
    print(zaehlerstand)
    # zählerstand = mit einer Kommastelle, daher:
    zeige= (int(zaehlerstand,base=16))/10
    # für die rrd-db muss der wert ohne kommastelle gewählt werden
    i=(int(zaehlerstand,base=16))
    # Differenz ermitteln
    if start !=0:
    dif = i - letzter_wert
    letzter_wert=i
    else:
    start=1
    letzter_wert=i

    print("Messwert: ",zeige/1000, 'kWh Differenz:', dif/10, 'Wh',time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))

    time.sleep(60)
    ser.close()
    print("Ende")

  7. Gerade habe ich bei meinem Raspberry auch den BPW40 angeklemmt.
    Allerdings bekamm ich keine vernüftigen Daten.
    Ein (Pull Up) Widerstand mit 4,7k Ohm zwischen 3,3V und RX hat das Problem gelöst.

Comments are closed.