Onkelandy schöner Traum. Dachte ich auch mal das man Smartmeter mit DLMS und SML unter einen Hut bekommen kann. Allerdings wird der Code im Endeffekt nicht mehr wartbar weil hier und da und dort eine Sonderlocke auftaucht oder Geräte mit Bugs. Allenfalls kann man sich ein Modul überlegen das dann von Plugins befüllt wird. Ob das allerdings die Sache dann übersichtlicher macht, weiß ich nicht. Jedenfalls bleibe ich bei KISS
Ankündigung
Einklappen
Keine Ankündigung bisher.
Viessmann Plugin Neuentwicklung Python Hilfe
Einklappen
X
-
So, ich habe alle - bisherigen - Änderungen als PR eingestellt. Kannst du in deinem Repo (online) sehen; wenn du es annimmst, wird es in deinen Code integriert.
Ansonsten als "Standalone" unter https://github.com/Morg42/myplugins ...
- Heizung V200WO1C (0x204D) integriert
- Betriebsart BA: gültiger String wird beim Senden in Bytewert umgewandelt, ungültiger String wird abgewiesen, Änderung des Items rückgängig gemacht
- Unitcodes teilweise umbenannt und ergänzt
- kleinere Fehler behoben
- Code bereinigt
Ich glaube, das wars...
Bei mir läufts problemlos, auch mit Zuweisen von Werten, sogar mit Zuweisen von Strings an BA. Ich glaube, vcontrold, der cron-Job und das network-Plugin können dann erstmal ausruhen gehen
Kommentar
-
Zitat von Morg Beitrag anzeigenSo, ich habe alle - bisherigen - Änderungen als PR eingestellt. Kannst du in deinem Repo (online) sehen; wenn du es annimmst, wird es in deinen Code integriert.
Ich möchte die Änderungen schon integrieren, so dass es dann auch in das offizielle Repo kann.
Schöne Zeit!
Kommentar
-
Zitat von Onkelandy Beitrag anzeigenKönntest dir vielleicht auch mal das drexel und weiß Plugin ansehen, ist ja eine ähnliche Gerätegruppe.(über den Code könnte ich drüberschauen, aber ich habe kein passendes Gerät zum Testen... )
Kommentar
-
Ah, okay. So wie ich es verstanden habe, basiert Michaels Plugin auf dem Comfoair, und grundsätzlich sieht das auch ganz solide aus. Komplett neuschreiben wollte ich es sowieso nicht, und durch die einigermaßen modulare Struktur mit der Konfigurationsdatei konnte ich meine Heizung problemlos einbinden.
Aber ich werde trotzdem mal reinschauen, vielleicht erkenne ich ja noch die eine oder andere Idee, die sich zu behalten lohnt
Kommentar
-
Morg
Hallo,
ich habe noch ein Thema: Heute haben wir eine Öllieferung bekommen und die Heizung war somit eine gewisse Zeit ausgeschaltet. Damit kommt via Optolink natürlich keine Antwort und das Plugin versucht ständig zu "reconnecten". Wenn die Heizung wieder eingeschaltet wird, klappt das dann auch endlich.
Das Problem ist, dass der Thread für die zyklischen Queries nicht beendet wird und es dann zum Fehler
Code:lib.scheduler Needing more worker threads than the specified maximum of 20!
Kannst Du mal schauen, ob wir das anfangen können?
Danke.
Kommentar
-
Ich überlege gerade, wie es dazu kommen kann. Grundsätzlich könnte auch etwas anderes die Scheduler-Threads belegen, aber gehen wir mal nur von diesem Modul aus.
Der Scheduler wird regelmäßig (zB 30 Sekunden) die Methode send_cyclic_cmds() triggern. Diese setzt alle READ-Befehle aus _cyclic_cmds[] ab. Danach (wenn alle READ-Befehle ausgeführt sind), beendet sich send_cyclic_cmds() und der Scheduler-Thread wird - wahrscheinlich - beendet.
Die ganze Initialisierung der Kommunikation ist an sich kein Problem und auch kein Zeitfaktor, solange die Verbindung zur Heizung läuft. Da in den Schleifen in initcommunication() aber immer nur ein Byte gelesen wird, gilt auch für jedes gelesene Byte neu der Timeout von 1 Sekunden. Fürs Schreiben habe ich nicht gesehen, dass überhaupt ein Timeout gesetzt ist, also wäre das ein blocking call, da bleibt er dann hängen. Allerdings sollte das Schreiben über IR auch nicht fehlschlagen, solange der Lesekopf dran ist.
Für mich sieht das so aus, als sollte man:
a) einen write-timeout einführen. Wenn Schreiben fehltschlägt, dann _initialized() zurücksetzen und ggf. aktuellen Durchgang (schedule cycle?) abbrechen. Genau genommen müsste man bei einem write timeout auch _connected zurücksetzen. Möglicherweise hilft das nicht beim aktuellen Problem, ist aber eine mögliche Fehlerschleife, die man ggf. auflösen kann.
b) Wenn ein send_caclic_cmds()-Durchlauf aktiv ist, ist es unsinnig, einen zweiten parallel laufen zu lassen. 1. kann die serielle Schnittstelle keine parallelen Anfragen, und sie ist offensichtlich noch mit dem ersten beschäftigt. 2. solange es Kommunikationsprobleme gibt, ist es auch zwecklos, noch mehr Kommunikation zu "fordern", auch wegen 1.
Hier würde ich eine Art soft lock einführen wollen, z.B. eine Variable wie _cyclic_update_active. Die wird beim Einstieg in send_cyclic_cmds() gesetzt und beim Verlassen gelöscht. Wenn send_cyclic_cmds() aufgerufen wird und die Variable schon gesetzt ist, gibts ne Log-Meldung ("send_cyclic_cmds() aufgerufen, läuft aber noch. Prüfe Verbindung zur Heizung und Anzahl und Prüfzeit der zyklischen Abfragen.") und er beendet ohne weiter Aktion.
Um dauerhafte Deadlocks zu vermeiden, muss das Fehler-/Exception-Management sauber laufen; die Funktionen dürfen nicht aussteigen, ohne die lock-Variable zurückzusetzen. connect() und initcommunication() müssen die Variable auch zurücksetzen.
c) was mir aufgefallen ist (aber hier wahrscheinlich nicht zum Tragen kommt): initCommunication() fragt nicht ab, ob _connected gesetzt ist. Sollte nicht passieren, aber wer weiß.
Ich setz mich mal ran und versuch mal, das so einzubauen, dass dabei nix anderes kaputt geht
Achso, noch ein Punkt: ich kenne das als Konvention (in Python nicht formal umgesetzt), dass man private Funktionen mit einem Unterstrich beginnt, so wie du es bei den Variablen teilweise schon gemacht hast. Damit ist vor allem ersichtlich, welche Funktionen für den externen Aufruf vorgesehen sind (run(), stop(), parse_item(), update_item(), parse_logic() sind klar, aber zB send_cyclic_cmds() - habe ich welche übersehen?). Damit wird schon beim Lesen und Ändern von Code klar, ob jemand "Fremdes" diese Funktionen aufrufen soll. Damit erledigt sich dann eigentlich Punkt c) von oben, außer bei grobem Unfug
Kommentar
-
So, Änderungen sind drin; da der PR noch offen ist, sind die Änderungen automatisch mit übernommen worden.- in send_cyclic_cmds() gibt es jetzt die Abfrage von cyclic_read_active, wenn schon ein Zyklus läuft, bricht der andere einfach ab
- send_cyclic_cmds() loggt am Ende Dauer des Lesevorgangs und Anzahl der gelesenen Items auf DEBUG. Damit kann man ggf. abschätzen, ob die Konfig ok ist
- habe alle Funktionen (und class-globalen Variablen) auf "protected" gesetzt, sofern sinnvoll (beginnen alle mit "_")
- an einigen Stellen habe ich noch Abfragen und Typecasts vereinfacht oder einzelne lokale Variablen zum besseren Verständnis umbenannt
- zu Beginn der Klassendefinition werden die verschiedenen Konfigurationen in dicts eingelesen. Für die serial-Parameter wurde dann jeder einzelne Parameter nochmal in eine globale Klassenvariable gespeichert, obwohl er nur einmal (in _connect()) verwendet wurde. Die habe ich rausgeworfen. Die anderen verbliebenen Variablen haben zumindest die Typumwandlung von str (?) zu byte dabei, die habe ich gelassen. Schöner und aufgeräumter wäre es, die auch rauszuwerfen. Dann wird bei "jedem" Gebrauch konvertiert, was wohl auch kein Problem wäre. Welche Variante (CPU-Last für Konvertierung, Speicher für zusätzliche Variable) ressourcenschonender ist, weiß ich nicht. Dürfte keinen großen Unterschied machen.
(Schade, eigentlich wollte ich die Fehlerbehandlung beim Öffnen und Ansprechen des Devices testen)
Code läuft bei mir ohne Fehler und mit dem erwarteten Ergebnis.
Kommentar
-
Betriebszeiten? Was meinst du damit?
Meine Heizung ist eine Wärmepumpe, da gehe ich mit Betriebszeiten und so wahrscheinlich etwas anders um
Aber wenn du erklärst, was du meinst, kann ich ja mal zuhören
Achso, hast du mal getestet, was passiert, wenn du die Heizung ausschaltest? Und wie lange braucht er bei dir zum Lesen von einem Zyklus?
Kommentar
-
Zitat von Morg Beitrag anzeigenBetriebszeiten? Was meinst du damit?
Worum geht es:
Schaltzeiten gibt es (für meine Steuerung) für Warmwasser und jeden Heizkreislauf (1x Heizkreis A1M1 und 1x Heizkreis M2) also in Summe 3 mal.
Dabei gibt es pro Tag die Möglichkeit4 Schaltzeitpaare (je AN und AUS) festzugelegen.
Jeder Tag jeder Anwendung hat eine eigene Codieradresse.
Aktuell lese ich die jeweilige Codieradresse aus und wandle das in eine Liste mit den 4 Schaltzeitpaaren (AN / AUS). Diese Liste wird dem jeweiligen Item zugewiesen.
Weiterhin wird im Plugin geprüft, ob es zu diesem Item entsprechende Child-Items für AN1, AUS1 ... AN4, AUS4 gibt (Struct bringt das Plugin mit). Sind die Child-Items vorhanden, wir die Liste "zerlegt" und den Items zugewiesen. Damit kann man dan per smartVISU mit Boardmitteln die Zeiten bearbeiten
Soweit klappt das aus.
Für das Schreiben der Schaltzeiten muss man nun die Liste wieder zusammensetzen. Wenn alle Zeiten (in der smartVISU oder dem AdminInterface) bearbeitet sind, löse ich eine Logik aus, die aus den (bearbeiteten) Werten der Child-Items, die Liste wieder erstellt und dem Parent-Item wieder zuweise. Das Plugin merkt, dass das Item geändert wurde und schreibt die neuen Schaltzeiten auf die entsprechende Codieradresse.
Meine Frage ist, ob die etwas einfällt, um das zu vereinfachen.
Zitat von Morg Beitrag anzeigenAchso, hast du mal getestet, was passiert, wenn du die Heizung ausschaltest? Und wie lange braucht er bei dir zum Lesen von einem Zyklus?
Danke
Kommentar
-
Ah, okay. Das klingt etwas komplexer
Wenn die Heizung für jeden Tag (7 Tage) für jede Anwendung (3 Anw.) jeweils 4 An- und 4 Aus-Zeiten speichern kann, komme ich auf 21 Codieradressen zu jeweils 8 Zeiten, die im Paket zu 8 Werten übergeben werden - stimmt das?
Wenn jedes der 21 Items sowieso intern als Liste geführt wird, dann würde ich versuchen, auf die Child-Items zu verzichten (Umgang mit Listen im Plugin ist ja kein Problem) und das Item "as is" an die SmartVisu zu schicken. Da müsste man dann ein passendes Widget schreiben, das aus der linearen Liste (8 Werte) bzw. der geschachtelten Liste (4x 2 Werte) eine entsprechende Schaltuhr anzeigt/umsetzt.
Ansonsten könnte man die Childitems "nur so" definieren, ohne Beziehung zum Plugin und das Plugin bekommt ein neues Item, das nur das Packen und Senden der 8 Subitems triggert. Da bräuchte man keine Logik für, man muss ja eh manuell "bescheid" geben, wenn alle Zeit da sind.
Schöner wäre wahrscheinlich die obere Lösung. Damit bliebe auch das Plugin erheblich weniger komplex/speziell. Und ich halte es für total praktikabel, 8 Schaltzeiten als Liste zu übergeben, ganz ohne Sarkasmus. Im Admin-Interface sowieso, da ist ja kein WAF gefragt. Und den WAF würde ich im Widget installieren.
Nur so ein Gedanke...
Kommentar
-
Morg
Ich möchte das Thema mit dem Timern nochmal aufgreifen.
Mittlerweile habe ich eine Logik gebaut, die die TagesTimer einer Anwendung, wie sie heute das Viessmann Plugin ausgibt, in das UZSU Format bringt und in dem UZSU-Item das UZSU-dict erstellt bzw. modifiziert.
Eine zweite Logik nimmt das UZSU-dict und erstellt daraus die TagesTimer einer Anwendung und schreibt die 7 Items neu.
Nun überlege ich, wie man das am besten in das Plugin einbaut, denn Viessmann hat für jeden Tagestimer einen Datenpunkt buw. Codieradresse, die UZSU hat dann aber alle 7 Tagestimer einer Anwendung.
Mein Vorschlag zu Diskussion:- Pro Timeranwendung (je Heizkreis und Warmwasser) wird für jeden Tagestimer und damit für jeden Viessmann Datenpunkt ein Item angelegt (so wie ich es heute im struct schon realisiert ist). Dort wird auch das viessmann-command hinterlegt.
- Zusätzlich wird ein USZU-Item angelegt.
- Das Plugin liest nun alle commands aus der Steuerung aus und decodiert das Ergebnis.
- Sind alle command eines Timerblock ausgelesen, wird daraus das UZSU-dict erstellt und in das UZSU-Item für den Timer geschrieben bzw das dort befindliche modifziert.
- Dieses UZSU-Item bekommt auch ein viessmann-command und wird im Plugin mit "update_item" überwacht.
- Wird das Item extern verändert (durch Änderung der UZSU über die visu bspw) wird das UZSU-dict ausgelesen und in die viessmann-timer gewandelt und in diese Items zurückgeschrieben.
Danke für Deine Antwort.
Michael
Kommentar
-
Das klingt doch schon mal super, ich habe auch die - sichtbaren- Entwicklungsschritte bei SV mit einem Ohr mitverfolgt.
Nachdem ich jetzt einiges dazu geschrieben hatte, habe ich das alles wieder gelöscht. Letztlich habe ich deinen Vorschlag nur mit anderen Worten beschrieben, das Ergebnis und der Weg dahin waren letztlich gleich.
Also: passtWillst du das schreiben oder soll ich mich da ransetzen?
Gruß
Sebastian
Kommentar
Kommentar