Stromzähler-Pin mit Raspi raten

Um vollen Zugriff auf die Messdaten eines Stromzählers zu erhalten, wird in der Regel eine Pin benötigt. Diese kann beim zuständigen Netzbetreiber angefordert werden. Da die Netzbetreiber sich hiermit teilweise monatelang Zeit lassen, lässt sich alternativ ein Raspberry Pi programmieren, um den korrekten Zähler-Pin mittels Brute-Force Methode herauszufinden.

Dazu wird eine LED verwendet, die in einem präzisen Rhythmus ein- und ausgeschaltet wird. Zunächst muss die LED zweimal blinken, um den Eingabemodus des Zählers zu aktivieren. Anschließend kann das System die Zahlenkombinationen von 0000 bis 9999 systematisch durchlaufen. Dabei ist darauf zu achten, dass die LED nah genug am Sensor des Stromzählers fixiert wird, um Übertragungsfehler zu vermeiden. Zudem muss das Timing exakt auf das jeweilige Zählermodell abgestimmt sein, damit die Lichtsignale weder zu schnell noch zu langsam erfolgen. Bei erfolgreicher Eingabe werden in meinem Zählermodell die erweiterte Verbrauchsdatenübermittlung zum Betrieb eines Zählermesskopfes automatisch freigeschaltet.

 

import RPi.GPIO as GPIO
import time

LED_PIN = 17

GPIO.setmode(GPIO.BCM)
GPIO.setup(LED_PIN, GPIO.OUT)

def signal(sleeptime=0.1):
   GPIO.output(LED_PIN, GPIO.HIGH)
   time.sleep(0.01)
   GPIO.output(LED_PIN, GPIO.LOW)
   time.sleep(sleeptime)
   
try:
    for index in range(0000,10000):  # 0000 bis 9999
        # Zahl als 4-stellige Zeichenkette formatieren
        number_str = f"{index:04d}"
        
        # In einzelne Ziffern umwandeln
        digits = [int(d) for d in number_str]
        
        print(f"Aktueller Index: {number_str} -> {digits}")
        # Init Pin Mode
        signal(0.2)
        signal()
        for digit in digits:
            
            # LED für jede Ziffer kurz einschalten
            print(digit)
            for i in range(digit):
               signal()
            # Pause zwischen den Ziffern
            time.sleep(3)
        
        # 3 Sekunden Pause nach 4 Ziffern
        time.sleep(1)

except KeyboardInterrupt:
    print("Programm beendet")

finally:
    GPIO.cleanup()

 

Nachtrag

Ganz so einfach war es nicht, denn wenn der Pin korrekt eingegeben ist, passiert erst einmal ... nichts. Der Stromzähler scrollt durch ein Menü, verlässt durch weitere Eingaben das Menü erneut und ist eine Zeit lang "Out of Sync" mit der Eingabe. Irgendwann fängt er sich jedoch wieder. Wenn man diesen Moment verpasst – Pech. Und die Wahrscheinlichkeit ist außerordentlich hoch.

Also musste eine Kamera vor dem Stromzähler aufgebaut werden, zusammen mit einer weißen LED zur Beleuchtung in der Nacht.
Dabei wurden zwei Fotos gemacht: Eines von der 'fertigen' Pin-Eingabe, um zu prüfen, ob auch der richtige Pin geprüft wurde (bis das nahezu ausschließlich der Fall war, wurden die Timings bzgl. Eingabe deutlich heruntergedreht), und ein weiteres von dem Display nach der Pin Eingabe. Dieses sollte zeigen, ob der Zähler danach entsperrt ist.

Im Anschluss wurden die Bilder "gecropt" und im Vorschaumodus "durchgescrollt". Bei fast 20.000 Bildern ist man damit durchaus 30 min beschäftigt.

from picamera2 import Picamera2
from time import sleep
import RPi.GPIO as GPIO
import time

picam2 = Picamera2()
picam2.start()
LED_PIN = 17

GPIO.setmode(GPIO.BCM)
GPIO.setup(LED_PIN, GPIO.OUT)

def signal(digit=1, sleep=0.2):
   for i in range(digit):
      GPIO.output(LED_PIN, GPIO.HIGH)
      time.sleep(0.05)
      GPIO.output(LED_PIN, GPIO.LOW)
      time.sleep(sleep)

try:
    for index in range(1,9999):  # 0000 bis 9999
        # Zahl als 4-stellige Zeichenkette formatieren
        number_str = f"{index:04d}"

        # In einzelne Ziffern umwandeln
        digits = [int(d) for d in number_str]

        print(f"\nAktueller Index: {number_str} ->", end=" ", flush=True)
        # Init Pin Mode
        signal(sleep=0.2)
        signal()
        for i, digit in enumerate(digits, start=1):
            print(digit, end=" ", flush=True)
            signal(digit)
            if i==4: picam2.capture_file(f"{index}_1.jpg")
            time.sleep(3)
        # 3 Sekunden Pause nach 4 Ziffern
        picam2.capture_file(f"{index}_2.jpg")
        time.sleep(0.5)


except KeyboardInterrupt:
    print("Programm beendet")

finally:
    GPIO.cleanup()
    picam2.stop()
    

Finale Worte

Was hat es mit diesem Projekt auf sich, und warum wird da so viel Zeit reingesteckt. Lohnt sich das wirtschaftlich? Natürlich nicht! Meine Frau sprang hier im Dreieck: "Der ganze Haushalt bleibt bei mir liegen und du kümmerst dich um solche Belanglosigkeiten und baust Kameraequipment vor dem Stromzähler auf!" Der Punkt geht an sie, sicherlich.

Das Projekt wurde von mir vorbereitet und im Anschluss mit einem Tagespraktikanten Felix erneut erarbeitet, inklusive das Schreiben und Veröffentlichen des obigen Beitrags (nicht der Nachtrag) auf der Webseite. Durch die gute Vorbereitung ist sichergestellt, dass alles wie vorgesehen funktioniert und keine Langeweile aufkommt; und wer sich mit der aktuellen Ausbildungssituation auseinandergesetzt hat, der weiß: Es ist heute nicht mehr ganz so einfach, die Jugend für den eigenen Job zu motivieren.

Quintessenz: Es ist in wenigen Stunden machbar, ein Ingenieursprojekt des praktischen Alltags zu verstehen und einen Proof of Concept zu erbringen. Bis zur stabilen Umsetzung dauert es dann aber durchaus einen ganzen Tag.