wie modul starten

Begonnen von justme1968, 12 Januar 2014, 12:09:48

Vorheriges Thema - Nächstes Thema

justme1968

was ist der 'offiziell' empfohlene weg beim modul start einmalig etwas zu initialisieren und z.b. mit internalTimer ein polling zu starten?

anfangs hatte ich das direkt in der defineFn gemacht. das bewirkt aber manchmal ein komplettes blockiere von fhem weil es noch nicht fertig initialisiert ist.

dann bin ich dazu übergegangen das per internalTimer etwa 10 sekunden zu verzögern. das ist aber keine gute lösung da es zum einen auch länger dauern kann bis alles läuft und zum ändern das auch beim define eines neuen device zur laufzeit dir unnötige verzögerung hat.

inzwischen hänge ich die initialisierung per notifyFn an global initialized und lösche sie dann damit sie zur laufzeit nicht unnötig performance frisst. ein define von hand zur laufzeit kann ich über $init_done rausfinden und dir initialisierung direkt zu machen.

das funktioniert im prinzip perfekt. nur das löschen verträgt sich nicht mit rereadcfg weil dort _initialize nicht aufgerufen wird und notifyFn somit nicht neu eingetragen wird.

abgesehen davon das rereadcfg noch andere unglückliche seiteneffekte hat wäre es für den zweck alles auf 'null' zu setzen vermutlich das richtigste _initialize für jedes modul aufzurufen auch wenn ein modul schon geladen ist.

oder rereadcfg abschaffen.

gruss
  andre

hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Zitatwas ist der 'offiziell' empfohlene weg beim modul start einmalig etwas zu initialisieren

FHEM ist nicht so auf die Welt gekommen, dass auf alles eine richtige/offizielle Antwort gibt, will sagen ich versuche eine Loesung zu finden, und wenn es nicht gut ist, dann muss man eine andere finden.

Die Loesung haengt von der Aufgabe ab:
- falls es Modulweit ist: in Initialize
- falls es Instanzweit, und die Aufgabe nicht von Attributen abhaengt (was ich besser finde), dann im DefineFn
- sonst per NotifyFn in global:INITIALIZED.

Ich sehe ein, dass die erste und letzte Methode nicht rereadcfg fest ist, und bin bereit es zu fixen:
rereadcfg sollte alle Initialize Funktionen der geladenen Module erneut aufrufen, und auch ein global:Initialized durchfuehren, hoffentlich gibts dadurch keine Nebeneffekte.

Frage: was soll mit der Liste der InternalTimer passieren?
- falls es bei rereadcfg geloescht wird, dann werden on-for-timer/etc Funktionen nach rereadcfg nicht ausgeloest.
- falls es nicht geloescht wird, dann besteht die Gefahr, dass im Initialize doppelte Timer gestartet werden.
Ich tendiere trotzdem zum nicht-Loeschen.

Ich wuerde rereadcfg auch gerne entfernen, aber etliche Dokumentationen beschreiben das Editieren von fhem.cfg im Frontend, und viele Leute fuehlen sich damit wohler, d.h. ein Loeschen wuerde ein Aufschrei zur Folge haben. Abgesehen davon gibt es ein paar Aufgaben, die z.Zt. nur durch das Editieren durchgefuehrt werden koennen, z.Bsp. das Aendern der Reihenfolge (fuer neues CUL, etc).

justme1968

ZitatFHEM ist nicht so auf die Welt gekommen, dass auf alles eine richtige/offizielle Antwort gibt, will sagen ich versuche eine Loesung zu finden, und wenn es nicht gut ist, dann muss man eine andere finden.
das ist mir klar. und einer der gründe warum das offiziell in anführungszeichen steht.

eigentlich sollte die reihenfolge egal sein und die config files am besten für den Benutzer (vor allem am anfang) gar nicht vorhanden sein. es kommt ja auch keiner auf die idee die windows registry oder eine db von hand zu sortieren damit es aufgeräumt ist oder um kommentare einzufügen. aber das ist ein anderes thema.

das erstmalige starten eines timers bei einem modul das pollt ist aber glaube schon so ein allgemeiner anwendungsfall das eine zumindest empfohlene lösung hilfreich ist. deshalb die frage. vor allem weil es sich zur zeit nicht gut lösen lässt. das kommt glaube ich zum teil auch daher das das NotifyFn modul weit gilt, der timer aber instanzweit. es im define zu verwenden geht nicht weil da fhem noch nicht 'läuft' und komplett blockieren kann.

vielleicht würde hier helfen eine IntializedFn auf modul ebene zu haben. damit wäre auch das timer problem gelöst.

wie wäre es ansonsten bei InternalTimer immer automatisch das RemoveInternalTimer zu machen wenn $arg gleich ist. ausser es wird explizit nicht gewünscht. das würde das versehentliche mehrfach starten im normal betrieb verhindern

ich hab gerade gesehen das InternalTimer ein $waitIfInitNotDone hat. das wartet aber doch nur blockierend oder? wie kann das überhaupt gehen? wie wäre es hier die internal timer zu merken und dann automatisch nach dem INITIALIZED aufzurufen?

ich glaube es wäre auch nicht schlecht zu empfehlen oder zum default zu machen die ganzen timer die beim initialized gestartet werden zufällig um einen kleinen betrag zu verzögern und so das starten über einen bereich zu verteilen. ich hab das beim owdevice modul gemacht und das verhindert das z.b. 10 temperatur sensoren zur gleichen zeit und damit direkt nacheinander gepolt werden und fhem länger blockieren.

wenn man konsequent IODev setzt/benutzt ist die reihenfolge egal.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Zitatvielleicht würde hier helfen eine IntializedFn auf modul ebene zu haben.

Das waere mehr oder weniger gleichwertig mit einem notify auf global:(INITIALIZED|REREADCFG), bloss dass sie das normale Eventhandling nicht blockiert. Ich habe nichts dagegen, ich habe aber auch ueberlegt die Benachrichtigung in fhem.pl so umzubauen, dass (falls am regexp erkennbar) nur zum Geraet passende notifies aufgerufen werden. Damit wuerde so ein notify im Normalbetrieb keine zusaetzliche Last bedeuten, und vermutlich auch die Last durch viele automatisch erzeugte FileLogs optimieren.

Zitatwie wäre es ansonsten bei InternalTimer immer automatisch das RemoveInternalTimer zu machen wenn $arg gleich ist.

Das habe ich trotz mehrmaligen lesen nicht kapiert.
$waitIfInitNotDone  sollte eigentlich abgeschafft werden, ich weiss inzwischen nicht mehr, wozu das gut sein soll.

Zitattimer die beim initialized gestartet werden zufällig um einen kleinen betrag zu verzögern
Die Idee gefaellt mir nicht wirklich, weil es ein Hack (pollen/blockieren) kaschiert, und ich noch nicht ueberzeugt bin, dass dieses Pollen notwendig ist :)

justme1968

ZitatDas wäre mehr oder weniger gleichwertig mit einem notify auf global:(INITIALIZED|REREADCFG), bloss dass sie das normale Eventhandling nicht blockiert. Ich habe nichts dagegen, ich habe aber auch ueberlegt die Benachrichtigung in fhem.pl so umzubauen, dass (falls am regexp erkennbar) nur zum Geraet passende notifies aufgerufen werden. Damit wuerde so ein notify im Normalbetrieb keine zusaetzliche Last bedeuten, und vermutlich auch die Last durch viele automatisch erzeugte FileLogs optimieren.
es wäre gleichwertig aber eben nebenwirkungsfrei und ohne probleme mit der rückwärts Kompatibilität.
_Intialize auch nach rereadcfg aufzurufen wäre konsistenter hat aber die probleme die du oben beschrieben hast.

so ein umbau ist vielleicht wirklich eine gute idee, würde aber nur anwender notifys betreffen und nicht die NotifyFn in einem modul da es keine regex gibt sondern diese immer aufgerufen wird. nützt also beim modul start nicht.


ZitatDas habe ich trotz mehrmaligen lesen nicht kapiert.
die aller meisten module verwenden InternTimer um genau eine aufgabe regelmässig auszuführen. wann man nicht selber darauf achtet vor jedem InternalTimer ein RemoveInternalTimer zu machen kann es ziemlich schnell passieren das man plötzlich meherer timer laufen hat. sei es durch modify, ein get oder set oder was auch immer.

diesen fehler könnte man verhindern wenn in InternalTimer immer ein RemoveInternalTimer gemacht wird wenn $arg gleich ist.

Zitat$waitIfInitNotDone  sollte eigentlich abgeschafft werden, ich weiss inzwischen nicht mehr, wozu das gut sein soll.
das beruhigt mich. dann lag es nicht an mir das ich es beim ansehen nicht verstanden habe.

statt es zu entfernen könnte man es aber auch genau zu dem verwenden was der name impliziert. den timer automatisch zu verzögern bis die initialisierung rum ist.

oder warum nicht gleich grundsätzlich alle aufrufe von InternalTimer während der initialisierung ($init_done == 0) bis zum $init_done = 1 verschieben. oder zumindest die die nur ein paar minuten oder sekunden verzögert laufen sollen. dann könnte man direkt im define den timer starten und muss sich keine gedanken um initialized oder rereadcfg machen und brauch auch keine InitalizedFn.



ZitatDie Idee gefaellt mir nicht wirklich, weil es ein Hack (pollen/blockieren) kaschiert, und ich noch nicht ueberzeugt bin, dass dieses Pollen notwendig ist :)
die frage das es mit der selectList richtiger oder mit BlockingCall besser gemacht wäre stellt sich bei devices die von sich aus nicht melden leider gar nicht erst. ohne pollen geht es hier nicht.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

justme1968

beim lesen fällt mir gerade ein das ich eigentlich gemeint habe die InitializedFn auf instanz ebene zu haben. also das fhem sie automatisch für jede definierte instanz aufruft wenn die initialisierung nach start oder rereadcfg fertig ist.

dann muss man sie nicht wie NotifyFn löschen weil sie nur genau dann aufgerufen wird und keinen overhead hat. wenn sie nicht gelöscht wird gibt es das auch das problem das sie nicht wieder eingetragen wird weil _Initialize nicht aufgerufen wird nicht.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

klaus.schauer

Ich würde es ebenfalls begrüßen, falls

  • es ein "initializedFn" geben würde. Dies ist deutlich übersichtlicher als die Lösung mit "notifyFn" und hat hoffentlich keine Seiteneffekte.
  • der InternalTimer selbst dafür sorgen würde, dass er nicht mehrfach läuft.

rudolfkoenig

 
Zitatwürde aber nur anwender notifys betreffen und nicht die NotifyFn in einem modul da es keine regex gibt sondern diese immer aufgerufen wird.
Nein, da ich das natuerlich Modulunabhaengig machen will: das Modul setzt ein notifyDevice: in deinem Fall ist das global, falls man es nicht setzt, dann wird man wie bisher fuer alle Events aufgerufen. Ist flexibler (fuer die unterschiedlichen Events) und gleichzeitig kompatibel zum alten Welt. Und notifyFn sollte man wg. rereadcfg nicht mehr loeschen. Die Schleife ueber die eigenen Geraete darf das Modul selbst durchfuehren.

Zitatdiesen fehler könnte man verhindern wenn in InternalTimer immer ein RemoveInternalTimer gemacht wird wenn $arg gleich ist.
Das koennen wir gerne machen, ich braeuchte nur Hilfe beim durchkaemmen der Module, ob das z.Zt. keine Probleme verursacht. Fuer meine Module uebernehme ich das natuerlich.

Timer immer zentral verschieben passt mir nicht: z.Bsp. will at immer genau um 12 laufen, waere aber verschoben, falls fhem direkt vor 12 gestartet wird. Welches Problem waere dadurch eigentlich geloest?

Ich meine waitIfInitNotDone kommt daher, dass man einem FHZ zum verdauen eines Befehls Zeit geben muss, und es wird mit etlichen Befehlen initialisiert. Wuesste aber jetzt auch nicht, wieso ohne diesen Flag nicht funktionieren sollte, vermutlich ist diese Loesung durch etliche Umbauten sinnlos geworden.

Zitatohne pollen geht es hier nicht.
Glaube ich nicht :), hoechstens dass es aufwendiger ist.
Gibt es unter Linux wirklich etwas, was man pollen _muss_ ?

justme1968

verstanden. ja das würde natürlich so gehen mit der optimierung. ich finde das klingt gut.


das verschieben ginge dann wenn man beim timer aufruf erkennen könnte ob der zeitpunkt absolut oder relativ sein soll. es würde auch nur die timer betreffen die im define und während des fhem starts erzeugt werden. also vor INITIALIZED.

das problem ist das wenn man im define einen InternalTimer startet und die zeit so kurz gewählt ist das fhem noch nicht fertig initialisiert ist es einige dinge gibt die noch nicht gehen (z.b. werden sockets noch nicht bedient) und alles hängen bleiben kann. wenn man die zeit zu lang wählt verschenkt man zeit. deshalb der weg über NotifyFn um mit dem INITIALIZED richtig anzufangen. was aber wegen rereadcfg nicht geht wenn man es löscht. dafür wäre eine InitializedFn die auf instanz ebene aufgerufen wird eben gut.


diverse 'moderne' devices und dienste die über web api angesprochen werden und keine sockets unterstützen. z.b. 1-wire, hue, diverse av geräte, ... oder mail-server die (noch) kein idle unterstützen mir fallen noch viele ein.

ja. das ist schlechter design und gehört eigentlich auf der anderen seite repariert.

natürlich kann man zwischen fhem und so einem device immer einen extra prozess hängen und das pollen dahin verlagert und so das ganze dann auch noch nicht blockierend macht. das ist aber manchmal schon mit kanonen auf spatzen geschossen. und keiner der das bis jetzt allgemein angegangen ist ist schon fertig damit.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Ich habe meinen Vorschlag implementiert:
- falls eine Instanz im $hash->{NOTIFYDEV} setzt, dann wird NotifyFn nur dann aufgerufen, falls das Event von der passenden Instanz generiert wurde.
- in autocreate wird NOTIFYDEV auf "global" gesetzt
- notify&FileLog setzen diesen Eintrag, falls das "Geraete-Teil" des Regexps als Instanz existiert. Das sollte fuer die meisten per autocreate angelegten FileLogs zutreffen, und hoffentlich auf nichts unbeabsichtigtes.
- falls kein NOTIFYDEV existiert, dann wird NotifyFn fuer alles wie bisher aufgerufen.

Ich hoffe ich habe nichts uebersehen, wenn doch, bitte melden.

justme1968

ich komme jetzt erst dazu das mal zu probieren. und bei mir schaut es bei mir gut aus.

es gibt aber einen thread in dem es probleme mit notifys gib. eventuell hängt es mit der änderung zusammen.

hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig


justme1968

hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

rudolfkoenig

Danke, habs gefixed. Einchecken hat laenger gedauert, da sourceforge zwischenzeitlich gesponnen hat (permission denied??)

Tobias

Zitat von: rudolfkoenig am 14 Januar 2014, 20:35:37
Ich habe meinen Vorschlag implementiert:
- falls eine Instanz im $hash->{NOTIFYDEV} setzt, dann wird NotifyFn nur dann aufgerufen, falls das Event von der passenden Instanz generiert wurde.
- in autocreate wird NOTIFYDEV auf "global" gesetzt
- notify&FileLog setzen diesen Eintrag, falls das "Geraete-Teil" des Regexps als Instanz existiert. Das sollte fuer die meisten per autocreate angelegten FileLogs zutreffen, und hoffentlich auf nichts unbeabsichtigtes.
- falls kein NOTIFYDEV existiert, dann wird NotifyFn fuer alles wie bisher aufgerufen.

Ich hoffe ich habe nichts uebersehen, wenn doch, bitte melden.

Hab ich noch nicht verstanden... Gibts wo ein Beispiel? Wäre ein Fall fürs Wiki..??
Maintainer: Text2Speech, TrashCal, MediaList

Meine Projekte: https://github.com/tobiasfaust
* PumpControl v2: allround Bewässerungssteuerung mit ESP und FHEM
* Ein Modbus RS485 zu MQTT Gateway für SolarWechselrichter