Dispatch, readingsProxy(2) oder internen Code verwenden für Sub-Devices

Begonnen von Beta-User, 14 Mai 2025, 10:43:24

Vorheriges Thema - Nächstes Thema

Beta-User

Hallo zusammen,

der Titel ist vielleicht nicht wirklich selbsterklärend, hier daher vorab ein paar Hintergrundinfos:

Anlass ist "vitoconnect" - das dankenswerterweise von stefanru überarbeitete Modul zum Anzapfen der Viessmann-API. Das ist (mit seinen Überarbeitungen) im Prinzip generisch gestaltet, was bedeutet, dass man Reading- und Setter-Namen bekommt, die sich aus der API selbst direkt ableiten.

Damit sind sie immer aktuell, aber in der Namensgebung auch "unendlich" lang und nicht unbedingt selbsterklärend, und zudem ist das ganze eben ein "Großdevice", in dem alle Anlagenteile abgebildet werden - kurz: das ist irgendwie "unFHEMish".

Die bisherigen vitoconnect-Lösungen hatten jeweils hart vercodete Mappings, aber weiter alles in einem Großdevice. Damit waren die Reading-Namen zwar etwas besser lesbar, aber der heutige Code dient zu gefühlt der Hälfte zur Beibehaltung der Kompabilität zu den älteren Versionen, und die Namensgebung ist imo nicht immer "glücklich" im Sinne von https://forum.fhem.de/index.php?topic=117933.0 - schon alleine, weil es z.B. bei praktisch allen Heizungssystemen (funktional) z.B. sowas wie eine "desired-temp" sowohl für den Heizkreislauf wie auch das Warmwasser gibt...

Insbesondere, was die Reading-Namensgebung angeht, erinnerte mich das (aus den Augenwinkeln) an HomeConnect, von daher _könnte_ es sein, dass die Ausgangslage ein allgemeines Thema ist, das ggf. besser mit einer generischen, für mehrere Module passenden Lösung adressiert werden sollte - daher dieser Post hier.

Was (bei vitoconnect) bisher geschah:
Ich habe den Code so überarbeitet, dass das Modul zwei "Modi" kennt,
- einen "Server"-Modus, in dem die sich aus der API ergebenden Reading- und Setter-Namen verwendet werden (und vom Gedanken her keine Mappings mehr zugelassen werden sollen), und
- einen "Client"-Modus, in dem (per mapping-File) nur noch eine Auswahl aller Readings des "Server"-Devices unter anderen Namen angezeigt und gesetzt werden können. Man kann also z.B. den Warmwasser-Teil (& den Heizungskreislauf 1 usw.) "abtrennen" und hat dort (in allen Sub-Devices) dann (u.A.) "measured-temp" und "desired-temp" - letzteres dann auch setzbar mit den Parametern und Grenzwerten, die die API dafür vorgibt. (Aktuelle überarbeitete Fassung des Moduls ist in https://forum.fhem.de/index.php?msg=1340965 zu finden).

Abgesehen vom Spezialfall "weekprofile" (das ich gerne bei allen Heizungs-Type-Geräten direkt nutzen möchte), ist das einigermaßen generisch, und man könnte das auch abtrennen.

Jedenfalls soweit ich das bisher überblicke, scheint es bis dato keine Lösung zu geben, mit der man einzelne Baugruppen aus solchen Großdevices "absplitten" kann.

Ansätze:
readingsProxy geht zwar in diese Richtung, hat aber zwei Haken: Es kennt nur ein Reading (bzw. eine setFn), und man kann nicht wirklich generisch umbenennen (außer, das eine Reading als "state" im readingsProxy zu behandeln); alle set-Befehle vom "Master-Device" zu übernehmen geht zwar auch, aber dann eben alle und unter dem dortigen Namen.
Es gibt imo gewisse Anklänge im readingsProxy-Modul-Code, um mehrere Readings abzubilden, aber das ist ein stub, und umbenennen ist da auch nicht vorgesehen.

Fragen von meiner Seite:
- gibt es überhaupt allgemeines Interesse an so was wie einem "generischen sub-Device"
- wenn ja: wie realisiert man das sinnvollerweise? Per notifyFn() wie readingsProxy oder als Client-Device per Dispatch?
-- ein "readingsProxy2" wäre vermutlich relativ schnell zu realisieren, die Verzahnung mit dem Stammdevice - insbesondere was "weekprofile" angeht - dürfte dafür aber etwas aufwändiger werden, und man bräuchte alle Änderungen aus dem Stammdevice in der Event-Liste...
-- Dispatch hat den "Nachteil", dass man die "message" wieder serialisieren muss und (gefühlt) einen ziemlichen Overhead erzeugt (und sowas wie ein Fingerprint zumindest auf den ersten Blick keinen Mehrwert bietet). Vorteil wäre aber, dass man dann davon ausgehen könnte, dass die Verzahnung mit dem "IO-Modul" enger wäre (=> weekprofile) und man im Stammdevice gar keine Events bräuchte.
(Wenn "Dispatch" alternativ die Referenz auf den key-value-Hash durchreichen würde, wäre man ggf. schneller am Ziel, aber vielleicht übersehe ich auch da was  :-[ .)

Meinungen dazu?
Andere Ideen?
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

rudolfkoenig

Meine Bemerkungen (ohne eine Praeferenz zu haben) aus dem Standpunkt der Dispatch Variante:

- der Benutzer kann nicht in die Datenuebermittlung zwischen physischen und logischen Modul eingreifen (Vorteil?)
- man kann das neue logische Modul nicht fuer existierende Module anwenden, ohne diese anzupassen
- statt Serialisierung wuerde ich einen Schluessel in einem in beiden Modulen bekannten Hash uebergeben
- Serialisierung und die Verwendung von IOWrite haette den Vorteil, dass man FHEM2FHEM verwenden kann, das ist aber heutzutage nicht wirklich ein Argument.
- mit IODev existiert eine Methode fuer die Zuordnung beider Module, mit notify muesste man das noch dazubauen
- ob man IOWrite oder CommandSet verwendet, ist Geschmacksache, man sollte nur das andere Modul nicht hartkodieren, wie einige Module (z.Bsp. MQTT_DEVICE) das tun. Bei der notify Methode faellt IOWrite weg.
- falls man nicht serialisiert, sollten die beiden Methoden aus Performance-Sicht gleich sein

Beta-User

Vorab mal Danke für die Antwort!

Die hilft mir in mehrfacher Hinsicht weiter :) .

Zum ersten scheint die Idee/der Gedanke an sich weder bereits gelöst noch uninteressant zu sein...
Zitat von: rudolfkoenig am 14 Mai 2025, 15:02:38Meine Bemerkungen (ohne eine Praeferenz zu haben) aus dem Standpunkt der Dispatch Variante:

- der Benutzer kann nicht in die Datenuebermittlung zwischen physischen und logischen Modul eingreifen (Vorteil?)
Das sehe ich als Vorteil; jede Art Nutzereingriffs-Option erzeugt erfahrungsgemäß mehr Fragen als es Probleme löst...
Von daher sollten Nutzereingriffe selbstredend da möglich sein, wo es "FHEMish" ist (z.B. on/off statt (boolean) 1/0 bzw. true/false), aber ansonsten sollte das (sowieso dann schon eher komplexe Zusammenspiel) eher "geschlossen" werden.

Zitat- man kann das neue logische Modul nicht fuer existierende Module anwenden, ohne diese anzupassen
Das spräche in der Tat (deutlich) für die notifyFn-Varante - die wenigsten Modul-Autoren werden geneigt sein, ein ihnen nicht bekanntes Client-Modul zu unterstützen; es wäre daher ggf. wünschenswert, den Einstieg über diese Variante zu erleichtern.

Zitat- statt Serialisierung wuerde ich einen Schluessel in einem in beiden Modulen bekannten Hash uebergeben
Das klingt nach einer sehr eleganten Abkürzung :) !
Im Moment neige ich dazu, den ersten Wurf für Dispatch mit einem Schlüsselbegriff/HASH unterhalb "$hash->{helper}" unterzubringen. Das würde eine gewisse Öffnung für mehrere Schlüssel bedeuten, ohne jetzt schon entscheiden zu müssen, ob man das überhaupt braucht.

Zitat- Serialisierung und die Verwendung von IOWrite haette den Vorteil, dass man FHEM2FHEM verwenden kann, das ist aber heutzutage nicht wirklich ein Argument.
FHEM2FHEM ist eine fremde Welt für mich; jede Transformation bringt imo aber auch immer ein gewisses Risiko mit sich, dass dabei was missverstanden werden kann, von daher würde ich tendenziell darauf verzichten wollen. Ggf. kann der geneigte User dann das Endergebnis mit FHEM2FHEM doppeln und nicht das Ausgangsdevice?

Zitat- mit IODev existiert eine Methode fuer die Zuordnung beider Module, mit notify muesste man das noch dazubauen
Da man imo sinnvollerweise nur ein Device als Quell-Device hat, kann/sollte das Client-Modul sowieso NOTIFYDEF sauber setzen. Darüber wäre dann auch "probably associated with" zufriedenzustellen, oder?
Zitat- ob man IOWrite oder CommandSet verwendet, ist Geschmacksache, man sollte nur das andere Modul nicht hartkodieren, wie einige Module (z.Bsp. MQTT_DEVICE) das tun. Bei der notify Methode faellt IOWrite weg.
Was das Weitergeben von Kommandos an das Quell-Device angeht, hatte ich bisher einfach die setFn() in vitoconnect rekursiv aufgerufen (und dann für weekprofile nur den einen weiteren Parameter ergänzt, den das Modul intern "braucht", um zu wissen, für welche Baugruppe ein neues Wochenprofil erstellt werden soll - die müssen nämlich nicht nur an einen anderen Endpunkt der API, sondern sehen z.B. auch unterschiedlich aus für Heizung und Warmwasser...).

Da wäre IOWrite() vermutlich dann deutlich von Vorteil; das muss ich mir aber erst mal im Detail anschauen. Ich habe nämlich auch nur ein "böses" Modulpaar in meinem Gehege (MySensors)...

Zitat- falls man nicht serialisiert, sollten die beiden Methoden aus Performance-Sicht gleich sein

Fazit:
Im Moment leuchtet eine "eierlegende Wollmilchsau" vor meinem geistigen Auge auf:
Wenn das IODev das neue Modul als Client kennt => Dispatch + IOWrite, wenn nicht halt notifyFn+CommandSet() (?).

Anmerkungen?

Das wird sicher etwas dauern, bis es soweit ist, dass man sich über konkreteren Code beugen kann...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

rudolfkoenig

ZitatDa man imo sinnvollerweise nur ein Device als Quell-Device hat, kann/sollte das Client-Modul sowieso NOTIFYDEF sauber setzen. Darüber wäre dann auch "probably associated with" zufriedenzustellen, oder?
Wenn ich das Code richtig verstehe, dann ja (will sagen, habs nicht getestet).
NOTIFYDEV ist aber nur in der notify-Variante relevant.

ZitatDa wäre IOWrite() vermutlich dann deutlich von Vorteil;
IOWrite ist da nicht unbedingt in Vorteil (dafuer muss man ein Protokoll festlegen), ich dachte eher an CallFn(<IoDevice>, "SetFn", ...)  anstatt vitoconnect_Set(...).

ZitatWenn das IODev das neue Modul als Client kennt => Dispatch + IOWrite, wenn nicht halt notifyFn+CommandSet() (?).
Damit wuerde man beide Varianten implementieren.
Ich sehe den Vorteil der IODev Methode in diesem Fall nicht.

betateilchen

#4
Zitat von: Beta-User am 14 Mai 2025, 19:27:38
Zitat- statt Serialisierung wuerde ich einen Schluessel in einem in beiden Modulen bekannten Hash uebergeben
Das klingt nach einer sehr eleganten Abkürzung :) !
Im Moment neige ich dazu, den ersten Wurf für Dispatch mit einem Schlüsselbegriff/HASH unterhalb "$hash->{helper}" unterzubringen.

Bezüglich "einem in beiden Modulen bekannten hash" könnte man auch über die Verwendung von %data nachdenken.

Ansonsten habe ich noch nicht wirklich komplett verstanden, was das eigentliche Ansinnen hier ist. Was aber überhaupt nicht schlimm ist.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Beta-User

Zitat von: betateilchen am 19 Mai 2025, 15:17:15Bezüglich "einem in beiden Modulen bekannten hash" könnte man auch über die Verwendung von %data nachdenken.
Thx für den Hinweis.
Tendenziell muss das nicht persistent sein, von daher neige ich im Moment dazu, das (temporär) am "IODev" unterzubringen, auch um eventuelle Konflikte mit anderen Mechanismen zu vermeiden.
Wird aber noch etwas Nachdenken erfordern, bis das ein Gesamtbild ergeben wird.

ZitatAnsonsten habe ich noch nicht wirklich komplett verstanden, was das eigentliche Ansinnen hier ist.
In erster Linie ging es mir darum zu erfahren, ob ich irgendeine bereits bestehende Option übersehen habe, mit der man
a) (eigenständige) "sub-Devices" generieren kann, und
b) ggf. eine allgemein verwendbare Option anbieten könnte, mit der man das lösen kann, was ich als "allgemeines Mapping-Problem" bezeichnen würde.

ad b) Wenn du heute in die aktuelle svn-Fassung von 98_vitoconnect.pm schaust, sind von den rund 4000 Zeilen Code 2x550 Zeilen mappings ($RequestListSvn, $RequestListRoger) und nochmal 2x500 Zeilen Kompabilitätscode für set (vitoconnect_Set_SVN, vitoconnect_Set_Roger). Ergo: Die Hälfte des (in der Form unwartbaren...) Codes ist nur für Kompabilität gedacht.
Das ganze mit den Ziel, (in 4-facher Ausführung) so feine Unterschiede zu ermöglichen wie
Zitat"heating.circuits.0.circulation.pump.status" => "HK1-Zirkulationspumpe",
"heating.circuits.0.circulation.pump.status" => "HK1_Zirkulationspumpe",
Vorne steht der "ungemappte" Reading-Name, wie er sich aus der API ergibt, hinten irgendwas, was imo auch nicht wirklich "FHEM"-like ist.

ad a) Mein vitoconnect-Hauptgerät hat mind. 140 Datenpunkte, die die API liefert. Neben "allem möglichen" gibt es zwei Hauptgruppen, die mich für die Steuerung eigentlich interessieren, den Heizkreislauf und die Warmwasserbereitung.

Klar könnte ich jetzt hergehen, und nur für meine Zwecke je eine readingsGroup basteln, die das zumindest in FHEMWEB schön darstellt. Aber damit kann ich dann immer noch nicht wirklich einfach "weekprofile" verwenden, um Warmwasserbereitung und das Heizssystem "in sync" mit unseren aktuellen Gewohnheiten (und z.B. dem erwarteten Solarertrag) zu halten...

Hoffe, damit vielleicht etwas verständlicher erklärt zu haben, was die "eigentlichen Ansinnen" sind.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

Beta-User

Mit kleinen Tippleschrittchen geht es weiter...

Hier mal eine erste Fassung, bei der zumindest mal das event-basierte Mapping mehrerer Readings klappt - falls jemand mittesten möchte.

set ist noch nicht getestet, sollte aber funktionieren. Wobei das erst mal nicht über
Zitat von: rudolfkoenig am 18 Mai 2025, 14:15:01CallFn(<IoDevice>, "SetFn", ...)
realisiert ist, sondern via AnalyzeCommand(). Wenn ich die Zusammenhänge richtig im Kopf habe, wird dann auch eventMap am "master" beachtet, so dass die (gemappte) set-Syntax und die per getAllSets() ermittelte set-Syntax des master-Devices dann auch zusammenpassen sollten.


Werde mich dann bei Gelegenheit als nächstes mal mit der dispatch-Variante befassen, was aber ggf. größere Umbauten in (erst mal meiner Fassung von) vitoconnect erforderlich machen wird.
Im Moment neige ich dazu, nur wenige "harte" keywords zuzulassen, wie "updated" für Reading-Aktualisierungen oder "resetSets" für den Hinweis, dass sich (eventuell) die set-Kommandos (am master) verändert haben und man das auch am Proxy neu ermitteln muss.

Die Mapping-File ist JSON-encoded. Im Moment war das die _für mich_ einfachste Variante, die mir auch offen für potentielle Erweiterungen erschien. V.a. der set-Umgang mit "state" könnte da ein Thema sein...

Was noch nicht klappt, ist die automatische Übernahme der confFile in die Liste bei "Edit files". Nach meinem Verständnis muss da hart das "./conf"-Verzeichnis verwendet werden und nur der filename in $data{confFile} angegeben werden, was sich im Moment noch mit der Syntax des Attributs beißt - folgt auch bei Gelegenheit.

Das Modul selbst importiert im Moment noch viel zu viel "drumrum", das räume ich auch bei Gelegenheit mal noch auf...

Und hier noch ein Beispiel für das "Ausgliedern" von zwei Readings aus einer ecowitt-Wetterstation:
defmod devProxy subDeviceProxy master=WittBoy
attr devProxy confFile ./conf/sensor_outdoor.mapping
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors