[gelöst] global:INITIALIZED zu früh seit Update heute?

Begonnen von DeeSPe, 21 April 2017, 11:22:48

Vorheriges Thema - Nächstes Thema

Thorsten Pferdekaemper

Zitat von: Loredo am 23 April 2017, 11:46:05
Ich kann dir hier nicht das gesamte Event Handling von FHEM erläutern.
Wozu auch?

ZitatDas beste Beispiel ist der ursprüngliche Grund dieses Threads, nämlich Dans HOMEMODE Modul im Zusammenspiel mit RESIDENTS. Dazu musst du nur die Nachrichten von Anfang an lesen.
Das habe ich getan. ...und jetzt nochmal. Es sieht doch so aus, dass das HOMEMODE-Device "sein" RESIDENTS-Device kennt. D.h. es interessiert eigentlich nur, ob dieses Device schon fertig ist. Warum muss man wissen, ob alle RESIDENTS fertig sind?

Zitat
Ein Reading ist mehr als nur ein Event
...und genau deshalb fände ich hier ein Reading angebracht.

Zitat
Wir reden hier von eine Abstraktionsebene höher, der allgemeinen Modulebene, die zunächst erst einmal gerätelos ist. Deshalb sind wir dann auch automatisch bei Events des Pseudo-Devices "global", da nur dafür ein gesondertes Event Handling in FHEM existiert. Es ist schlicht der Architektur von FHEM geschuldet, dass Events IMMER an einem Device hängen müssen, FHEM selbst und alle Module jedoch zunächst einmal gerätelos sind.
Deshalb gibt es auch zwei Funktionen, die bei der Initialisierung eines Moduls eine Rolle spielen: X_Initialize() initialisiert das Modul ansich unter %modules, X_Define() das jeweilige Device unter %defs.
Das ist mir alles klar. Mir ist nur nicht klar, warum man das auf Modulebene braucht.

Gruß,
   Thorsten
FUIP

Loredo

#61
Da ich es nicht geschafft habe den rereadcfg Fall rein über die bestehenden Events richtig zu handhaben, habe ich jetzt einen Patch geschrieben, der FHEM um eine neue ModulFn InitDevFn erweitert.Beiliegender Patch beinhaltet die zwei neuen Funktionen DoModuleTrigger() und DoInitDev() sowie die Anpassungen, um InitDevFn als Modul Funktion registrieren zu können.

Das Modul-globale Event Handling ist darin so gekapselt, dass man als Modulautor nur die InitDevFn bereitstellen muss. Dafür werden die folgenden Variablen verwendet, um den Initialisierungsstatus zu speichern:

$modules{$m}{READY}
$modules{$m}{INIT}
$defs{$d}{READY}
$defs{$d}{MOD_INIT}

Es ist sichergestellt, dass man über DoModuleTrigger() nur Modul-eigene Events auslösen kann. Die Events TYPE:INITIALIZED, TYPE:INITIALIZING, TYPE:MODIFIED und TYPE:DELETED kann man nicht übersteuern, sie werden vollständig von DoModuleTrigger verwaltet.

Beispiel wie eine InitDevFn für RESIDENTS/ROOMMATE/GUEST aussehen würde:


sub RESIDENTStk_InitializeDev($) {
    my ($hash) = @_;
    $hash = $defs{$hash} unless ( ref($hash) );
    my $NOTIFYDEV = "global";

    if ( $hash->{TYPE} eq "RESIDENTS" ) {
        $NOTIFYDEV .= "," . RESIDENTStk_findResidentSlaves($hash);
    }
    else {
        $NOTIFYDEV .= "," . RESIDENTStk_findDummySlaves($hash);
    }

    return 0
      if ( defined( $hash->{NOTIFYDEV} ) && $hash->{NOTIFYDEV} eq $NOTIFYDEV );

    $hash->{NOTIFYDEV} = $NOTIFYDEV;

    return undef;
}


Entsprechende globale Events werden dann für das Modul gehandhabt.

Folgende Events werden während des Startvorgangs _nach_ global:INITIALIZED erzeugt:
1. je Device => global:TYPE:INITIALIZED <device>
2. erst wenn alle Devices initialisiert wurden => global:TYPE:INITIALIZED

Je nach Rückgabe der InitDevFn wird ermittelt, ob und wie ein Event ausgelöst wird. Für verzögerte Geräte muss man nur einen nicht leeren Returnwert liefern. Eine Ausnahme bildet der Returnwert 0: Er bedeutet, dass keine strukturellen Änderungen am Device vorgenommen wurden und deshalb kein Event ausgelöst werden muss. Undef oder "" wird als erfolgreiche Initialisierung gewertet.

Während der Laufzeit kann der Modulautor die Wrapper-Funktion DoInitDev([$name|@array]) so oft ausführen, wie er möchte. Darüber wird indirekt seine InitDevFn aufgerufen und die Modul-globalen Events werden dann entsprechend gesteuert. Außerdem ist auch die Nutzung von DoModuleTrigger() ähnlich wie DoTrigger() möglich. Man kann darüber auch manuell die Events auslösen, die sonst über DoInitDev() gesteuert werden.


------
TL;DR

Im Bezug auf die Problematik, dass einige Module die globalen Events nur unzureichend filtern, habe ich alle betroffenen Modulautoren per PM angeschrieben:

HMInfo (martinp876)
DOIF (Damian)
weekprofile, pilight_ctrl (Risiko)
DOIFtools (Ellert)
DUOFERNSTICK (Telekatz)



Gruß
Julian
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

Loredo

Zitat von: Thorsten Pferdekaemper am 23 April 2017, 12:48:24
Das habe ich getan. ...und jetzt nochmal. Es sieht doch so aus, dass das HOMEMODE-Device "sein" RESIDENTS-Device kennt. D.h. es interessiert eigentlich nur, ob dieses Device schon fertig ist. Warum muss man wissen, ob alle RESIDENTS fertig sind?


Das fragst du bitte Dan.
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

rudolfkoenig

ZitatDa ich es nicht geschafft habe den rereadcfg Fall rein über die bestehenden Events richtig zu handhaben, habe ich jetzt einen Patch geschrieben

Wenn ich diesen Patch einspielen soll, dann muss ich erst verstehen, warum es notwendig ist, und ja, ich habe deine Erklaerung hier gelesen. Kannst du bitte erlaeutern, was genau nicht moeglich ist?

DeeSPe

Zitat von: Loredo am 24 April 2017, 00:46:45

Das fragst du bitte Dan.

Das kann ich nicht beantworten, das ist nicht auf "meinem Mist" gewachsen.
Mir reicht es zu wissen wann genau das eine überwachte RESIDENTS Device, dessen Namen ich auch habe, initialisiert ist.
Bisher klappt das auch ohne die neuen Events von Loredo dank NotifyOrderPrefix.

Gab es hier schon eine grundlegende Entscheidung zum Event-Handling bezüglich Modul/Device Initialisierung?

Gruß
Dan
MAINTAINER: 22_HOMEMODE, 98_Hyperion, 98_FileLogConvert, 98_serviced

Als kleine Unterstützung für meine Programmierungen könnt ihr mir gerne einen Kaffee spendieren: https://buymeacoff.ee/DeeSPe

Loredo

#65
Zitat von: Thorsten Pferdekaemper am 23 April 2017, 12:48:24
Warum muss man wissen, ob alle RESIDENTS fertig sind?


Damit festgestellt werden kann, wenn sich zur Laufzeit etwas geändert hat (RESIDENTS hat neue Bewohner aufgenommen oder entfernt) und Dan sein set updateInternalsForce in Rente schicken könnte. Während des Bootups ist es aktuell ein Nebenprodukt, es wird sicherlich jemand findiges auf Ideen kommen das sinnvoll zu verwenden, wenn die Funktion erstmal da ist.


Zitat von: DeeSPe am 24 April 2017, 11:05:14
Das kann ich nicht beantworten, das ist nicht auf "meinem Mist" gewachsen.


Nicht ganz, ich habe deine Anforderungen ja sehr wohl ernst genommen:
https://forum.fhem.de/index.php/topic,70882.msg624225.html#msg624225


Zitat von: DeeSPe am 24 April 2017, 11:05:14
Mir reicht es zu wissen wann genau das eine überwachte RESIDENTS Device, dessen Namen ich auch habe, initialisiert ist.
Bisher klappt das auch ohne die neuen Events von Loredo dank NotifyOrderPrefix.


NotifyOrderPrefix verwende ich nun nicht mehr, da die Module ihre eigenen Events für die Fertigstellung generieren können.


Zitat von: DeeSPe am 24 April 2017, 11:05:14
Gab es hier schon eine grundlegende Entscheidung zum Event-Handling bezüglich Modul/Device Initialisierung?


IMHO sind wir dabei das auszuloten und ich habe dafür einen POC in meine Module eingebaut sowie einen generellen Patch für fhem.pl bereitgestellt, damit es keine Eigenbrödlerlösung bleiben muss und alle etwas davon haben können.


Zitat von: rudolfkoenig am 24 April 2017, 10:55:36
Wenn ich diesen Patch einspielen soll, dann muss ich erst verstehen, warum es notwendig ist, und ja, ich habe deine Erklaerung hier gelesen. Kannst du bitte erlaeutern, was genau nicht moeglich ist?

Nachdem ich die eigentlich für FHEM global gedachte Implementierung nun nochmals (fast) 1-zu-1 in meine Module eingebunden habe, kann ich es auf diese Dinge eingrenzen:

1. Beim triggern auf global:INITIALIZED werden die Devices unnötig mehrfach initialisiert bzw. zumindest die Funktion mehrfach aufgerufen, da das Event bei jedem einzelnen Gerät auch dann noch eintrifft, wenn es bereits über das allerste Gerät aus fhem.cfg initialisiert wurde.
2. Auf DELETED Events können Module nicht reagieren, da für das gelöschte Device die Information nicht mehr zu Verfügung steht, welchem Modul das Gerät einmal gehört hat.
3. Es ist nicht möglich ein Modul-globales Event zu senden, nachdem das letzte Devices eines Moduls gelöscht wurde.
4. Die "Hoheit" über die globalen Events bleibt bei fhem.pl (davon ausgehend, dass Modulautoren DoTrigger() nicht verwenden, sondern DoModuleTrigger()).

Das mögen jetzt nicht mehr die dringendsten Gründe sein. Ich meine aber, dass die Bereitstellung dieser Funktionalität als InitDevFn für alle Modulautoren eine sinnvolle Ergänzung wäre. Natürlich kann man das noch feinschleifen, dafür bin ich aber auf Mitarbeit angewiesen.



Gruß
Julian
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

zap

Zitat von: Loredo am 24 April 2017, 17:19:25
Ich meine aber, dass die Bereitstellung dieser Funktionalität als InitDevFn für alle Modulautoren eine sinnvolle Ergänzung wäre.

Ich würde das jetzt nicht verallgemeinern. Mag sein, dass es für das eine oder andere Modul sinnvoll ist, für meine Module kann ich da jetzt keinen Usecase ausmachen.
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

Loredo

Ich spreche vom Angebot, nicht der Nachfrage.


Aber ich bin die Diskussion auch schon wieder leid...  :-X
Hat meine Arbeit dir geholfen? ⟹ https://paypal.me/pools/c/8gDLrIWrG9

Maintainer:
FHEM-Docker Image, https://github.com/fhem, Astro(Co-Maintainer), ENIGMA2, GEOFANCY, GUEST, HP1000, Installer, LaMetric2, MSG, msgConfig, npmjs, PET, PHTV, Pushover, RESIDENTS, ROOMMATE, search, THINKINGCLEANER

DeeSPe

Zitat von: Loredo am 24 April 2017, 17:19:25
Nicht ganz, ich habe deine Anforderungen ja sehr wohl ernst genommen:
https://forum.fhem.de/index.php/topic,70882.msg624225.html#msg624225

Vielen Dank für Deinen Einsatz.
Leider hast Du mich wohl missverstanden.
Ich habe niemals eine Anforderung gestellt:
Zitat von: DeeSPe am 21 April 2017, 21:05:12
Genau das ist der Punkt warum es in meinem Modul "set <name> updateInternalsForce" gibt. Wenn sich ein überwachter TYPE erweitert/verringert dann muss eben genau das ausgeführt werden damit die Device aktualisiert werden ohne Neustart.

Das war lediglich eine Feststellung dass ich generell dazu keine Möglichkeit gefunden habe. Es ging mir dabei garnicht primär um RESIDENTS, denn die ändern sich ja i.d.R. nicht so oft. Mein Modul überwacht noch ein Vielzahl weiterer Geräte (z.B. Kontakt- und Bewegungssensoren), bei denen durchaus mal der ein oder andere dazukommt oder wegfällt.
Deswegen ging es mir um eine evtl. allgemein gültige Lösung. Vielen Dank für Deinen Vorschlag dazu.
Mein ursprüngliches Problem war durch Ändern von NotifyOrderPrefix in meinem Modul bereits gelöst, zumindest habe ich bisher nichts Nachteiliges feststellen können.

Für die allgemein gültige Lösung bin ich weiterhin offen und finde Dein PoC gut! Ich kann aber die Tragweite nicht beurteilen und ob das für jeden Entwickler sinnvoll zu integrieren geht.

Gruß
Dan

P.S. Die endgültige Lösung sollte dann auch "in Stein gemeisselt" werden (commandref + DeveloperGuide).
MAINTAINER: 22_HOMEMODE, 98_Hyperion, 98_FileLogConvert, 98_serviced

Als kleine Unterstützung für meine Programmierungen könnt ihr mir gerne einen Kaffee spendieren: https://buymeacoff.ee/DeeSPe

rudolfkoenig

Zitat1. Beim triggern auf global:INITIALIZED werden die Devices unnötig mehrfach initialisiert bzw. zumindest die Funktion mehrfach aufgerufen, da das Event bei jedem einzelnen Gerät auch dann noch eintrifft, wenn es bereits über das allerste Gerät aus fhem.cfg initialisiert wurde.

Meiner Ansicht nach kann man das auch ohne Patch:
Variante a) ohne Notify
Im MODUL_Initialize() folgendes aufrufen:
InternalTimer(1, "MyModuleFinalInitializer", undef);

Variante b) mit Notify auf global:INITIALIZED
Im DefineFn folgendes einbauen:
if(!$modules{MODULNAME}{ldata}{notifyset}) {
    $modules{MODULNAME}{ldata}{notifyset} = 1;
    $hash->{NOTIFYDEV} = "global";
  } else {
    $hash->{NOTIFYDEV} = "__NO_DEVICE__";
  }

Im notifyFn kann man dann entweder $modules{MODULNAME}{NotifyFn} entfernen oder NOTIFYDEV aendern oder alles lassen, wie es ist.
Damit rereadcfg funktioniert, bzw. der Benutzer ohne FHEM Neustart beliebig Instanzen entfernen kann, muss man im UndefFn dafuer sorgen, dass NOTIFYDEV an der naechsten Instanz weitergegeben wird, bzw. beim Entfernen der Letzten notifyset entfernt wird.


Zitat2. Auf DELETED Events können Module nicht reagieren, da für das gelöschte Device die Information nicht mehr zu Verfügung steht, welchem Modul das Gerät einmal gehört hat.
Das ist leider unpraezise formuliert. Fuer das eigene Modul gibt es UndefFn, andere Module muessen das Modul der anderen Instanz merken, wenn das beim Entfernen dort eine Rolle spielt.


Zitat3. Es ist nicht möglich ein Modul-globales Event zu senden, nachdem das letzte Devices eines Moduls gelöscht wurde.
Im UndefFn kann man pruefen, ob es noch andere Modul-Instanzen gibt, und wenn nicht, ein Event per DoTrigger vor dem return senden. Ich habe aber Schwierigkeiten vorzustellen, wozu das gut sein soll.

Meine Vorschlaege sind teilweise nicht elegant, ich bin aber noch auf dem Standpunkt, dass man fuer seltene Sonderfaelle keine Abkuerzungen einbauen muss.