DevIo Connection vor Define aufbauen

Begonnen von dominik, 30 September 2020, 19:27:12

Vorheriges Thema - Nächstes Thema

dominik

Hi,

ich habe ein Modul wo ich vor dem Define eine Websocket DevIo Connection aufbauen muss. Gibt es Möglichkeiten dies zu forcieren? Nachdem die Websocket Connection nur mit callback funktioniert, kann ich darauf auch nicht warten. Im dachte ich kann im Modul selbst mit DevIo_IsOpen() warten, jedoch klappt das auch nicht, weil die Main Loop ja weiter laufen muss damit die Connection aufgebaut werden kann.

Hat noch noch jemand eine Idee zur Lösung?

Danke & Gruß,
dominik
fhempy -  https://github.com/fhempy/fhempy: GoogleCast, Tuya, UPnP, Ring, EQ3BT, Nespresso, Xiaomi, Spotify, Object Detection, ...
Kaffeespende: https://paypal.me/todominik

rudolfkoenig

Zitatich habe ein Modul wo ich vor dem Define eine Websocket DevIo Connection aufbauen muss.
Bitte anders formulieren, ich verstehe das nicht.

Wenn ich rate, dann wird daraus: "ich haette gerne ein blockierendes Websocket-Connect".
Wenn stimmt, dann  muss ich enttaeuschen, und auf die Callback-Variante verweisen.
Ist kaum komplizierter als die blockierende Variante, wenn man sich daran gewoehnt hat.

dominik

Ok, gerne ein paar mehr Details.

Ich habe im Zuge der googlecast (pychromecast als Basis) Neuimplementierung eine Python Anbindung an FHEM geschaffen - ist noch in der Testphase - damit lassen sich dann über eine Websocket Schnittstelle auch Module in Python programmieren. Nun habe ich einen Python "Server" mit dem jedes Modul über Websockets mit FHEM kommuniziert.

Beim Starten habe ich aber folgende Herausforderung:
- Zuerst wird ein Modul geladen, welches den Python Server startet
- Dann wird ein Modul geladen, welches als DevIo Device zum Python Server fungiert
- An letzter Stelle wird das richtige Device geladen, welches im Define sofort ein IOWrite macht und über das DevIo Device den Python Server aufruft

Genau der letzte Punkt ist das Problem. Beim Define ist die DevIo Verbindung noch nicht aufgebaut, da diese natürlich etwas braucht. Im Define selbst, kann ich diese aber auch nicht Blocking aufbauen - also ja, wahrscheinlich ist die einzige Lösung wirklich ein Blocking Websocket Connect. Was besseres fällt mir im Moment nicht ein.
Im Moment führe ich das komplette Define aus dem Callback vom Websocket Connect aus, das führt zu ein paar Problemen, wie das setDevAttrList Thema das wir in einem anderen Thread hatten.
fhempy -  https://github.com/fhempy/fhempy: GoogleCast, Tuya, UPnP, Ring, EQ3BT, Nespresso, Xiaomi, Spotify, Object Detection, ...
Kaffeespende: https://paypal.me/todominik

zap

Warum kannst Du die ganze Python Umgebung inkl. server nicht erst dann initialisieren bzw. starten, wenn die FHEM per Notify meldet, dass die Initialisierung abgeschlossen ist?

Dein define kann vorher schon erfolgen. Bis zur Initialisierung setzt Du es in eine Art busy Status, d.h. man kann damit nichts anfangen. Aber das ist ja nicht schlimm, weil ein paar Sekunden später init_done true ist und FHEM dein Modul darüber informiert.

Ich mache das bei HMCCU genauso: erst wenn FHEM initialisiert ist, starte ich die RPC Prozesse und erst wenn diese laufen, teile ich der CCU mit, dass sie nun Daten schicken kann.
2xCCU3, Fenster, Rollläden, Themostate, Stromzähler, Steckdosen ...)
Entwicklung: FHEM auf AMD NUC (Ubuntu)
Produktiv inzwischen auf Home Assistant gewechselt.
Maintainer: FULLY, Meteohub, HMCCU, AndroidDB

dominik

So hatte ich es bisher auch, bis ich dann bemerkt habe, dass so Sachen wie "setDevAttrList" und vielleicht noch ein paar andere die ich noch nicht kenne, schon während der Initialisierung passieren müssen. Ich habe dafür schon einen Workaround über userattr, aber dennoch hätte ich es lieber wenn es dem FHEM Standard folgt und damit auch ein Python Modul das Define beim Start komplett durchläuft.

Wenn das nicht geht, ist es nicht soooo schlimm, dann gibt es eben ein paar Funktionen die im Python Define nicht 1:1 möglich sind.
fhempy -  https://github.com/fhempy/fhempy: GoogleCast, Tuya, UPnP, Ring, EQ3BT, Nespresso, Xiaomi, Spotify, Object Detection, ...
Kaffeespende: https://paypal.me/todominik

rudolfkoenig

Ich bin immer noch der Ansicht, das nichtblockierende Programmierung nur  Gewoehnungssache ist.
Als Beweis dient fuer mich node.js mit den 1Mio+ Modulen: da sind blockierende Aufrufe auch nicht moeglich.

Wg. setDevAttrList: kannst Du genau erklaeren, wo das Problem liegt?
Ich gehe davon aus, dass dafuer mehr als eine Loesung gibt.

dominik

Ich bin 100% bei dir, ich bin ein Fan von nichtblockierender Programmierung und der ganze Python Code basiert auf asyncio :)

Bei setDevAttrList passiert folgendes:
- Wenn im Define setDevAttrList zum Zeitpunkt der Initialisierung nicht aufgerufen wird, dann kann FHEM beim Startup die Attribute aus der fhem.cfg nicht setzen, da es diese Attribute aus FHEM Sicht noch nicht gibt
- setDevAttrList muss daher innerhalb von Define ausgeführt werden

Da ich das aus oben genannten Gründen (DevIo Connection) nicht tun kann und die Initialisierung der Python Module erst nach der Initialisierung von FHEM stattfindet, gehen alle Attribute aus der fhem.cfg verloren.
fhempy -  https://github.com/fhempy/fhempy: GoogleCast, Tuya, UPnP, Ring, EQ3BT, Nespresso, Xiaomi, Spotify, Object Detection, ...
Kaffeespende: https://paypal.me/todominik

rudolfkoenig

Ich wollte kein Management-Summary (soweit war ich schon), sondern was fuer Techniker. Am besten mit Beispiel und so. Konkret halt. :)

dominik

Ok, dann konkret ;)

Zuerst ein kleines Architekturbild dazu:
https://github.com/dominikkarall/fhem_pythonbinding/blob/development/flowchart.png

Die 3 FHEM Module (https://github.com/dominikkarall/fhem_pythonbinding/tree/development/FHEM)
- 10_BindingsIo: Ist das DevIo Device
- 10_PythonBinding: Ist das Modul, welches als CoProcess den Python Server startet
- 10_PythonModule: Das ist das Grundgerüst Modul für alle PythonModule und ruft nur per IOWrite (über BindingsIo als DevIo) die Funktionen aus dem Python Code auf.

...und hier die problematische Stelle im googlecast Modul:
https://github.com/dominikkarall/fhem_pythonbinding/blob/development/FHEM/bindings/python/lib/googlecast/googlecast.py#L52

Ich hoffe das hilft dir weiter. Bei Fragen gerne melden.
fhempy -  https://github.com/fhempy/fhempy: GoogleCast, Tuya, UPnP, Ring, EQ3BT, Nespresso, Xiaomi, Spotify, Object Detection, ...
Kaffeespende: https://paypal.me/todominik

rudolfkoenig

Mir ist nicht klar, ob favorite_1 bis 5 immer da ist, oder dynamisch erzeugt wird.

Wenn immer, dann kann man das fest einbauen.

Wenn dynamisch, koennte man die Logik in das FHEM-Modul verlagern: man speichert nur den fuer die Entscheidung notwendigen Werte in einem Attribut, dessen Name im Alphabet vor den anderen Attributnamen ist, und damit beim Start vor dem Anderen gesetzt wird. In AttrFn ruft man beim Bearbeiten dieses Attributes setDevAttrList auf.
Dieses Verfahren ist aber eine komplizierte, zu implementierende Loesung fuer eine vorhandene, einfache Alternative: userattr.

Wo ist das Problem mit userattr?

dominik

favorite_1 bis 5 sind Fix, nur wird es "dynamisch" erzeugt, da das Define erst nach der FHEM Initialisierung aufgerufen wird.

Die Logik ins FHEM Modul verlagern passt nicht ganz mit meinem Konzept überein, da ich gerne die Logik komplett in Python lassen möchte, nur so kann ich ein generische Python Binding für Module anbieten.

userattr gefällt mir nicht so gut, da User selbst die userattr löschen können. Wenn das mal unabsichtlich passiert, können diese bis zum nächsten Neustart die Attribute nicht mehr nutzen.
fhempy -  https://github.com/fhempy/fhempy: GoogleCast, Tuya, UPnP, Ring, EQ3BT, Nespresso, Xiaomi, Spotify, Object Detection, ...
Kaffeespende: https://paypal.me/todominik