Stromzähler Pyhton RS485 FHEM InfluxDB Grafana

Begonnen von Andreasgs, 07 August 2024, 10:12:13

Vorheriges Thema - Nächstes Thema

Andreasgs

Hallo,

Ich wollte euch mal zeigen, wie ich meinen Standardstromzähler von Logarex per RS485 auslese. Mein Energieversorger hat mir den Stromzähler von Logarex installiert. Dieser hat eine RS485 Schnittstelle, mit der die Üblichen Daten des zähler ausgelesen werden kann.

Man braucht:
- Raspberry Pi3, mit FHEM, und FHEM Pyhton Modul
- InfluxDB
- Grafana server

Das Python Skript liest den Speicher des Zählers aus, (im 20 Sekundentakt), baut für jede Speicherzelle ein REading uns schickt es an FHEM. Dieses FHEM ist mit einer InfluxDB verbunden und schreibt seinerseits alle DAten in die Datenbank. Ein Grafana dashboard hold diese Daten aus der InfluxDB und stellt diese dann dar.

Ich lese folgende Daten aus:
Speicherblock_Bezeichnung = (
    "1-0:96.1.0*255(001LOG0065800***)Hersteller unabhaengige Identifikationsnummer –Produktionsnummer",
    "1-0:1.8.0*255(000000.0000*kWh)Kumulatives Register der aktiven Energie in kWh T1+T2",
    "1-0:2.8.0*255(000000.0000*kWh)-A Energie",
    "1-0:16.7.0*255(000000*W)aktuelle Gesamtleistung",
    "1-0:32.7.0*255(000.0*V)Spannung L1, Auflösung 0.1 V",
    "1-0:52.7.0*255(000.0*V)Spannung L2, Auflösung 0.1 V",
    "1-0:72.7.0*255(228.8*V)Spannung L3, Auflösung 0.1 V",
    "1-0:31.7.0*255(000.00*A)Strom L1, Auflösung 0.01 A",
    "1-0:51.7.0*255(000.00*A)Strom L2, Auflösung 0.01 A",
    "1-0:71.7.0*255(000.00*A)Strom L3, Auflösung 0.01 A",
    "1-0:81.7.1*255(000*deg)Phasenwinkel UL2 : UL1",
    "1-0:81.7.2*255(000*deg)Phasenwinkel UL3 : UL1",
    "1-0:81.7.4*255(000*deg)Phasenwinkel IL1 : UL1",
    "1-0:81.7.15*255(000*deg)Phasenwinkel IL2 : UL2",
    "1-0:81.7.26*255(000*deg)Phasenwinkel IL3 : UL3",
    "1-0:14.7.0*255(50.0*Hz)Netz Frequenz in Hz",
    "1-0:1.8.0*96(00000.0*kWh)Historischer Energieverbrauchswert vom letzten Tag (1d)",
    "1-0:1.8.0*97(00000.0*kWh)Historischer Energieverbrauchswert der letzten Woche (7d)",
    "1-0:1.8.0*98(00000.0*kWh)Historischer Energieverbrauchswert des letzten Monats (30d)",
    "1-0:1.8.0*99(00000.0*kWh)Historischer Energieverbrauchswert des letzten Jahres (365d)",
    "1-0:1.8.0*100(00000.0*kWh)Historischer Energieverbrauchswert seit letzter Rückstellung",
    "1-0:0.2.0*255(ver.03,432F,20170504)Firmware Version, Firmware Prüfsumme CRC , Datum",
    "1-0:96.90.2*255(F0F6)Prüfsumme -CRC der eingestellten Parameter",
    "1-0:97.97.0*255(00000000)FF -Status Register -Interner Gerätefehler")

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import serial
import serial.rs485
import fhem

# Hier wird der String defniert, der spaeter zum senden an FHEM benutzt wird
op = "setreading"  # Befehl, der in FHEM Syntax zu beginn steht
dev = "RS485_Strom_Zaehler"  # FHEM - Device, dass mit dem befehl angesprochen werden soll

Speicherblock_Bezeichnung = (
    "1-0:96.1.0*255(001LOG0065800***)Hersteller unabhaengige Identifikationsnummer –Produktionsnummer",
    "1-0:1.8.0*255(000000.0000*kWh)Kumulatives Register der aktiven Energie in kWh T1+T2",
    "1-0:2.8.0*255(000000.0000*kWh)-A Energie",
    "1-0:16.7.0*255(000000*W)aktuelle Gesamtleistung",
    "1-0:32.7.0*255(000.0*V)Spannung L1, Auflösung 0.1 V",
    "1-0:52.7.0*255(000.0*V)Spannung L2, Auflösung 0.1 V",
    "1-0:72.7.0*255(228.8*V)Spannung L3, Auflösung 0.1 V",
    "1-0:31.7.0*255(000.00*A)Strom L1, Auflösung 0.01 A",
    "1-0:51.7.0*255(000.00*A)Strom L2, Auflösung 0.01 A",
    "1-0:71.7.0*255(000.00*A)Strom L3, Auflösung 0.01 A",
    "1-0:81.7.1*255(000*deg)Phasenwinkel UL2 : UL1",
    "1-0:81.7.2*255(000*deg)Phasenwinkel UL3 : UL1",
    "1-0:81.7.4*255(000*deg)Phasenwinkel IL1 : UL1",
    "1-0:81.7.15*255(000*deg)Phasenwinkel IL2 : UL2",
    "1-0:81.7.26*255(000*deg)Phasenwinkel IL3 : UL3",
    "1-0:14.7.0*255(50.0*Hz)Netz Frequenz in Hz",
    "1-0:1.8.0*96(00000.0*kWh)Historischer Energieverbrauchswert vom letzten Tag (1d)",
    "1-0:1.8.0*97(00000.0*kWh)Historischer Energieverbrauchswert der letzten Woche (7d)",
    "1-0:1.8.0*98(00000.0*kWh)Historischer Energieverbrauchswert des letzten Monats (30d)",
    "1-0:1.8.0*99(00000.0*kWh)Historischer Energieverbrauchswert des letzten Jahres (365d)",
    "1-0:1.8.0*100(00000.0*kWh)Historischer Energieverbrauchswert seit letzter Rückstellung",
    "1-0:0.2.0*255(ver.03,432F,20170504)Firmware Version, Firmware Prüfsumme CRC , Datum",
    "1-0:96.90.2*255(F0F6)Prüfsumme -CRC der eingestellten Parameter",
    "1-0:97.97.0*255(00000000)FF -Status Register -Interner Gerätefehler")

Speicherblock_Variablenname = (
    "Zaehler-ID",
    "Zaehlerstand",
    "Energie",
    "P_act",
    "U_L1",
    "U_L2",
    "U_L3",
    "I_L1",
    "I_L2",
    "I_L3",
    "Phasenwinkel_UL2UL1",
    "Phasenwinkel_UL3UL1",
    "Phasenverschiebeung_IL1UL1",
    "Phasenverschiebeung_IL2UL2",
    "Phasenverschiebeung_IL3UL3",
    "Netzfrequenz",
    "Energie_1d",
    "Energie_7d",
    "Energie_30d",
    "Energie_365d",
    "Energie_SeitReset",
    "FWVersion_FWCRC_Datum",
    "Parameter_CRC",
    "int_Fehler"
)

Speicherblock_Wert = [
    "Leerer Text",
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    0.0,
    "Leerer Text",
    "Leerer Text",
    "Leerer Text"
]

Speicherblock_Einheit = ("Zeichenkette",
                         "kWh",
                         "kWh",
                         "W",
                         "V",
                         "V",
                         "V",
                         "A",
                         "A",
                         "A",
                         "deg",
                         "deg",
                         "deg",
                         "deg",
                         "deg",
                         "Hz",
                         "kWh",
                         "kWh",
                         "kWh",
                         "kWh",
                         "kWh",
                         "Zeichenkette",
                         "Byte",
                         "Byte",
                         "Byte",
                         )

for i in range(0, len(Speicherblock_Bezeichnung) - 1):
    print(Speicherblock_Bezeichnung[i], Speicherblock_Variablenname[i], Speicherblock_Wert[i], Speicherblock_Einheit[i])

print("try to Connect to FHEM")
fh = fhem.Fhem("localhost", port=7072, use_ssl=False, password="CndoOS39#")
fh.connect()
print("connected")
print("init RS485")

while 1:
    ser = serial.rs485.RS485(
        port='/dev/ttyUSB1',  # Replace ttyS0 with ttyAM0 for Pi1,Pi2,Pi0
        baudrate=9600,
        timeout=5
    )
    ser.rs485_mode = serial.rs485.RS485Settings()
    print('check which port was really used')
    print(ser.name)  # check which port was really used
    print(ser)
    jetzt = time.localtime()
    a = ser.readline()
    print("Steht mist im Buffer:\n" + str(a) + "\n")
    print("Schicke InitBytes\n")
    values = bytearray([47, 63, 33, 13, 10])  # /?!<CR><LF> Carrige Retrun <CR> # Line Feed <LF>
    ser.write(values)
    print("Warte\n")
    time.sleep(0.3)
    a = ser.readline()
    print("Buffer gelesen\n")
    # print("Anzahl Bytes empfangen: %d" % ser.inWaiting())
    if len(a) > 0:
        print("Folgendes Bytearry wurde empfangen:\n" + str(a) + "\n")
    else:
        print("Nix drin\n")
    ser.close()
    time.sleep(1)
    print("Schnittstelle neu initialiseren mit 9600bd\n")
    ser = serial.rs485.RS485(
        port='/dev/ttyUSB1',  # Replace ttyS0 with ttyAM0 for Pi1,Pi2,Pi0
        baudrate=9600,
        timeout=2
    )
    ser.rs485_mode = serial.rs485.RS485Settings()
    values = bytearray([6, 48, 35, 48, 13, 10])  # <ACK>050<CR><LF> Carrige Retrun <CR> # Line Feed <LF>
    ser.write(values)
    time.sleep(0.4)
    x = ser.readlines()
    if len(x) > 0:
        print("Folgendes Bytearry wurde empfangen:\n" + str(x) + "\n")
        print(len(x))
        for i in range(0, len(Speicherblock_Bezeichnung)):
            # m = maske.match(str(x[i]))
            StartIndex = 0
            EndIndexStar = 0
            EndIndexklammer = 0
            # print(m.group(1))
            # print(m.group(2))
            Speicherblock = str(x[i])
            StartIndex = Speicherblock.index("(")  # Finden von der öffnenden Klammer
            EndIndexStar = Speicherblock.index("*")  # Finden von Einheitenmultiplikator
            EndIndexklammer = Speicherblock.index(")")  # Finden der schließenden Klammer
            summ = StartIndex + EndIndexStar + EndIndexklammer
            if summ > 0:  # Es gibt entweder eine der Klammern oder einen STern
                if StartIndex > 0:  # Es gibt eine oeffnende Klammer
                    m = Speicherblock[StartIndex + 1:EndIndexklammer]  # Substring zwischen den Klammern
                    print("Anfang:")
                    print(m)  # String zwischen den klammern
                    if "*" in m:  # Gibt es im Substring einen Stern?
                        print("Stern ist an position %d" % m.index("*"))
                        Speicherblock_Wert[i] = float(m[0:m.index("*")])
                        print("Das wird in den Speicherblock geschrieben: %f" % float(m[0:m.index("*")]))
                        cmd = '%s %s %s %f' % (op, dev, Speicherblock_Variablenname[i], Speicherblock_Wert[
                            i])  # Zusammenbau des ersten FHEM - Kommandos aus Befehl, Geraet, Reading, Wert, Einheit
                        print(cmd)  # debugging
                        fh.send_cmd(cmd, 0)
                    else:
                        Speicherblock_Wert[i] = m
                        print("Das wird in den Speicherblock geschrieben:", str(m))
                        cmd = '%s %s %s %s' % (op, dev, Speicherblock_Variablenname[i], Speicherblock_Wert[
                            i])  # Zusammenbau des ersten FHEM - Kommandos aus Befehl, Geraet, Reading, Wert, Einheit
                        print(cmd)  # debugging
                        fh.send_cmd(cmd, 0)
                        # Senden des Kommandos an FHEM durch nutzung des FHEM - Objekts

                else:
                    print("Da iss keine klammer" % i)
    else:
        print("Verdammt!!!\n")
    ser.close()
    print("Time to sleep")
    time.sleep(20)