Zum Inhalt

Python (Raspberry Pi · Linux · macOS · Windows)

Mit Python lässt sich der WattWächter TTL plattformübergreifend auslesen – egal ob direkt am Raspberry Pi über dessen GPIO-UART oder an Mac, Linux und Windows über einen einfachen USB-TTL-Adapter.

Die meisten modernen Zähler senden ihre Daten im SML-Format (Smart Message Language) mit 9600 Baud, 8N1. Wir verwenden dafür pyserial zum Einlesen der seriellen Schnittstelle und smllib zum Dekodieren der Telegramme.

So funktioniert die Kommunikation

Die meisten Zähler senden ihr Telegramm von sich aus zyklisch (Push) – bei ihnen genügt zum Auslesen die Empfangsleitung (grün / RXD). Die gelbe TX-Leitung ist nur für die übrigen Zähler nötig, die erst per Befehl zum Senden aufgefordert werden müssen.

Welche Zähler müssen zum Senden aufgefordert werden?

Moderne SML-Zähler (z. B. EMH eHZ/eBZD, EasyMeter Q3A/Q3D, eBZ, Holley DTZ541, Iskra MT 681) senden ohne Anfrage – hier genügt die RX-Leitung. Das obige Beispiel-Skript ist auf diese Zähler ausgelegt.

Eine Anfrage über die TX-Leitung benötigen dagegen vor allem ältere Zähler mit IEC-62056-21-Protokoll (Modus C, „D0"-ASCII). Sie liefern ihr Telegramm erst, nachdem die Anfragesequenz /?!\r\n gesendet wurde. Laut unseren Zähler-Skripten betrifft das diese Modelle:

Hersteller Modelle
Apator 12EC3 / 12EC3G
Baylan BM, BT
Elster / Honeywell AS1350, AS1440, AS1500, AS2018, AS3500, T510
EMH ITZ, LZQJ-XC
Iskra AM550, MT 171, MT 174, MT 382
Itron ACE3000 Typ 260, ACE6000
Kamstrup 382
Landis + Gyr E230, E350, E650, ZMB120, ZMD120, T550
Logarex LK11BL, LK13BD, LK13BO
MetCom MCS301
PAFAL 20EC3gr
Siemens TD-3511
ZPA ZE311, ZE314

Zusätzlich benötigen einige M-Bus-Wärme-/Wasserzähler (Engelmann SensoStar, MetCom Ultramess C3, Sensus Pollucom F) ein Weck-Telegramm. Für all diese Zähler reicht das obige reine SML-Skript nicht aus – sie sprechen ein anderes Protokoll und müssen aktiv abgefragt werden.

Voraussetzungen am Zähler

Damit der Zähler die vollständigen Momentanwerte (Leistung, Phasen) sendet, muss am Zähler meist die PIN deaktiviert und der erweiterte Infomodus (Inf → On) aktiviert sein. Die PIN erhältst du bei deinem Netzbetreiber.


Verkabelung

Die vier Adern werden 1:1 verbunden (die Kreuzung von RX/TX erfolgt bereits auf der Platine des Lesekopfs).

Kabel (TTL) Funktion Raspberry-Pi-Pin
Braun VCC Pin 1 — 3V3
Grün RXD (Daten) Pin 10 — GPIO15 / RXD
Gelb TXD Pin 8 — GPIO14 / TXDoptional
Weiß GND Pin 6 — GND

Verkabelung WattWächter TTL an Raspberry Pi

Adernfarben: braun → VCC, grün → RXD, gelb → TXD (gestrichelt = optional), weiß → GND.

UART am Raspberry Pi freigeben

Den seriellen Port aktivierst du mit sudo raspi-configInterface Options → Serial Port: Login-Shell über Serial deaktivieren, serielle Hardware aktivieren. Danach neu starten. Die Schnittstelle ist dann unter /dev/serial0 erreichbar.

Für PC, Mac oder Server verbindest du den WattWächter TTL über einen handelsüblichen USB-TTL-Adapter (z. B. CP2102, FT232, CH340).

Kabel (TTL) Funktion USB-TTL-Adapter
Braun VCC 3V3 (oder 5V)
Grün RXD (Daten) RXD
Gelb TXD TXDoptional
Weiß GND GND

Verkabelung WattWächter TTL an USB-TTL-Adapter

Adernfarben: braun → VCC, grün → RXD, gelb → TXD (gestrichelt = optional), weiß → GND.


Installation

pip install pyserial smllib

Beispiel-Skript

import serial
from smllib import SmlStreamReader

# --- Serielle Schnittstelle -------------------------------------------------
# Raspberry Pi (GPIO-UART):  /dev/serial0
# USB-TTL-Adapter (Linux):   /dev/ttyUSB0
# macOS:                     /dev/tty.usbserial-XXXX
# Windows:                   COM3
PORT = "/dev/serial0"

# OBIS-Codes, die uns interessieren (Kurzform -> Bezeichnung)
OBIS = {
    "1.8.0":  "Bezug",        # Wh, aus dem Netz bezogen
    "2.8.0":  "Einspeisung",  # Wh, ins Netz eingespeist
    "16.7.0": "Leistung",     # W, aktuelle Wirkleistung (vorzeichenbehaftet)
}

ser = serial.Serial(PORT, baudrate=9600, bytesize=8,
                    parity="N", stopbits=1, timeout=2)
stream = SmlStreamReader()

print(f"Lese WattWächter TTL an {PORT} ...")
while True:
    data = ser.read(ser.in_waiting or 1)
    if not data:
        continue

    stream.add(data)
    frame = stream.get_frame()
    if frame is None:
        continue   # Telegramm noch nicht vollständig

    for entry in frame.get_obis():
        name = OBIS.get(entry.obis.obis_short)
        if name is None:
            continue
        value = entry.get_value()          # bereits skaliert (Wert × 10^Scaler)
        if entry.obis.obis_short in ("1.8.0", "2.8.0"):
            print(f"{name:12s}: {value / 1000:.3f} kWh")
        else:
            print(f"{name:12s}: {value:.0f} W")
    print("-" * 30)

Beispiel-Ausgabe:

Lese WattWächter TTL an /dev/serial0 ...
Bezug       : 12345.678 kWh
Einspeisung : 4321.000 kWh
Leistung    : 437 W
------------------------------

Weitere Werte auslesen

Ergänze das OBIS-Dictionary um weitere Codes (z. B. 36.7.0, 56.7.0, 76.7.0 für die Phasenleistungen oder 32.7.0, 52.7.0, 72.7.0 für die Phasenspannungen). entry.get_value() liefert den Wert bereits korrekt skaliert, entry.unit enthält den Einheiten-Code. Eine Übersicht gängiger OBIS-Codes findest du unter Weitere OBIS-Kennzahlen.


Fehlerbehebung

Problem Mögliche Ursache / Lösung
Permission denied auf /dev/... Benutzer zur Gruppe dialout hinzufügen: sudo usermod -aG dialout $USER, danach neu anmelden
Keine Daten / frame bleibt None Lesekopf nicht korrekt über der IR-Diode positioniert; grünes Kabel (RXD) nicht am RX des Adapters; falscher Port
Nur Energiezähler, keine Leistung/Phasen Am Zähler PIN deaktivieren und Inf → On setzen
Am Raspberry Pi kommt nichts an Serielle Login-Shell deaktiviert? Port /dev/serial0 statt /dev/ttyAMA0 verwenden
Werte um Faktor 10/100 falsch In seltenen Fällen get_obis() durch parse_frame() ersetzen (siehe smllib-Doku)