Hallo zusammen,
in einem anderen Thread kam die Frage nach meinem viessmann Plugin. Daher möchte ich es hier gern vorstellen. Ich bin selbst mit den vcontrold und dem vclient nicht zurechtgekommen, daher habe ich mich dann selbst ans Werk gemacht und habe ein eigenes Plugin geschrieben. Es ist natürlich auf meine Heizung und Konfiguration zugeschnitten aber ich denke es kann auch anderen helfen eine Viessmann Heizung auszulesen.
Zunächst an der Stelle vielen Dank an die Seite https://github.com/openv/openv über die ich die meisten Informationen bezogen habe.
Leider nicht alle, es musst auch einiges "ertüftelt" werden.
Ich habe eine Vitodens 343F (Gas-Brennwertkessel mit witterungsgeführter Kessel- und Heizkreisregelung für 2 Heizkreise). Hiervon ist einer mit Mischer und einer ohne.
Der folgende Screeshot zeigt, was ich alles auslese. Dies habe ich gemacht, da ich viele Probleme im Vorfeld mit der Heizung hatte und nun immer up to date bleiben wollte, ob es der Heizung gut geht oder nicht.
screenshot.jpg
Als Auslesegerät verwende ich den USB Optolink von der folgenden Seite, der hier auch kostengünstig bestellt werden kann.
https://github.com/openv/openv/wiki/Bauanleitung-USB
Mit diesem habe ich dann mal mit einem Windows System einen ersten Test gemacht. Hierzu habe ich das Programm vControl verwendet.
https://github.com/openv/openv/wiki/v-control
Schaut man sich hier den Log an, sieht man schon in etwa, wie die Heizung kommuniziert.
Der folgende Block gibt Auskunft über das Protokoll und die Heizung selbst:
Ein Blick in die Geräteliste https://github.com/openv/openv/wiki/Ger%C3%A4te zeigt, dass es sich um die folgende Heizung handelt:
20 CB = VScotHO1, 300,KW, Vitodens200 / 300 mit Vitotronic 200 (HO1), Gas-Brennwertkessel mit witterungsgeführter Kessel- und Heizkreisregelung für 2 Heizkreise mit Mischer und 1 Heizkreis ohne Mischer
Um die Nutzdaten genauer zu verstehen lohnt sich ein Blick in den Telegrammaufbau, der ebenfalls auf der Seite openv beschrieben ist:
https://github.com/openv/openv/wiki/Protokoll-300
Das Schwierige ist es später herauszufinden, wie die Datenpunkte genau heißen, die abgefragt werden sollen. Auch hier gibt es Listen auf der nun viel zitierten Seite. Allerdings habe ich hier nicht alles finden können und musste mir das über die verschiedensten Seiten zusammensuchen.
https://github.com/openv/openv/wiki/Adressen
Nun aber zum eigentlichen Plugin. Es funktioniert genau für meine Heizung und läuft schon sehr lange absolut reibungslos. Das USB Interface habe ich mit einem Link versehen, so dass ich es immer unter dem Namen "ttyUSB_HEIZUNG" ansprechen kann. Hier muss dann natürlich euer Device entsprechend eingetragen sein.
Wichtig zu verstehen ist, dass dieses Plugin aktuell nur Daten liest. Es ist etwas vorbereitet für das Schreiben, allerdings habe ich hier nicht weitergemacht. Ich wollte meine Zirkulationspumpe manuell starten. Das ist aber wohl bei dem Modell nicht möglich. Schade, ansonsten hätte ich es morgens einfach eingeschaltet, wenn ich auch warmes Wasser brauche und nicht einfach nach der integrierten Zeitschaltuhr.
Das Plugin ermittelt die zugehörigen items selbst. Diese haben ein paar zusätzliche Parameter. Somit ist es dem Plugin egal, wie die Items in euren Config Files benannt werden. Die zusätzlichen Parameter sind ebenfalls kommentiert. Wichtig ist hier noch der Parameter "pluginreduction". Hiermit kann man die Abfrage untersetzen. So wird dieser Wert nicht bei jeder Abfrage abgefragt.
Beispiel für die item:
Die vollständige Liste meiner Items hänge ich auch mal an. Da kann man ggf. die Codes entnehmen.
Plugin code
\plugins\viessmann\__init__.py
Zum Schluss muss das Plugin dann noch in smarthome eingebettet und aufgerufen werden. Das passiert natürlich über die plugin.yaml
plugin.yaml
Das ist schon alles einige Zeit her. Ich denke einiges ist beschrieben. Die Fragen kommen sicherlich beim Probieren. Vielleicht kann ich dann helfen. Ansonsten einfach mal ausprobieren, wer es mag.
Gruß
loeserman
in einem anderen Thread kam die Frage nach meinem viessmann Plugin. Daher möchte ich es hier gern vorstellen. Ich bin selbst mit den vcontrold und dem vclient nicht zurechtgekommen, daher habe ich mich dann selbst ans Werk gemacht und habe ein eigenes Plugin geschrieben. Es ist natürlich auf meine Heizung und Konfiguration zugeschnitten aber ich denke es kann auch anderen helfen eine Viessmann Heizung auszulesen.
Zunächst an der Stelle vielen Dank an die Seite https://github.com/openv/openv über die ich die meisten Informationen bezogen habe.
Leider nicht alle, es musst auch einiges "ertüftelt" werden.
Ich habe eine Vitodens 343F (Gas-Brennwertkessel mit witterungsgeführter Kessel- und Heizkreisregelung für 2 Heizkreise). Hiervon ist einer mit Mischer und einer ohne.
Der folgende Screeshot zeigt, was ich alles auslese. Dies habe ich gemacht, da ich viele Probleme im Vorfeld mit der Heizung hatte und nun immer up to date bleiben wollte, ob es der Heizung gut geht oder nicht.
screenshot.jpg
Als Auslesegerät verwende ich den USB Optolink von der folgenden Seite, der hier auch kostengünstig bestellt werden kann.
https://github.com/openv/openv/wiki/Bauanleitung-USB
Mit diesem habe ich dann mal mit einem Windows System einen ersten Test gemacht. Hierzu habe ich das Programm vControl verwendet.
https://github.com/openv/openv/wiki/v-control
Schaut man sich hier den Log an, sieht man schon in etwa, wie die Heizung kommuniziert.
Code:
[FONT=courier new]22-11-2016 13:42:22 DATA Init 22-11-2016 13:42:22 COMM Init auf COM3 22-11-2016 13:42:22 DATA TX: 16 0 0 22-11-2016 13:42:23 COMM Comm Port OK 22-11-2016 13:42:23 COMM Verbunden: COM3 22-11-2016 13:42:24 DATA Lese: Version 22-11-2016 13:42:24 DATA TX: 41 5 0 1 0 F8 2 0 22-11-2016 13:42:24 DATA RX: 6 41 7 1 1 22-11-2016 13:42:24 DATA RX: 0 F8 2 20 CB EE 22-11-2016 13:42:24 SYS Version: VScotHO1 22-11-2016 13:42:25 DATA Lese Daten 22-11-2016 13:42:25 DATA TX: 41 5 0 1 8 8A 4 9C 22-11-2016 13:42:25 DATA RX: 6 41 22-11-2016 13:42:25 DATA RX: 9 1 1 8 8A 4 80 22-11-2016 13:42:25 DATA RX: 5 1 0 27 22-11-2016 13:42:25 DATA TX: 41 5 0 1 55 25 2 82 22-11-2016 13:42:25 DATA RX: 6 22-11-2016 13:42:25 DATA RX: 41 7 1 1 55 25 22-11-2016 13:42:25 DATA RX: 2 70 0 F5 22-11-2016 13:42:25 DATA TX: 41 5 0 1 55 27 2 84 22-11-2016 13:42:25 DATA RX: 6 41 7 1 22-11-2016 13:42:25 DATA RX: 1 55 27 2 61 0 22-11-2016 13:42:25 DATA RX: E8 22-11-2016 13:42:25 DATA TX: 41 5 0 1 55 5A 2 B7 22-11-2016 13:42:25 DATA RX: 6 41 7 1 22-11-2016 13:42:25 DATA RX: 1 55 5A 2 32 0 22-11-2016 13:42:25 DATA RX: EC 22-11-2016 13:42:25 DATA TX: 41 5 0 1 8 10 2 20 22-11-2016 13:42:25 DATA RX: 6 22-11-2016 13:42:25 DATA RX: 41 7 1 1 8 10 22-11-2016 13:42:25 DATA RX: 2 8D 2 B2 22-11-2016 13:42:25 DATA TX: 41 5 0 1 8 8 2 18 22-11-2016 13:42:25 DATA RX: 6 41 7 22-11-2016 13:42:25 DATA RX: 1 1 8 8 2 51 2 22-11-2016 13:42:25 DATA RX: 6E 22-11-2016 13:42:25 DATA TX: 41 5 0 1 8 96 2 A6 22-11-2016 13:42:25 DATA RX: 6 22-11-2016 13:42:25 DATA RX: 41 7 1 1 8 96 22-11-2016 13:42:25 DATA RX: 2 C8 0 71[/FONT]
Code:
[FONT=courier new]22-11-2016 13:42:24 DATA Lese: Version 22-11-2016 13:42:24 DATA TX: 41 5 0 1 0 F8 2 0 22-11-2016 13:42:24 DATA RX: 6 41 7 1 1 22-11-2016 13:42:24 DATA RX: 0 F8 2 [COLOR=#FF0000]20 CB[/COLOR] EE 22-11-2016 13:42:24 SYS Version: VScotHO1[/FONT]
20 CB = VScotHO1, 300,KW, Vitodens200 / 300 mit Vitotronic 200 (HO1), Gas-Brennwertkessel mit witterungsgeführter Kessel- und Heizkreisregelung für 2 Heizkreise mit Mischer und 1 Heizkreis ohne Mischer
Um die Nutzdaten genauer zu verstehen lohnt sich ein Blick in den Telegrammaufbau, der ebenfalls auf der Seite openv beschrieben ist:
https://github.com/openv/openv/wiki/Protokoll-300
Das Schwierige ist es später herauszufinden, wie die Datenpunkte genau heißen, die abgefragt werden sollen. Auch hier gibt es Listen auf der nun viel zitierten Seite. Allerdings habe ich hier nicht alles finden können und musste mir das über die verschiedensten Seiten zusammensuchen.
https://github.com/openv/openv/wiki/Adressen
Nun aber zum eigentlichen Plugin. Es funktioniert genau für meine Heizung und läuft schon sehr lange absolut reibungslos. Das USB Interface habe ich mit einem Link versehen, so dass ich es immer unter dem Namen "ttyUSB_HEIZUNG" ansprechen kann. Hier muss dann natürlich euer Device entsprechend eingetragen sein.
Wichtig zu verstehen ist, dass dieses Plugin aktuell nur Daten liest. Es ist etwas vorbereitet für das Schreiben, allerdings habe ich hier nicht weitergemacht. Ich wollte meine Zirkulationspumpe manuell starten. Das ist aber wohl bei dem Modell nicht möglich. Schade, ansonsten hätte ich es morgens einfach eingeschaltet, wenn ich auch warmes Wasser brauche und nicht einfach nach der integrierten Zeitschaltuhr.
Das Plugin ermittelt die zugehörigen items selbst. Diese haben ein paar zusätzliche Parameter. Somit ist es dem Plugin egal, wie die Items in euren Config Files benannt werden. Die zusätzlichen Parameter sind ebenfalls kommentiert. Wichtig ist hier noch der Parameter "pluginreduction". Hiermit kann man die Abfrage untersetzen. So wird dieser Wert nicht bei jeder Abfrage abgefragt.
Beispiel für die item:
Code:
[ZAEHLER] [[HEIZUNG]] [[[AUSSENTEMPERATUR]]] # Information Kessel Außentemperatur read 2-Byte -60..60 0x5525 # DATA TX: 41 5 0 1 55 25 2 82 # DATA RX: 41 7 1 1 55 25 2 EF 0 74 --> 00EF = 239 --> 23.9°C (Faktor 0.1) # --> Senden 41 5 0 1 55 25 2 82 # -- - - - ----- - -- # | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]5+0+1+55+25+2 = [dez]5+0+1+(5x16)+5+(2x16)+5+2 = 130dez = 82hex # | | | | | +----- XX Anzahl der Bytes, die in der Antwort erwartet werden # | | | | +--------- XX XX 2 byte Adresse der Daten oder Prozedur # | | | +------------- XX 01 = ReadData, 02 = WriteData, 07 = Function Call # | | +--------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler # | +----------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) # +------------------- Telegramm-Start-Byte # # --> Empfangen 6 41 7 1 1 55 25 2 EF 0 74 # - -- - - - ----- - ---- -- # | | | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]7+1+1+55+25+2+EF+0 = [dez]7+1+1+(5x16)+5+(2x16)+5+2+(14*16)+(15*16)+0 = [dez]7+1+1+(80)+5+(32)+5+2+(224)+(15)+0 = 372dez = 1.74hex) # | | | | | | | +------ Wert # | | | | | | +---------- XX Anzahl der Bytes, die in der Antwort erwartet werden # | | | | | +-------------- XX XX 2 byte Adresse der Daten oder Prozedur # | | | | +------------------ XX 01 = ReadData, 02 = WriteData, 07 = Function Call # | | | +-------------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler # | | +---------------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) # | +------------------------ Telegramm-Start-Byte # +--------------------------- OK (Antwort auf 0x16 0x00 0x00 und auf korrekt empfangene Telegramme) # # --> Antwort: 0x00EF = 239 = 23.9° name = Aussentemperatur [°C] type = num cache = True database@mysqldb = init knx_dpt = 9 knx_send = 5/2/0 # Temperatur auf den Bus schreiben für die Plus-Taster [COLOR=#FF0000] pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = aussentemperatur # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = signed # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000155250282# Ende direkt hinter dem Byte String[/COLOR]
Code:
# ----------------------------------------------------------------------- # Items für die Heizung # ----------------------------------------------------------------------- [ZAEHLER] [[HEIZUNG]] [[[READ]]] name = Alle Werte sofort auslesen type = bool value = False autotimer = 1 = False pluginusage = viessmann # Wird vom angegebenen Plugin verwendet pluginfct = readtrigger # Funktion, dieses items [[[SET_ZIRKULATION]]] name = Zirkulationspumpe ein/ausschalten type = bool value = False pluginusage = viessmann # Wird vom angegebenen Plugin verwendet pluginfct = setcirculationpump # Funktion, dieses items [[[LAST_READ]]] name = Letzter Lesevorgang type = str pluginusage = viessmann # Wird vom angegebenen Plugin verwendet pluginfct = lastreadtime # Funktion, dieses items [[[ALARMMESSAGE]]] name = Heizung Alarmmeldung type = bool visu_acl = rw value = False [[[AUSSENTEMPERATUR]]] # Information Kessel Außentemperatur read 2-Byte -60..60 0x5525 # DATA TX: 41 5 0 1 55 25 2 82 # DATA RX: 41 7 1 1 55 25 2 EF 0 74 --> 00EF = 239 --> 23.9°C (Faktor 0.1) # --> Senden 41 5 0 1 55 25 2 82 # -- - - - ----- - -- # | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]5+0+1+55+25+2 = [dez]5+0+1+(5x16)+5+(2x16)+5+2 = 130dez = 82hex # | | | | | +----- XX Anzahl der Bytes, die in der Antwort erwartet werden # | | | | +--------- XX XX 2 byte Adresse der Daten oder Prozedur # | | | +------------- XX 01 = ReadData, 02 = WriteData, 07 = Function Call # | | +--------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler # | +----------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) # +------------------- Telegramm-Start-Byte # # --> Empfangen 6 41 7 1 1 55 25 2 EF 0 74 # - -- - - - ----- - ---- -- # | | | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]7+1+1+55+25+2+EF+0 = [dez]7+1+1+(5x16)+5+(2x16)+5+2+(14*16)+(15*16)+0 = [dez]7+1+1+(80)+5+(32)+5+2+(224)+(15)+0 = 372dez = 1.74hex) # | | | | | | | +------ Wert # | | | | | | +---------- XX Anzahl der Bytes, die in der Antwort erwartet werden # | | | | | +-------------- XX XX 2 byte Adresse der Daten oder Prozedur # | | | | +------------------ XX 01 = ReadData, 02 = WriteData, 07 = Function Call # | | | +-------------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler # | | +---------------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) # | +------------------------ Telegramm-Start-Byte # +--------------------------- OK (Antwort auf 0x16 0x00 0x00 und auf korrekt empfangene Telegramme) # # --> Antwort: 0x00EF = 239 = 23.9° name = Aussentemperatur [°C] type = num cache = True database@mysqldb = init knx_dpt = 9 knx_send = 5/2/0 # Temperatur auf den Bus schreiben für die Plus-Taster pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = aussentemperatur # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = signed # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000155250282# Ende direkt hinter dem Byte String [[[AUSSENTEMPERATUR_GEDAEMPFT]]] # Information Kessel Außentemperatur gedaempft read 2-Byte -60..60 0x557 # DATA TX: 41 5 0 1 55 27 2 84 # DATA RX: 41 7 1 1 55 27 2 F5 0 7C --> 00F5 = 245 --> 24.5°C (Faktor 0.1) name = Aussentemperatur gedaempft [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = aussentempgedaempft # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = signed # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000155270284# Ende direkt hinter dem Byte String [[[BRENNERSTATUS]]] # Brenner eingesachaltet name = Brennerstatus type = bool cache = True eval = True if (sh.ZAEHLER.HEIZUNG.BRENNER_LEISTUNG() > 0.0) else False eval_trigger = ZAEHLER.HEIZUNG.BRENNER_LEISTUNG [[[[ALTER]]]] # Brenner eingesachaltet name = Dauer des aktuellen Brennerstatus type = num # Berechnung minütlich crontab = * * * * = 1 # crontab Minütlich - Aufbau: mm(0..59) hh day(0..28) wday(0=Mo, 1=Di, 2=Mi, 3=Do, 4=Fr, 5=Sa, 6=So) enforce_updates = True # Updates True, da der Crontab immer mit 1 ausführt und die Berechnung durchgeführt werden soll. eval = (sh.ZAEHLER.HEIZUNG.BRENNERSTATUS.age() / 60) [[[[PREV_ALTER]]]] # Brenner eingesachaltet name = Dauer des Brennerstatus zuvor type = num # Berechnung minütlich crontab = * * * * = 1 # crontab Minütlich - Aufbau: mm(0..59) hh day(0..28) wday(0=Mo, 1=Di, 2=Mi, 3=Do, 4=Fr, 5=Sa, 6=So) enforce_updates = True # Updates True, da der Crontab immer mit 1 ausführt und die Berechnung durchgeführt werden soll. eval = (sh.ZAEHLER.HEIZUNG.BRENNERSTATUS.prev_age() / 60) [[[BRENNERSTARTS]]] # Information Kessel Brennerstarts read 4-Byte 0..64000 0x088A # DATA TX: 41 5 0 1 8 8A 4 9C # DATA RX: 41 9 1 1 8 8A 4 48 F0 0 0 D9 --> 0000F048 = 61512 --> 61512 (Faktor 1) name = Brennerstarts type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = brennerstarts # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 1 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 41050001088A049C# Ende direkt hinter dem Byte String [[[[LETZTE_STUNDE]]]] name = Brennertstarts innerhalb der letzten Stunde type = num cache = True # Berechnung stündlich crontab = 0 * * * = 1 # crontab Stündlich - Aufbau: mm(0..59) hh day(0..28) wday(0=Mo, 1=Di, 2=Mi, 3=Do, 4=Fr, 5=Sa, 6=So) enforce_updates = True # Updates True, da der Crontab immer mit 1 ausführt und die Berechnung durchgeführt werden soll. eval = round((sh.ZAEHLER.HEIZUNG.BRENNERSTARTS() - sh.ZAEHLER.HEIZUNG.BRENNERSTARTS.db('min', '1h')), 1) [[[[LETZTER_TAG]]]] name = Brennertstarts innerhalb des letzten Tages type = num cache = True database@mysqldb = init # Berechnung täglich crontab = 0 0 * * = 1 # crontab Täglich 0 Uhr - Aufbau: mm(0..59) hh day(0..28) wday(0=Mo, 1=Di, 2=Mi, 3=Do, 4=Fr, 5=Sa, 6=So) enforce_updates = True # Updates True, da der Crontab immer mit 1 ausführt und die Berechnung durchgeführt werden soll. eval = round((sh.ZAEHLER.HEIZUNG.BRENNERSTARTS() - sh.ZAEHLER.HEIZUNG.BRENNERSTARTS.db('min', '1d')), 1) [[[ANLAGEN_LEISTUNG]]] # Brenner Leistung # DATA TX: 41 5 0 1 A3 8F 2 3A # DATA RX: 41 7 1 1 A3 8F 2 0 0 3D --> 0000 = 0 --> Aus (Faktor 0.1) name = Anlagenleistung type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = anlagenleistung # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 41050001A38F023A# Ende direkt hinter dem Byte String [[[BRENNER_LEISTUNG]]] # Brenner Leistung # DATA TX: 41 5 0 1 A3 05 2 B0 # DATA RX: 41 7 1 1 A3 05 2 0 0 B3 --> 0000 = 0 --> Aus (Faktor 0.1) name = Brennerleistung type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = brennerleistung # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 41050001A30502B0# Ende direkt hinter dem Byte String [[[BETRIEBSSTUNDEN]]] # Information Kessel Brenner Betriebsstunden read 4-Byte 0..64000 0x08A7 # DATA TX: 41 5 0 1 8 A7 4 B9 # DATA RX: 41 9 1 1 8 A7 4 CE 47 DD 0 B0 --> 00DD47CE = 14501838 --> 4028,28h (Faktor 1/3600) name = Betriebsstunden [h] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = betriebsstunden # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 3600 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000108A704B9# Ende direkt hinter dem Byte String [[[[LETZTE_STUNDE]]]] name = Betriebsstunden innerhalb der letzten Stunde type = num cache = True # Berechnung stündlich crontab = 0 * * * = 1 # crontab Stündlich - Aufbau: mm(0..59) hh day(0..28) wday(0=Mo, 1=Di, 2=Mi, 3=Do, 4=Fr, 5=Sa, 6=So) enforce_updates = True # Updates True, da der Crontab immer mit 1 ausführt und die Berechnung durchgeführt werden soll. eval = round((sh.ZAEHLER.HEIZUNG.BETRIEBSSTUNDEN() - sh.ZAEHLER.HEIZUNG.BETRIEBSSTUNDEN.db('min', '1h')), 1) [[[[LETZTER_TAG]]]] name = Betriebsstunden innerhalb des letzten Tages type = num cache = True database@mysqldb = init # Berechnung täglich crontab = 0 0 * * = 1 # crontab Täglich 0 Uhr - Aufbau: mm(0..59) hh day(0..28) wday(0=Mo, 1=Di, 2=Mi, 3=Do, 4=Fr, 5=Sa, 6=So) enforce_updates = True # Updates True, da der Crontab immer mit 1 ausführt und die Berechnung durchgeführt werden soll. eval = round((sh.ZAEHLER.HEIZUNG.BETRIEBSSTUNDEN() - sh.ZAEHLER.HEIZUNG.BETRIEBSSTUNDEN.db('min', '1d')), 1) [[[BETRIEB_ZU_STARTS]]] name = Brennertstarts / Betriebsstunden gesamt type = num cache = True # Berechnung bei Änderung eval = round((sh.ZAEHLER.HEIZUNG.BRENNERSTARTS() / sh.ZAEHLER.HEIZUNG.BETRIEBSSTUNDEN()), 1) eval_trigger = ZAEHLER.HEIZUNG.BRENNERSTARTS | ZAEHLER.HEIZUNG.BETRIEBSSTUNDEN [[[[LETZTE_STUNDE]]]] name = Brennertstarts / Betriebsstunden innerhalb der letzten Stunde type = num cache = True # Berechnung stündlich crontab = 0 * * * = 1 # crontab Stündlich - Aufbau: mm(0..59) hh day(0..28) wday(0=Mo, 1=Di, 2=Mi, 3=Do, 4=Fr, 5=Sa, 6=So) enforce_updates = True # Updates True, da der Crontab immer mit 1 ausführt und die Berechnung durchgeführt werden soll. eval = round(((sh.ZAEHLER.HEIZUNG.BRENNERSTARTS() - sh.ZAEHLER.HEIZUNG.BRENNERSTARTS.db('min', '1h')) / (sh.ZAEHLER.HEIZUNG.BETRIEBSSTUNDEN() - sh.ZAEHLER.HEIZUNG.BETRIEBSSTUNDEN.db('min', '1h'))), 1) [[[[LETZTER_TAG]]]] name = Brennertstarts / Betriebsstunden innerhalb des letzten Tages type = num cache = True database@mysqldb = init # Berechnung täglich crontab = 0 0 * * = 1 # crontab Täglich 0 Uhr - Aufbau: mm(0..59) hh day(0..28) wday(0=Mo, 1=Di, 2=Mi, 3=Do, 4=Fr, 5=Sa, 6=So) enforce_updates = True # Updates True, da der Crontab immer mit 1 ausführt und die Berechnung durchgeführt werden soll. eval = round(((sh.ZAEHLER.HEIZUNG.BRENNERSTARTS() - sh.ZAEHLER.HEIZUNG.BRENNERSTARTS.db('min', '1d')) / (sh.ZAEHLER.HEIZUNG.BETRIEBSSTUNDEN() - sh.ZAEHLER.HEIZUNG.BETRIEBSSTUNDEN.db('min', '1d'))), 1) [[[KESSELSOLLTEMPERATUR]]] # Diagnose Kessel Kesselsolltemperatur read 2-Byte 0..127 0x555A # DATA TX: 41 5 0 1 55 5A 2 B7 # DATA RX: 41 7 1 1 55 5A 2 32 0 EC --> 0032 = 50 --> 5.0°C (Faktor: 0.1) name = Kesselsolltemperatur [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = kesselsolltemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 41050001555A02B7# Ende direkt hinter dem Byte String [[[KESSELTEMPERATUR]]] # Information Kessel Kesseltemperatur read 2-Byte 0..150 0x0810 # DATA TX: 41 5 0 1 8 10 2 20 # DATA RX: 41 7 1 1 8 10 2 7C 1 A0 --> 017C = 380 --> 38.0°C (Faktor: 0.1) name = Kesseltemperatur [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = kesseltemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000108100220# Ende direkt hinter dem Byte String [[[ABGASTEMPERATUR]]] # Abgastemperatur read 2-Byte 0..500 0x0816 # DATA TX: 41 5 0 1 8 16 2 26 # DATA RX: 41 7 1 1 8 16 2 7C 1 A6 --> 017C = 380 --> 38.0°C (Faktor: 0.1) name = Abgastemperatur [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = abgastemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000108160226# Ende direkt hinter dem Byte String [[[WARMWASSERSOLLTEMPERATUR]]] # Bedienung HK1 Betriebsdaten HK1 Warmwassersolltemperatur write 1-Byte 10 60 (90) 0x6300 # DATA TX: 41 5 0 1 63 0 1 6A # DATA RX: 41 7 1 1 63 0 1 36 A2 --> 36 = 54 --> 54°C (Faktor: 1) name = Warmwassertemperatur [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = warmwassersolltemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 1 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 410500016300016A# Ende direkt hinter dem Byte String [[[WARMWASSERISTTEMPERATUR]]] # Information Warmwasser Temperatur Speicher-/ Lade-/ Komfortsensor read 2-Byte 0 150 0x0812 # DATA TX: 41 5 0 1 8 12 2 22 # DATA RX: 41 7 1 1 8 12 2 1F 2 46 --> 021F = 543 --> 54.3°C (Faktor: 0.1) name = Warmwassertemperatur [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = warmwasseristtemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000108120222# Ende direkt hinter dem Byte String [[[WARMWASSERAUSTRITTSTEMPERATUR]]] # Information Warmwasser Austrittstemperatur read 2-Byte 0 150 0x0814 # DATA TX: 41 5 0 1 8 14 2 24 # DATA RX: 41 7 1 1 8 14 2 1F 2 48 --> 021F = 543 --> 54.3°C (Faktor: 0.1) name = Warmwasseraustrittstemperatur [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = warmwasserausttemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000108140224# Ende direkt hinter dem Byte String [[[BETRIEBSART]]] [[[[HK1]]]] # Information Heizkreis HK1 Aktuelle Betriebsart read 1-Byte 0 3 0x2500 # VALUE: 0 - Abschaltbetr. (Dauernd) 0x00 # VALUE: 1 - Red. Betrieb (Schaltuhr) 0x01 # VALUE: 2 - Normalbetrieb (Schaltuhr) 0x02 # VALUE: 3 - Normalbetrieb (Dauernd) 0x03 # DATA TX: 41 5 0 1 25 0 1 2C # DATA RX: 41 7 1 1 25 0 1 2 31 --> 02 = 2 --> Normalbetrieb (Schaltuhr) name = Betriebasart 0..3 type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = hk1betriebsart # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 3 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 1 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 410500012500012C# Ende direkt hinter dem Byte String [[[[HK2]]]] # Information Heizkreis HK2 Aktuelle Betriebsart read 1-Byte 0 3 0x2500 # VALUE: 0 - Abschaltbetr. (Dauernd) 0x00 # VALUE: 1 - Red. Betrieb (Schaltuhr) 0x01 # VALUE: 2 - Normalbetrieb (Schaltuhr) 0x02 # VALUE: 3 - Normalbetrieb (Dauernd) 0x03 # DATA TX: 41 5 0 1 35 0 1 3C # DATA RX: 41 7 1 1 35 0 1 2 41 --> 02 = 2 --> Normalbetrieb (Schaltuhr) name = Betriebasart 0..3 type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = hk2betriebsart # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 3 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 1 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 410500013500013C# Ende direkt hinter dem Byte String [[[HEIZART]]] [[[[HK1]]]] # Information Heizkreis HK1 Aktuelle Heizart read 1-Byte 0 3 0x2323 # VALUE: 0 - Abschaltbetrieb 0x00 # VALUE: 1 - Nur Warmwasser 0x01 # VALUE: 2 - Heizen und Warmwasser 0x02 # VALUE: 3 - Normalbetrieb (Dauernd) 0x03 # DATA TX: 41 5 0 1 23 23 1 4D # DATA RX: 41 7 1 1 23 23 1 2 52 --> 02 = 2 --> Heizen und Warmwasser name = Betriebasart 0..3 type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = hk1heizsart # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 3 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 1 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 410500012323014D# Ende direkt hinter dem Byte String [[[[HK2]]]] # Information Heizkreis HK2 Aktuelle Heizart read 1-Byte 0 3 0x3323 # VALUE: 0 - Abschaltbetrieb 0x00 # VALUE: 1 - Nur Warmwasser 0x01 # VALUE: 2 - Heizen und Warmwasser 0x02 # VALUE: 3 - Normalbetrieb (Dauernd) 0x03 # DATA TX: 41 5 0 1 33 23 1 5D # DATA RX: 41 7 1 1 33 23 1 2 62 --> 02 = 2 --> Heizen und Warmwasser name = Betriebasart 0..3 type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = hk2heizsart # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 3 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 1 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 410500013323015D# Ende direkt hinter dem Byte String [[[VORLAUFSOLLTEMPERATUR]]] [[[[HK1]]]] # Diagnose Heizkreis HK1 Vorlaufsolltemperatur read 2-Byte 0 127 0x2544 # DATA TX: 41 5 0 1 25 44 2 71 # DATA RX: 41 7 1 1 25 44 2 0 0 74 --> 0000 = 0 --> 0.0°C (Faktor: 0.1) name = Vorlaufsolltemperatur HK1 [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = hk1vorlaufsolltemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000125440271# Ende direkt hinter dem Byte String [[[[HK2]]]] # Diagnose Heizkreis HK2 Vorlaufsolltemperatur read 2-Byte 0 127 0x3544 # DATA TX: 41 5 0 1 35 44 2 81 # DATA RX: 41 7 1 1 35 44 2 0 0 84 --> 0000 = 0 --> 0.0°C (Faktor: 0.1) name = Vorlaufsolltemperatur HK1 [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = hk2vorlaufsolltemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000135440281# Ende direkt hinter dem Byte String [[[VORLAUFISTTEMPERATUR]]] [[[[HK1]]]] # Diagnose Heizkreis HK1 Vorlaufisttemperatur read 2-Byte 0 127 0x2544 # DATA TX: 41 5 0 1 29 0 2 31 # DATA RX: 41 7 1 1 29 0 2 0 034 --> 0000 = 0 --> 0.0°C (Faktor: 0.1) name = Vorlaufisttemperatur HK1 [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = hk1vorlaufisttemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000129000231# Ende direkt hinter dem Byte String [[[[HK2]]]] # Diagnose Heizkreis HK2 Vorlaufisttemperatur read 2-Byte 0 127 0x3544 # DATA TX: 41 5 0 1 39 0 2 41 # DATA RX: 41 7 1 1 39 0 2 0 0 44 --> 0000 = 0 --> 0.0°C (Faktor: 0.1) name = Vorlaufisttemperatur HK1 [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = hk2vorlaufisttemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 4105000139000241# Ende direkt hinter dem Byte String [[[PUMPE]]] [[[[HK1]]]] # Diagnose Heizkreis HK1 Umwälzpumpe read 1-Byte 0 1 0x2906 # DATA TX: 41 5 0 1 29 06 1 36 # DATA RX: 41 7 1 1 29 06 1 1 3A --> 1 --> TRUE name = Umwälzpumpe HK1 type = bool cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = hk1umwaelzpumpe # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = bool # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginvcode = 4105000129060136# Ende direkt hinter dem Byte String [[[[HK2]]]] # Diagnose Heizkreis HK2 Umwälzpumpe read 1-Byte 0 1 0x2906 # DATA TX: 41 5 0 1 39 06 1 46 # DATA RX: 41 7 1 1 39 06 1 1 4A --> 1 --> TRUE name = Umwälzpumpe HK1 type = bool cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = hk2umwaelzpumpe # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = bool # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginvcode = 4105000139060146# Ende direkt hinter dem Byte String [[[[WARMWASSER]]]] # Information Warmwasser Speicherladepumpe read 1-Bit 0 1 0x6513 # DATA TX: 41 5 0 1 65 13 1 7F # DATA RX: 41 7 1 1 65 13 1 1 83 --> 1 --> TRUE name = Warmwasserpumpe type = bool cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = warmwasserpumpe # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = bool # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginvcode = 410500016513017F# Ende direkt hinter dem Byte String [[[[ZIRKULATION]]]] # Zirkulationspumpe read 1-Byte TRUE/FALSE 0x6515 # DATA TX: 41 5 0 1 65 15 1 81 # DATA RX: 41 7 1 1 65 15 1 0 83 --> 0 --> FALSE name = Zirkulations Pumpe type = bool cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = ausgang28_zirkpumpe # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = bool # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginvcode = 4105000165150181# Ende direkt hinter dem Byte String [[[[SOLAR]]]] # Solarpumpe read 1-Byte TRUE/FALSE 0x6552 # DATA TX: 41 5 0 1 65 52 1 BE # DATA RX: 41 7 1 1 65 52 1 1 C2 --> 1 --> TRUE name = Solar Pumpe type = bool cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = solarpump # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = bool # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginvcode = 41050001655201BE# Ende direkt hinter dem Byte String [[[[INTERN]]]] # Interne Pumpe # DATA TX: 41 5 0 1 76 60 1 DD # DATA RX: 41 7 1 1 76 60 1 1 E1 --> 1 --> TRUE name = Interne Pumpe type = bool cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = intern # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = bool # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginvcode = 41050001766001DD# Ende direkt hinter dem Byte String [[[SOLARKOLLEKTORTEMPERATUR]]] # Solar Kollektortemperatur read 2-Byte -50..240 0x6564 # DATA TX: 41 5 0 1 65 64 2 D1 # DATA RX: 41 7 1 1 65 64 2 2 0 D6 --> 0002 = 2 --> 0.2°C (Faktor 0.1) name = Solarkollektor Temperatur [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = solarkollektortemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = signed # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 41050001656402D1# Ende direkt hinter dem Byte String [[[SOLARSPEICHERTEMPERATUR]]] # Solar Speichertemperatur read 2-Byte 0..130 0x6566 # DATA TX: 41 5 0 1 65 66 2 D3 # DATA RX: 41 7 1 1 65 66 2 2 0 D8 --> 0002 = 2 --> 0.2°C (Faktor 0.1) name = Solarspeicher Temperatur [°C] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = solarspeichertemp # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 10 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 41050001656602D3# Ende direkt hinter dem Byte String [[[SOLARBETRIEBSSTUNDEN]]] # Solar Betriebsstunden read 2-Byte 0..64000 0x6568 # DATA TX: 41 5 0 1 65 68 2 D5 # DATA RX: 41 9 1 1 65 68 2 F 0 E7 --> 000F = 15 --> 15 (Faktor 1) name = Solar Betriebsstunden [h] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = solarbetriebsstunden# Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 1 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 41050001656802D5# Ende direkt hinter dem Byte String [[[SOLARWAERMEMENGE]]] # Solar Wärmemenge read 2-Byte 0..64000 0x6560 # DATA TX: 41 5 0 1 65 60 2 CD # DATA RX: 41 9 1 1 65 60 2 F 0 DF --> 000F = 15 --> 15kWh (Faktor 1) name = Solar Wärmemenge [kWh] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = solarwaermemenge # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 1 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 41050001656002CD# Ende direkt hinter dem Byte String [[[SOLARAUSBEUTE]]] # Solar Ausbeute heute read 4-Byte 0..1150000 0xCF30 # DATA TX: 41 5 0 1 CF 30 4 09 # DATA RX: 41 9 1 1 CF 30 4 F 0 0 0 1B --> 0000.000F = 15 --> 15Wh (Faktor 1) name = Solar Ausbeute heute [Wh] type = num cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = solarausbeute # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = num # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginsigned = unsigned # Ist der Analogdatentyp mit Vorzeichen behaftet (Möglichkeiten "signed", "unsigned") pluginreduction = 1 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginfactor = 1 # Übertragener Integerwert muss durch den gegebenen Faktor geteilt werden bevor der Wert im Item gespeichert wird pluginvcode = 41050001CF300409# Ende direkt hinter dem Byte String [[[FROSTGEFAHR]]] # Frostgefahr read 1-Byte TRUE/FALSE 0x2510 # DATA TX: 41 5 0 1 25 10 1 3C # DATA RX: 41 7 1 1 25 10 1 0 3F --> 0 --> FALSE name = Frostgefahr type = bool cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = frostgefahr # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = bool # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginreduction = 3 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginvcode = 410500012510013C# Ende direkt hinter dem Byte String [[[SAMMELSTOERUNG]]] # Sammelstoerung read 1-Byte TRUE/FALSE 0x0A82 # DATA TX: 41 5 0 1 0A 82 1 93 # DATA RX: 41 7 1 1 0A 82 1 0 96 --> 0 --> FALSE name = Sammelstoerung type = bool cache = True database@mysqldb = init pluginusage = viessmann # Wird vom angegebenen Plugin verwendet plugintagid = sammelstoerung # Im Plugin wird das Item im Dictionary unter dem defineirten Namen geführt. So ist es unabhängig vom Item Namen und Pfad plugintype = bool # Datentyp dieses Items (num=Numerische Werte, bool=Binärwert) pluginreduction = 3 # Untersetzung: 1=bei jedem Aufruf den Wert auslesen, 2= bei jedem 2. Aufruf, 3=bei jedem 3. Aufruf ... pluginvcode = 410500010A820193# Ende direkt hinter dem Byte String [[[ICON_STATUS]]] # 0 = Störung Icon = control_x.svg (rot) # 1 = Solarpumpe Icon = sani_solar.svg (weiss) # 2 = Brenner Icon = sani_boiler_temp.svg (weiss) # 3 = Brenner aus Icon = sani_boiler_temp.svg (weiss) name = Iconstatus für die Heizung type = num cache = True eval = 0 if (sh.ZAEHLER.HEIZUNG.SAMMELSTOERUNG() == True) else 1 if (sh.ZAEHLER.HEIZUNG.PUMPE.SOLAR() == True) else 2 if (sh.ZAEHLER.HEIZUNG.BRENNER_LEISTUNG() > 0.0) else 3 eval_trigger = ZAEHLER.HEIZUNG.SAMMELSTOERUNG | ZAEHLER.HEIZUNG.PUMPE.SOLAR | ZAEHLER.HEIZUNG.BRENNER_LEISTUNG
\plugins\viessmann\__init__.py
Code:
#!/usr/bin/env python3 # vim: set encoding=utf-8 tabstop=4 softtabstop=4 shiftwidth=4 expandtab # # Viessmann Heizung, Auswertung # Vitodens200 / 300 mit Vitotronic 200 (HO1) # Gas-Brennwertkessel mit witterungsgeführter Kessel- und Heizkreisregelung für 2 Heizkreise mit Mischer und 1 Heizkreis ohne Mischer # 20CB = VScotHO1 # # Version | Datum | Author | Beschreibung # --------|------------|--------|--------------------------------------------------------- # 1.00 | 24.11.2016 | LC | Initialversion # 1.01 | 29.12.2017 | LC | Logger besser angepasst self.logger = logging.getLogger(__name__), initialisiert in def ___init___ # # # Beispiel # # Senden 41 5 0 1 55 25 2 82 # Read Request -- - - - ----- - -- # | | | | | | +------- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]5+0+1+55+25+2 = [dez]5+0+1+(5x16)+5+(2x16)+5+2 = 130dez = 82hex # | | | | | +---------- XX Anzahl der Bytes, die in der Antwort erwartet werden # | | | | +-------------- XX XX 2 byte Adresse der Daten oder Prozedur # | | | +------------------ XX 01 = ReadData, 02 = WriteData, 07 = Function Call # | | +-------------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler # | +---------------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) # +------------------------ Telegramm-Start-Byte # # Empfangen : 6 ----------------------- OK (Antwort auf 0x16 0x00 0x00 und auf korrekt empfangene Telegramme) # 5 ----------------------- Schnittstelle ist aktiv und wartet auf eine Initialisierung # 15 ----------------------- Schnittstelle meldet einen Fehler zurück # # 41 7 1 1 55 25 2 EF 0 74 # -- - - - ----- - ---- -- # | | | | | | | +-- Prüfsumme (Summe über alley Bytes ohne die 41; [hex]7+1+1+55+25+2+EF+0 = [dez]7+1+1+(5x16)+5+(2x16)+5+2+(14*16)+(15*16)+0 = [dez]7+1+1+(80)+5+(32)+5+2+(224)+(15)+0 = 372dez = 1.74hex) # | | | | | | +------ Wert # | | | | | +---------- XX Anzahl der Bytes, die in der Antwort erwartet werden # | | | | +-------------- XX XX 2 byte Adresse der Daten oder Prozedur # | | | +------------------ XX 01 = ReadData, 02 = WriteData, 07 = Function Call # | | +-------------------- XX 00 = Anfrage, 01 = Antwort, 03 = Fehler # | +---------------------- Länge der Nutzdaten (Anzahl der Bytes zwischen dem Telegramm-Start-Byte (0x41) und der Prüfsumme) # +------------------------ Telegramm-Start-Byte # # # Protokollbeschreibung # http://openv.wikispaces.com/Protokoll+300 import logging import serial import time import binascii # Plugin Klasse class viessmann(): # Def: __init__ # Beschreibung von: https://github.com/mknx/smarthome/wiki/Write-a-plugin-5-minutes # The function init is called once when smarthome.py initializes before the # items are loaded. Here you place the code that is needed to initialize you # plugin. For example you can open a serial port if you need to communicate # to an external device, open files, initialize other variables you need and # so on. The function receives the parameter “smarthome” which gives access to # the smarthome.py functions. You should save the value in a variable for later # use like in the example above. Other parameter values are received from the # file plugin.conf. You can default values for the case that the parameter is # not defined in the plugin.conf file. It is a good practice to log your plugin # name to the smarthome.log file. def __init__(self, smarthome, serialport="/dev/ttyUSB_HEIZUNG", update_cycle="900"): # Logger festlegen self.logger = logging.getLogger(__name__) # Eintrag in den Log self.logger.info('Plugin viessmann - Initialisierung gestartet') # Grundwerte festlegen self._sh = smarthome self._update_cycle = int(update_cycle) self._serial = serial.Serial( port=serialport, timeout=1, baudrate=4800, bytesize=serial.EIGHTBITS, parity=serial.PARITY_EVEN, stopbits=serial.STOPBITS_TWO) self._items = dict() self._lastbyte = b'' self._lastbytetime = time.time() # Untersetzung: Aktueller Zähler, 0=Init, 1=bei jedem Zyklus, 2=jeden 2. Zyklus, 3=jeden 3. Zyklus # Der Zähler ist nur bei Systemstart = 0 # Anschließend zählt dieser immer von 1..maxreduction self._actreduction = 0 # Untersetzung: Maximaler Wert, der über die Konfig projektiert wurde. Wird dynamisch ermittelt # Begrenzt auch den actreduction Zähler, dieser wird läuft immer von 1..maxreduction self._maxreduction = 0 # Def: run # Beschreibung von: https://github.com/mknx/smarthome/wiki/Write-a-plugin-5-minutes # The function run is called once when smarthome.py starts. # Run is executed after all items are loaded. # You need to set the variable self.alive=True here. def run(self): # Eigenen Scheduler Eintrag erzeugen und diese Logik alle 2sek # selbständig aufrufen, um keine Umdrehung des Zählers zu verpassen. self._sh.scheduler.add( 'viessmann', self._readCyclicData, cycle=self._update_cycle) # Alive Variable für das System auf True setzen self.alive = True # Def: stop # Beschreibung von: https://github.com/mknx/smarthome/wiki/Write-a-plugin-5-minutes # This is called when smarthome.py shuts down. # This is the right place to close files and data connections. # You need to set the variable self.alive=False here. def stop(self): # Alive Variable für das System auf False setzen self.alive = False # Serielle Schnittstelle schließen self._serial.close() # Scheduler selbständig entfernen self._sh.scheduler.remove('viessmann') # Def: parse_item # Beschreibung von: https://github.com/mknx/smarthome/wiki/Write-a-plugin-5-minutes # The function parse_item is called for each item during startup when # smarthome.py reads the item.conf file. You can access item parameters # and start according action here. For example you have the following # item defined in …/items/smarthome.conf # # Items für dieses Plugin verfügen über mehrere Attribute # + pluginusage = viessmann # + plugintagid = z.B. brennerstarts # + pluginreduction = 1 # + ... # Ist es ein Item für dieses Plugin so trägt es auch ein weiteres Attribut namens "plugintagid" # Hierüber können mehrere zu einem Plugin gehörende Items klar definiert und verwendet werden # ohne, dass der eigentliche Item Name/Pfad eine bestimmte Nomenklatur aufweisen müssen. def parse_item(self, item): # Prüfung ob ein Item existiert mit dem attribut "pluginusage" if (('pluginusage' in item.conf) and ('plugintagid' in item.conf) and ('pluginvcode' in item.conf) and ('pluginreduction' in item.conf)): # Prüfung ob dieses Attribut den Namen "viessmann" trägt if ((item.conf['pluginusage'] == 'viessmann') and ('pluginvcode' in item.conf)): # String aus der Config wird in einen bytestring gewandelt # Beispiel: "4105000108A704B9" --> b'\x41\x05\x00\x01\x08\xA7\x04\xB9' vcodebytestring = binascii.a2b_hex(item.conf['pluginvcode']) if (self._checkChecksum(vcodebytestring) == True): # Speichern des Items unter seinem "plugintagid" Namen im # Plugin eigenen Item-Dictionary self._items[item.conf['plugintagid']] = item # Maximale Untersetzung ermitteln anhand der Daten aus der Config # Dient dazu den aktuellen Zähler immer wieder von 1 zu starten. self._maxreduction = max(self._maxreduction, int(item.conf['pluginreduction'])) # Eintrag in den Log self.logger.info('Plugin viessmann - Item added: {}'.format(item.conf['plugintagid'])) else: # Checksumme für das Item (Sendecode) ist nicht korrekt messagetext = 'Plugin viessmann - Falsche Checksumme für den vcode (Sendecode {}}, Item not added: {}, '.format(vcodebytestring, item.conf['plugintagid']) self.logger.error(messagetext) elif (('pluginusage' in item.conf) and ('pluginfct' in item.conf) ): if ((item.conf['pluginusage'] == 'viessmann') and (item.conf['pluginfct'] == 'lastreadtime')): self._itemlastread = item elif ((item.conf['pluginusage'] == 'viessmann') and (item.conf['pluginfct'] == 'readtrigger')): return self.update_item elif ((item.conf['pluginusage'] == 'viessmann') and (item.conf['pluginfct'] == 'setcirculationpump')): return self.update_item return None # Def: parse_logic # Nur der Vollständigkeit halber hier mit aufgelistet def parse_logic(self, logic): if 'xxx' in logic.conf: # self.function(logic['name']) pass # Def: update_item # Nur der Vollständigkeit halber hier mit aufgelistet def update_item(self, item, caller=None, source=None, dest=None): #if caller != 'plugin': self.logger.info("Plugin viessmann - Item update item: {0}".format(item.id())) if (('pluginusage' in item.conf) and ('pluginfct' in item.conf)): # Prüfung ob dieses Attribut den Namen "viessmann" trägt und es sich um das # Item zum erneuten Lesen handelt if ((item() == True) and (item.conf['pluginusage'] == 'viessmann') and (item.conf['pluginfct'] == 'readtrigger')): # Damit alle Werte gelesen werden muss die Untersetzung # auf den Inititialisierungswert gesetzt werden. self._actreduction = 0 # Lese Funktion manuell ausführen self._readCyclicData() # Rücksetzen des Trigger Items item('off') if ((item.conf['pluginusage'] == 'viessmann') and (item.conf['pluginfct'] == 'setcirculationpump')): # Zirkulationspumpe schalten self._writeCircPump(item()) # Lese Funktion manuell ausführen self._readCyclicData() def _checkChecksum(self, bytestring): # Returnvalue vorbelegen (Checksumme falsch) returnvalue = False # Checksummen Variable für die Berechnung checksum = 0 # Es wurde das Startbyte gefunden startbytefound = False # Sofern die Länge vom bytestring größer als # die Mindestlänge 2 ist, kann die Aktion # ausgeführt werden. bytestringwork = bytestring if ((len(bytestringwork)) > 1): # Bytestring Byte für Byte auswerten. Wenn nur # noch ein Byte übrig ist, dann stoppen. Dies # ist dann das Checksummen Byte while ((len(bytestringwork)) > 1): # Erstes Byte zwischenspeichern leftbyte = bytestringwork[:1] # Sofern das Startbyte bereits gefunden wurde # muss das aktuelle Byte mit in die Berechnung # einbezogen werden. if (startbytefound == True): # Checksumme berechnen. Sie bildet sich aus der # Aufsummierung der einzelenen Bytes checksum = checksum + ord(leftbyte) # Suche nach dem Startbyte b'\x41' elif (leftbyte == b'\x41'): # Es handelt sich um das Startbyte. # Ab dem nächsten Byte handelt es sich um # Nutzdaten, die mit in die Checksumme einfließen. startbytefound = True # Bytestring um das erste Byte verkürzen bytestringwork = bytestringwork[1:] # Checksumme prüfen if ((checksum % 256) == ord(bytestringwork)): # Berechnete Checksumme stimmt mit der angegebenen Checksumme überein returnvalue = True else: # Checksummen passen nicht zusammen messagetext = 'Plugin viessmann - Checksumme für Bytestring ist fehlerhaft. Bytestring : {}, CRC byte : {}, CRC Berechnet : {}, CRC im String : {}'.format(bytestring, bytestringwork, checksum, ord(bytestringwork)) self.logger.error(messagetext) else: messagetext = 'Plugin viessmann - Checksumme kann nicht berechnet werden. Bytestring zu kurz. Bytestring : {}'.format(bytestring) self.logger.error(messagetext) # Rückgabewert der Funktion zurückgeben # True = Checksumme ist okay # False = Checksumme falsch return returnvalue def _readByte(self): self.logger.debug('Plugin viessmann - Read byte') # Standard Rückgabewert definieren (leeres Byte) returnvalue = b'' # Es wird per Schleife x-mal gelesen j = 0 while (j < 5): readbyte = self._serial.read(1) self.logger.debug('Plugin viessmann --------- Read byte: {}'.format(readbyte)) # Prüfung, ob ein Byte empfangen wurde if (readbyte != b''): # Ein Byte wurde empfangen. Dieses wird gespeichert self._lastbyte = readbyte # Zeit des Empfangs ebenfalls speichern self._lastbytetime = time.time() # Schleife abbrechen break # Schleifenzähler inkrementieren j = j + 1 # Wert zurückgeben. Wenn kein Byte empfangen wurde, wird b'' zurückgeliefert. return returnvalue def _writeBytes(self, bytestring): self.logger.debug('Plugin viessmann - Write bytestring: {}'.format(bytestring)) # Sendepuffer leeren (Sicherheitsfunktion) self._serial.flushInput() # Übergebenen Bytestring senden self._serial.write(bytestring) # Sendepuffer leeren self._serial.flushInput() def _initCommunication(self): self.logger.info('Plugin viessmann - Init Communication') # Standard Rückgabewert definieren (Initialisierung fehlgeschlagen) returnvalue = False # Merker: Wurde der Initialisierungsstring b'\x16\x00\x00' gesendet. # Wird hierauf dann mit b'\x06' geantwortet ist die Komunikation aufgebaut. initstringsent = False # Schnittstelle zurücksetzen self._writeBytes(b'\x04') # Lesen eines Bytes self._readByte() # Initialisierung ca. 10mal probieren i = 0 while (i < 10): if ((initstringsent == True) and (self._lastbyte == b'\x06')): # Schnittstelle hat auf den Initialisierungsstring mit OK # geantwortet. Die Abfrage von Werten kann beginnen. Diese # Funktion meldet hierzu True zurück. returnvalue = True # Schleife abbrechen, da Initialisierung erfolgreich break if ((self._lastbyte == b'\x06') or (self._lastbyte == b'\x05')): # Schnittstelle ist zurückgesetzt und wartet auf Daten # b'\x05' = Warten auf Initialisierungsstring # b'\x06' = Schnittstelle initialisiert # In beiden Fällen wird zur Sicherheit der Initialisierungsstring gesendet. self._writeBytes(b'\x16\x00\x00') # Merker setzen: Initialisierungstring wurde zuletzt gesendet initstringsent = True elif (self._lastbyte == b'\x15'): # Die Schnittstelle hat einen Fehler zurückgemeldet. messagetext = 'Plugin viessmann - Die Schnittstelle hat einen Fehler zurückgemeldet (\x15), Schleifenindex {}'.format(i) self.logger.error(messagetext) # Schnittstelle zurücksetzen self._writeBytes(b'\x04') # Merker rücksetzen: Initialisierungstring wurde nicht zuletzt gesendet initstringsent = False else: # Letzter Wert ist undefiniert # Schnittstelle zurücksetzen self._writeBytes(b'\x04') # Merker rücksetzen: Initialisierungstring wurde nicht zuletzt gesendet initstringsent = False # Lesen eines Bytes self._readByte() # Counter hochzählen i = i + 1 # Zurückgeben, ob die Initialisierung erfolgreich war # True = Initialisierung erfolgreich. Letztes Byte war \x06 und nicht zu lange her # False = Initialisierung fehlgeschlagen. return returnvalue def _setItem(self, item, databytes): # Standard Rückgabewert definieren (Schreiben des Items nicht erfolgreich) returnvalue = False if (len(databytes) > 0): # In Abhängigkeit vom Datentyp die Datenbytes auswerten und das Item schreiben if (item.conf['plugintype'] == 'num'): # Faktor für das Item ermitteln factor = float(item.conf['pluginfactor']) # Initialisierung der internen Variablen longvalue = 0 floatvalue = 0.0 byteindex = 0 databytes_work = databytes while (len(databytes_work) > 0): # Erstes Byte zwischenspeichern leftbyte = databytes_work[:1] # Wert des Bytes ermitteln value = int(ord(leftbyte)) # Gewichten / Multiplizieren if (byteindex > 0): value = int(value * pow(256, byteindex)) # Aufaddieren der einzelnen Bytes longvalue = longvalue + value # Byteindex hochzählen, damit das Byte mit # netsprechend mit 1, 256, 65536, 16777216, usw. # multipliziert werden kann byteindex = byteindex + 1 # Bytestring um das erste Byte verkürzen databytes_work = databytes_work[1:] # Signed/Unsigned berücksichtigen if (item.conf['pluginsigned'] == 'signed'): if ((byteindex == 1) and (longvalue > 127)): longvalue = (256 - longvalue) * (-1) elif ((byteindex == 2) and (longvalue > 32767)): longvalue = (65536 - longvalue) * (-1) #elif ((byteindex == 4) and (longvalue > *2147483647)): # longvalue = (*4294967295 - longvalue) * (-1) # Faktor berücksichtigen floatvalue = round(float(longvalue / factor), 2) # Item schreiben item(floatvalue) # Debug Meldung über das erfolgreiche Schreiben self.logger.debug('Plugin viessmann - Analogwert geschrieben : {}, Float-Wert : {}, Long-Wert : {}, Rohbytes : {}'.format(item.conf['plugintagid'], floatvalue, longvalue, databytes)) # Item korrek geschrieben returnvalue = True elif (item.conf['plugintype'] == 'bool'): # Datenbyte Binärzustand prüfen if ((databytes == b'\x01') or (databytes == b'\x03')): # Item aktivieren item('on') # Debug Meldung über das erfolgreiche Schreiben self.logger.debug('Plugin viessmann - Binärwert geschrieben : {}, Wert : {}, Rohbytes : {}'.format(item.conf['plugintagid'], 'True', databytes)) # Item korrek geschrieben returnvalue = True elif ((databytes == b'\x00') or (databytes == b'\x02')): # Item deaktivieren item('off') # Debug Meldung über das erfolgreiche Schreiben self.logger.debug('Plugin viessmann - Binärwert geschrieben : {}, Wert : {}, Rohbytes : {}'.format(item.conf['plugintagid'], 'False', databytes)) # Item korrek geschrieben returnvalue = True else: messagetext = 'Plugin viessmann - Item kann nicht geschrieben werden, da Binärwert nicht klar. Read value : {}, Datenbytes : {}'.format(item.conf['plugintagid'], databytes) self.logger.error(messagetext) else: messagetext = 'Plugin viessmann - Item kann nicht geschrieben werden, da Datentyp undefiniert. Read value : {}, Datentyp : {}'.format(item.conf['plugintagid'], item.conf['plugintype']) self.logger.error(messagetext) else: messagetext = 'Plugin viessmann - Item kann nicht geschrieben werden, übergebener Bytestring leer ist. Read value : {}'.format(item.conf['plugintagid']) self.logger.error(messagetext) # Rückgabewert ausgeben # True : Schreiben des Items war erfolgreich # False : Schreiben des Items fehlerhaft return returnvalue def _readValue(self, item): # self.logger.debug('Plugin viessmann - Read value : {}, Type : {}'.format(item.conf['plugintagid'], item.conf['plugintype'])) # Standard Rückgabewert definieren (Lesen nicht erfolgreich) returnvalue = False # Übergebenen Sende Bytestring auswerten vcodestring = item.conf['pluginvcode'] # String aus der Config wird in einen bytestring gewandelt # Beispiel: "4105000108A704B9" --> b'\x41\x05\x00\x01\x08\xA7\x04\xB9' vcodebytestring = binascii.a2b_hex(vcodestring) # Vorletztes Byte ermitteln # Anfrage 41 05 00 01 55 25 02 82 # -- # LÄNGE vcodelengthbyte = vcodebytestring[-2:] vcodelengthbyte = vcodelengthbyte[:1] # Aus dem Byte den ASCII-Zahlenwert ermitteln. Diese Länge wird für den Dateninhalt der Antwort genutzt # Es müssen noch die Zusatzdaten mit addiert werden (diese sind immer +9) # Antwort 06 41 07 01 01 55 25 02 EF 00 74 # -- ----- -- # OK DATEN CS vcode_responselen = ord(vcodelengthbyte) vcode_responsetotallen = vcode_responselen + 9 # ByteString für den Rückgabewert bytestring = b'' # Schnittstelle ist bereit. Kommando kann gesendet werden. vcodestring = item.conf['pluginvcode'] # String aus der Config wird in einen bytestring gewandelt # Beispiel: "4105000108A704B9" --> b'\x41\x05\x00\x01\x08\xA7\x04\xB9' vcodebytestring = binascii.a2b_hex(vcodestring) self._writeBytes(vcodebytestring) # Rückgabebytestring einlesen k = 0 while k < vcode_responsetotallen: # Byte von Schnittstelle lesen self.logger.debug('Plugin viessmann --------- Read byte for : {}, index k : {}, kmax : {}, responselen : {}, lengthbyte : {}'.format(vcodebytestring, k, vcode_responsetotallen, vcode_responselen, vcodelengthbyte)) readbyte = self._readByte() # Erstes und letztes Byte muss b'\x06' sein (Bedeutung: OK der Daten) # Wenn dies nicht der Fall ist, wird abgebrochen #if ((k == 0) or (k == (vcode_responsetotallen - 1))): if (k == 0): if not (self._lastbyte == b'\x06'): # Bytestring zurücksetzen bytestring = b'' break else: # Schreiben des Readbyte Strings bestehend aus # allen gelesenen Bytes bis auf b'\x06' am # Anfang und am Ende (Bsp.: 41 07 01 01 55 25 02 EF 00 74) bytestring = bytestring + self._lastbyte # Schleifenzähler inkrementieren k = k + 1 self.logger.debug('Plugin viessmann --------- Bytestring : {}'.format(bytestring)) # Prüfung ob alle Daten gelesen wurden. Hierzu kann geprüft werden # ob die Länge der Bytestring der erwarteten Länge minus die beiden # b'\x06' Bytes am Anfang und Ende entspricht. if (len(bytestring) == (vcode_responsetotallen - 1)): # Entspricht das erste Byte b'\x41' bytestring_extract = bytestring[:1] if (bytestring_extract == b'\x41'): # Bytestring startet mit dem Identifier für den Telegramstart # Mit dem String kann weiter gearbeitet werden # Prüfung ob die Checksumme in Ordnung ist if (self._checkChecksum(bytestring) == True): # Gelesene Bytes aus dem Array auswerten # Datenbytes extrahieren bytestring_extract = bytestring[(((-1) * vcode_responselen) - 1):] bytestring_extract = bytestring_extract[:vcode_responselen] # messagetext = 'Plugin viessmann - Datenbytes extrahiert. Read value : {}, Databytes : {}'.format(item.conf['plugintagid'], bytestring_extract) # self.logger.debug(messagetext) # Wert aus den datenbytes ermitteln und mit Faktor in das Item schreiben self._setItem(item, bytestring_extract) # Wert wurde erfolgreich gelesen und das Item geschrieben returnvalue = True else: messagetext = 'Plugin viessmann - Checksumme fehlerhaft. Read value : {}, Readed bytestring : {}'.format(item.conf['plugintagid'], bytestring) self.logger.error(messagetext) else: messagetext = 'Plugin viessmann - Gelesener Bytestring startet nicht mit \x41. Read value : {}, Readed bytestring : {}'.format(item.conf['plugintagid'], bytestring) self.logger.error(messagetext) else: messagetext = 'Plugin viessmann - Gelesener Bytestring hat nicht die korrekte Länge. Read value : {}, Erwartete Länge : {}, Readed bytestring : {}'.format(item.conf['plugintagid'], (vcode_responsetotallen - 1), bytestring) self.logger.error(messagetext) # Rückgabe, ob der Wert erfolgreich gelesen und das Item geschrieben wurde return returnvalue # Schreiben der Zirkulationspumpe # Dummy: Wert wird nicht geschrieben. Dient nur dazu zu prüfen, ob die Funktion aufgerufen wird, wenn das Item sich ändert # Soll der Wert tatsächlich geschrieben werden, so muss die vollständige Implementierung entsprechend umbenannt werden. # Siehe direkt hierunter # _writeCircPump() --> _writeCircPump_DUMMY() und _writeCircPump_DEACTIVE() --> _writeCircPump() def _writeCircPump(self, seton): self.logger.info('Plugin viessmann - WRITE TEST (Wert wird nicht geschrieben) - Write circulation pump : {}'.format(seton)) def _writeCircPump_DEACTIVE(self, seton): self.logger.info('Plugin viessmann - WRITE - Write circulation pump : {}'.format(seton)) # Standard Rückgabewert definieren (Lesen nicht erfolgreich) returnvalue = False if (seton == True): # Code on vcodestring = "410600026515010386" else: vcodestring = "410600026515010285" # String aus der Config wird in einen bytestring gewandelt # Beispiel: "410600026515010184" --> b'\x41\x06\x00\x02\x65\x15\x01\x01\x84' vcodebytestring = binascii.a2b_hex(vcodestring) # Vorvorletztes Byte ermitteln # Anfrage 41 06 00 02 65 15 01 03 86 # -- # LÄNGE vcodelengthbyte = vcodebytestring[-3:] vcodelengthbyte = vcodelengthbyte[:1] # Aus dem Byte den ASCII-Zahlenwert ermitteln. Diese Länge wird für den Dateninhalt der Antwort genutzt # Es müssen noch die Zusatzdaten mit addiert werden (diese sind immer +9) # Antwort 06 41 06 01 02 65 15 01 01 85 # -- -- -- -- # OK DA CS vcode_responselen = ord(vcodelengthbyte) vcode_responsetotallen1 = vcode_responselen + 9 vcode_responsetotallen = 10 # ByteString für den Rückgabewert bytestring = b'' # Schnittstelle ist bereit. Kommando kann gesendet werden. vcodestring = vcodestring # String aus der Config wird in einen bytestring gewandelt # Beispiel: "410600026515010184" --> b'\x41\x06\x00\x02\x65\x15\x01\x01\x84' vcodebytestring = binascii.a2b_hex(vcodestring) self.logger.error('Plugin viessmann - WRITE - --------- Write zirkulation, sende bytestring : {}, erwartete antwortlänge : {}'.format(vcodebytestring, vcode_responsetotallen1)) self._writeBytes(vcodebytestring) # Rückgabebytestring einlesen k = 0 while k < vcode_responsetotallen: # Byte von Schnittstelle lesen self.logger.debug('Plugin viessmann - WRITE - --------- Write zirkulation, Read byte for : {}, index k : {}, kmax : {}, responselen : {}, lengthbyte : {}'.format(vcodebytestring, k, vcode_responsetotallen, vcode_responselen, vcodelengthbyte)) readbyte = self._readByte() self.logger.debug('Plugin viessmann - WRITE - --------- Write zirkulation, Readed byte : {}'.format(readbyte)) # Erstes und letztes Byte muss b'\x06' sein (Bedeutung: OK der Daten) # Wenn dies nicht der Fall ist, wird abgebrochen #if ((k == 0) or (k == (vcode_responsetotallen - 1))): if (k == 0): if not (self._lastbyte == b'\x06'): # Bytestring zurücksetzen bytestring = b'' break else: # Schreiben des Readbyte Strings bestehend aus # allen gelesenen Bytes bis auf b'\x06' am # Anfang und am Ende (Bsp.: 41 06 01 02 65 15 01 01 85) bytestring = bytestring + self._lastbyte # Schleifenzähler inkrementieren k = k + 1 self.logger.debug('Plugin viessmann - WRITE - --------- Write zirkulation, Empfangs bytestring : {}'.format(bytestring)) # Prüfung ob alle Daten gelesen wurden. Hierzu kann geprüft werden # ob die Länge der Bytestring der erwarteten Länge minus die beiden # b'\x06' Bytes am Anfang und Ende entspricht. if (len(bytestring) == (vcode_responsetotallen - 1)): # Entspricht das erste Byte b'\x41' bytestring_extract = bytestring[:1] if (bytestring_extract == b'\x41'): # Bytestring startet mit dem Identifier für den Telegramstart # Mit dem String kann weiter gearbeitet werden # Prüfung ob die Checksumme in Ordnung ist if (self._checkChecksum(bytestring) == True): # Gelesene Bytes aus dem Array auswerten # Datenbytes extrahieren bytestring_extract = bytestring[(((-1) * vcode_responselen) - 1):] bytestring_extract = bytestring_extract[:vcode_responselen] messagetext = 'Plugin viessmann - WRITE - Datenbytes extrahiert. Read Databytes : {}'.format(bytestring_extract) self.logger.info(messagetext) # Wert wurde erfolgreich gelesen und das Item geschrieben returnvalue = True else: messagetext = 'Plugin viessmann - WRITE - Checksumme fehlerhaft. Readed bytestring : {}'.format(bytestring) self.logger.error(messagetext) else: messagetext = 'Plugin viessmann - WRITE - Gelesener Bytestring startet nicht mit \x41. Readed bytestring : {}'.format(bytestring) self.logger.error(messagetext) else: messagetext = 'Plugin viessmann - WRITE - Gelesener Bytestring hat nicht die korrekte Länge. Erwartete Länge : {}, Readed bytestring : {}'.format((vcode_responsetotallen - 1), bytestring) self.logger.error(messagetext) # Rückgabe, ob der Wert erfolgreich gelesen und das Item geschrieben wurde return returnvalue # Def: _readCyclicData(zyklische Funktion) # Zu Beginn werden alle Werte ausgelesen, anschließend mit entsprechenden Untersetzungen # die wichtigen und die weniger wichtigen Daten def _readCyclicData(self): # Alle Einträge aus dem Distionary durchlaufen und für jedes Item prüfen, # ob dieses in dem Zyklus (Untersetzung) ausgelesen werden soll. for name in sorted(self._items.keys(), reverse=True): item = self._items[name] # Prüfung ob dieses Item in dem Zyklus ausgwertet werden soll if ((self._actreduction % int(item.conf['pluginreduction'])) == 0): self.logger.debug('Plugin viessmann') self.logger.debug('Plugin viessmann - Reduction act: {} - Read item: {}'.format(self._actreduction, item.conf['plugintagid'])) # Lesen readsuccess = False # 1. Versuch den Wert von der Heizung zu lesen if ((time.time() - 500) > self._lastbytetime): # Der letzte Lesevorgang ist länger als 500ms her. # Daher wird die Schnittstelle zur Sicherheit initialisiert. self._initCommunication() # Lesen der Daten (1. versuch) readsuccess = self._readValue(item) if (readsuccess == False): # Erster Leseversuch hat nicht funktioniert # Initialisierung der Schnittstelle vornehmen inited = self._initCommunication() # Prüfung, ob die Initialisierung erfolgreich war if (inited == True): # 2. Versuch den Wert von der Heizung zu lesen readsuccess = self._readValue(item) if (readsuccess == False): # Wert konnte nicht gelesen oder das Item nicht geschrieben werden messagetext = 'Plugin viessmann - Wert konnte nicht gelesen und Item geschrieben werden. Read value : {}, Schnittstelle initialisiert : {}'.format(item.conf['plugintagid'], readsuccess) self.logger.error(messagetext) else: # Korrekt gelesen und Item geschrieben messagetext = 'Plugin viessmann - Wert korrekt gelesen und Item geschrieben. Read value : {}'.format(item.conf['plugintagid']) self.logger.info(messagetext) # Untersetzungscounter um 1 hochzählen self._actreduction = self._actreduction + 1 # Sofern der Untersetzungscounter größer ist als der Maximalwert, # wird dieser auf 1 zurückgesetzt if self._actreduction > self._maxreduction: self._actreduction = 1 # Letzte Zeit vom Lesen setzen timestring = '' + time.strftime('%d.%m.%Y %H:%M:%S') self._itemlastread(timestring)
plugin.yaml
Code:
viessmann: class_name: viessmann class_path: plugins.viessmann serialport: /dev/ttyUSB_HEIZUNG update_cycle: 300
Gruß
loeserman
Kommentar