72_UBUS.pm Code Review / Feedback

Begonnen von xenos1984, 08 August 2021, 17:47:27

Vorheriges Thema - Nächstes Thema

xenos1984

Ich arbeite gerade an einem neuen Modul, das ich - nach kritischer Prüfung - gerne unter FHEM einchecken und damit auch betreuen möchte. Es dient dem Zugriff auf uBus:

http://openwrt.org/docs/guide-developer/ubus

Neben der dort angegebenen Kommandozeile und HTTP als Zugriffsmethode habe ich auch Websocket implementiert, wie es u.a. von JUCI benutzt wird:

https://github.com/mkschreder/juci

Zum selbst testen habe ich aber leider nur letzteres auf meinem Router zur Verfügung.

Vielleicht mag jemand einen Blick auf den Code werfen und Kritik daran üben, die ich gerne entgegennehme und verbessere. Falls jemand Hardware zum testen hat, ist das natürlich noch besser. An der Dokumentation arbeite ich noch; zumindest die Definition und die notwendigen Attribut / Set Werte sind drin, falls jemand vorab testen möchte.

Das Modul fragt in regelmäßigen Abständen verschiedene Daten ab (Systeminfo, darunter Speicher und CPU Auslastung; verbundene Clients; Netzwerk-Ports und deren Datenvolumen; Wifi-Schnittstellen; Netzwerk-Interfaces; Telefonleitungen) und erzeugt entsprechende Readings. Ich arbeite noch an weiteren Set-Befehlen, z.B. zum Reboot und zum setzen von Einstellungen, aktivieren / deaktivieren von WAN und W-LAN etc.

Die 72_ habe ich in Anlehnung an 72_FRITZBOX.pm genommen - die Funktion sollte ähnlich sein.

Beta-User

Einen vollständigen review habe ich nicht gemacht, hier mal eine Version mit ein paar (teils exemplarischen) Änderungen, die mir sinnvoll erschienen. Bitte ggf. nachfragen.

Hardware habe ich keine, hatte ein websocket-Testgerät definiert, und das schreibt ziemlich häufig fehlgeschlagene Verbindungsversuche ins log...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

xenos1984

Zitat von: Beta-User am 31 August 2021, 18:12:29
Einen vollständigen review habe ich nicht gemacht, hier mal eine Version mit ein paar (teils exemplarischen) Änderungen, die mir sinnvoll erschienen. Bitte ggf. nachfragen.

Danke für das Feedback! Ein paar Nachfragen habe ich bestimmt, wenn ich die Änderungen im Detail durchgegangen bin.

Zitat
Hardware habe ich keine, hatte ein websocket-Testgerät definiert, und das schreibt ziemlich häufig fehlgeschlagene Verbindungsversuche ins log...

Hm... Ja, ich habe ein paar Meldungen mit verbose=1 ("error messages or unknown packets") drin, wenn etwas fehlschlägt, insbesondere der Verbindungsaufbau. Ich hatte mich da im Wesentlichen am Wiki-Beispiel zu DevIo orientiert, aber vielleicht kann man die Anzahl der Verbindungsversuche oder die Häufigkeit reduzieren, wenn keine Antwort kommt.

Beta-User

Zitat von: xenos1984 am 31 August 2021, 22:11:03
Danke für das Feedback! Ein paar Nachfragen habe ich bestimmt, wenn ich die Änderungen im Detail durchgegangen bin.
Gerne.

Ergänzend vielleicht noch:
return DevIo_OpenDev($hash, 0, "FHEM::UBUS::Init", "FHEM::UBUS::Callback") if !DevIo_IsOpen($hash);müßte eigentlich auch funktionieren, wenn man Referenzen übergibt:
return DevIo_OpenDev($hash, 0, \&Init, \&Callback) if !DevIo_IsOpen($hash);

Weiter unten kommen dann ja ziemlich viele (teilweise noch auskommentierte) readingsBulkUpdate-Zeilen. Bis auf wenige Ausnahmen entsprechen da die Teilstrings für die Readingnamen dem, was aus decode_json an keys kommt. Die Teile könnte man in eine Schleife packen.

ZitatHm... Ja, ich habe ein paar Meldungen mit verbose=1 ("error messages or unknown packets") drin, wenn etwas fehlschlägt, insbesondere der Verbindungsaufbau. Ich hatte mich da im Wesentlichen am Wiki-Beispiel zu DevIo orientiert, aber vielleicht kann man die Anzahl der Verbindungsversuche oder die Häufigkeit reduzieren, wenn keine Antwort kommt.
Na ja, ich hatte pro Sekunde einige Zeilen nach dem Muster
<timestamp> 3: Opening <UBUS-Instanz-Name> device ws:<ip>
Habe aber nicht untersucht, wo das im Detail herkommt; u.A. war das der Hintergrund, warum ich den default für $interval von 0 auf 60 geändert hatte, hat aber nicht geholfen...

Generell fehlt gefühlt bei der Initialisierung eine Option, das Gerät (vorübergehend) zu deaktivieren - "none" als Interface, attr disabled, set inactive, IsDisabled() usw.. Evtl. übersehe ich da aber auch was.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

xenos1984

Zitat von: Beta-User am 01 September 2021, 10:02:34
Na ja, ich hatte pro Sekunde einige Zeilen nach dem Muster
<timestamp> 3: Opening <UBUS-Instanz-Name> device ws:<ip>
Habe aber nicht untersucht, wo das im Detail herkommt; u.A. war das der Hintergrund, warum ich den default für $interval von 0 auf 60 geändert hatte, hat aber nicht geholfen...
Ah... Ich denke, ich habe es gefunden. Das macht DevIo.pm:


427   my $l = $hash->{devioLoglevel}; # Forum #61970
428   Log3 $name, ($l ? $l:3), ($hash->{DevioText} ? $hash->{DevioText} : "Opening").
429        " $name device ". (AttrVal($name,"privacy",0) ? "(private)" : $dev)
430        if(!$reopen);


Üblicherweise also auf verbose=3. Das kommt mir doch etwas arg vor, ich würde es eher auf 4 setzen (indem ich $hash->{devioLoglevel} = 4 im Modul einbaue).

Zitat
Generell fehlt gefühlt bei der Initialisierung eine Option, das Gerät (vorübergehend) zu deaktivieren - "none" als Interface, attr disabled, set inactive, IsDisabled() usw.. Evtl. übersehe ich da aber auch was.

Ja, gute Idee, das habe ich in der Tat nicht bedacht - das baue ich auf jeden Fall ein.

Beta-User

Bzgl. DevIo: eigentlich sind dort für neue Anläufe 60 Sekunden hinterlegt, wenn ich den Code richtig interpretiere. Evtl. ist das auch ein spezielles Wind.*-Thema - das Testsystem läuft auf win32-strawberry-Perl (5.32)....

Verbose 3 finde ich dagegen ok, man kann das ja einstellen; mir kommen eher die vielen Versuche komisch vor.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

xenos1984

Ich habe mal etwas nachgeforscht und probiert, was bei mir (Ubuntu 20.04) passiert, wenn ich eine nicht vorhandene Websocket-Adresse eingebe. Gleiches Ergebnis, Verbindungsversuch einmal pro Sekunde. Und ich konnte auch den Grund finden. So häufig wird nämlich Ready aufgerufen, und das versucht dann, mittels Connect die Verbindung wieder aufzubauen. Dabei habe ich mich nur an das Schema aus dem Beispiel gehalten...

http://wiki.fhem.de/wiki/DevIo#TCP.2FIP-Verbindung


# called repeatedly if device disappeared
sub MY_MODULE_Ready($)
{
  my ($hash) = @_;
 
  # try to reopen the connection in case the connection is lost
  return DevIo_OpenDev($hash, 1, "MY_MODULE_Init", "MY_MODULE_Callback");
}


Ich werde mal sehen, was andere Module da machen. Eine Möglichkeit, Verbindungsversuche komplett abzuschalten, baue ich aber auf jeden Fall auch noch ein.

Inzwischen bin ich auch deine anderen Kommentare durchgegangen und habe sie im wesentlichen umgesetzt. Meine ursprünglichen Nachfragen haben sich beim Nachschlagen in PBP auch geklärt ;)

parseParams werde ich mir auch noch ansehen. Für den Anfang hatte ich mich noch nicht darin vertieft, weil es kaum Parameter zu parsen gab, aber inzwischen sind es bei define und set doch ein paar mehr geworden, da erscheint es sinnvoll.

Eine neue Version kommt, sobald ich o.g. eingebaut habe.

xenos1984

Hier ist erst einmal der aktuelle Stand. Ein paar Funktionen habe ich umstrukturiert, unnötige Wiederholungen durch Schleifen ersetzt und ein paar mehr Perl-Konventionen beachtet. Außerdem habe ich jetzt attr disable und set disable / enable eingebaut, um das Modul zu deaktivieren.

Zum Problem mit den häufigen Verbindungsversuchen habe ich noch keine schlüssige Lösung. So weit ich sehe, benutzt sonst nur 69_SoftliqCloud.pm WebSocket mit DevIo, und da macht Ready nichts - die Logik zum Verbinden sitzt anderswo. Wenn ich es aber ganz aus Ready rausnehme, passiert nach einem fehlgeschlagenen Verbindungsversuch nichts mehr, auch nicht nach 60 Sekunden. Vielleicht kann Rudi etwas dazu sagen, wie hier die beabsichtigte Vorgehensweise ist für Module, die DevIo benutzen?

parseParams sehe ich mir noch im Detail an und baue es dann ein - noch ist es nicht drin.

Beta-User

...bislang ist mir beim auf den Code starren auch nichts aufgefallen, an was es ggf. hängt...

Evtl. gibt es (allerdings nicht mit ws) einen reconnect-loop-"Zwilling": https://forum.fhem.de/index.php/topic,122767.msg1173072.html#msg1173072 (müßte dafür aber auch erst mal ein passendes Testsystem aufsetzen, und eigentlich ist MQTT-old auch nicht meine bevorzugte Baustelle...)

(Fast) ganz aus ready raus klingt aber uU. doch nach einem Ansatzpunkt, die Frage ist dann aber, wer nach einem fehlgeschlagenen Versuch dann (wann?) den nächsten initiieren sollte. So beim Überfliegen (!) hatte ich den Eindruck, dass die ganze Timer-Logik eigentlich auf DevIo-Seite liegen soll, aber das kann auch täuschen...

Die reconnects sind jedenfalls bei mir im Testsystem ca. Faktor 8-12 häufiger, an "sekündlich" glaube ich also noch nicht als Frequenz.

Falls du ein Implementierungsbeispiel für parseParams (an "allen Ecken") suchst: RHASSPY (contrib)

Ansonsten wäre "perltidy" noch ein Stichwort. Tabulatoren sind grausam...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

xenos1984

Zitat von: Beta-User am 06 September 2021, 16:30:44
...bislang ist mir beim auf den Code starren auch nichts aufgefallen, an was es ggf. hängt...

Evtl. gibt es (allerdings nicht mit ws) einen reconnect-loop-"Zwilling": https://forum.fhem.de/index.php/topic,122767.msg1173072.html#msg1173072 (müßte dafür aber auch erst mal ein passendes Testsystem aufsetzen, und eigentlich ist MQTT-old auch nicht meine bevorzugte Baustelle...)

(Fast) ganz aus ready raus klingt aber uU. doch nach einem Ansatzpunkt, die Frage ist dann aber, wer nach einem fehlgeschlagenen Versuch dann (wann?) den nächsten initiieren sollte. So beim Überfliegen (!) hatte ich den Eindruck, dass die ganze Timer-Logik eigentlich auf DevIo-Seite liegen soll, aber das kann auch täuschen...

Eine Möglichkeit wäre, bei jedem Verbindungsversuch einen Zeitstempel zu merken, und in Ready nur dann einen neuen Versuch zu unternehmen, wenn eine (setzbare) Wartezeit abgelaufen ist. Ich werde das mal versuchen.

ZitatDie reconnects sind jedenfalls bei mir im Testsystem ca. Faktor 8-12 häufiger, an "sekündlich" glaube ich also noch nicht als Frequenz.

Mit was versuchst du denn zu verbinden? Ich habe ws://<nicht vorhandene IP> genommen - vielleicht braucht es dann einfach eine Sekunde, bis mein Router meldet, dass es die IP nicht gibt. Ich werde das aber auch noch mal mit Wireshark o.ä. anschauen, ob das die Frequenz erklärt.

ZitatFalls du ein Implementierungsbeispiel für parseParams (an "allen Ecken") suchst: RHASSPY (contrib)

Danke! Das sieht ja recht überschaubar aus. Ich werde mal schauen, wie gut es mit der Struktur von define und set bei meinem Modul zusammenpasst. Benannte Parameter habe ich bislang nicht, aber unbenannte Parameter trennen ist schon praktisch (wenn es nicht an ungewollten Stellen passiert). Aber so weit ich sehe, würde es wohl auch einen JSON-Block intakt lassen (den übergebe ich derzeit mit set <name> rpc <...> zum Testen neuer Funktionsaufrufe).

ZitatAnsonsten wäre "perltidy" noch ein Stichwort. Tabulatoren sind grausam...

Das ist vermutlich eine viel diskutierte Frage ;) Und wohl eine, auf die jeder Programmierer (auch wenn ich mich nicht so nennen würde) seine eigene Antwort hat. Ja, PBP und perltidy empfehlen Leerzeichen, weil man dann immer die gleiche Einrückung bekommt. Anderenorts bevorzugt man Tabs, und überlässt die angezeigte Breite der Einrückung dem Editor bzw. dem dort vom Benutzer eingestellten Wert... Meine Prämisse ist, konsistent vorzugehen, eine Einrückungsebene immer gleich zu formatieren und nicht mit anderen zu mischen (d.h. entweder nur Tabulatoren oder nur Leerzeichen, nie beides), und bevorzugt "eine Ebene = ein Zeichen". Aber wie gesagt, ich denke, das ist eine Frage der Philosophie, und wenn ich mir die existierenden Module ansehe, kommt wohl beides vor (teilweise nicht konsistent und gemischt - das finde ich grausam...).

Beta-User

Zitat von: xenos1984 am 07 September 2021, 10:06:22
Eine Möglichkeit wäre, bei jedem Verbindungsversuch einen Zeitstempel zu merken, und in Ready nur dann einen neuen Versuch zu unternehmen, wenn eine (setzbare) Wartezeit abgelaufen ist. Ich werde das mal versuchen.
Hmm, setzt halt voraus, dass der "flow control" von UBUS aus gemacht wird; eigentlich war ich davon ausgegangen, dass das DevIo machen sollte und nur die timeout-Parameter ggf. beizusteuern wären.

Habe gestern noch ein wenig mit 00_MQTT gespielt und dabei teilweise die return-Werte von $callback (\&Ready) und \&Start geändert, z.B. von
  DevIo_CloseDev($hash);
  return DevIo_OpenDev($hash, 0, "MQTT::Init");
}

nach
  DevIo_CloseDev($hash);
  DevIo_OpenDev($hash, 0, &Init);
  return;
}

Damit scheint sich zumindest das Fehlerbild teils geändert zu haben...

Zitat
ws://<nicht vorhandene IP>
Ja, dto. hier, ich kann aber nicht sagen, wie schnell da die Rückmeldung erfolgt.

Zitat
Danke! Das sieht ja recht überschaubar aus. Ich werde mal schauen, wie gut es mit der Struktur von define und set bei meinem Modul zusammenpasst. Benannte Parameter habe ich bislang nicht, aber unbenannte Parameter trennen ist schon praktisch (wenn es nicht an ungewollten Stellen passiert). Aber so weit ich sehe, würde es wohl auch einen JSON-Block intakt lassen (den übergebe ich derzeit mit set <name> rpc <...> zum Testen neuer Funktionsaufrufe).
Ist es. Für RHASSPY war mehr "Text-Block" und weniger das JSON-Geklammere relevant, aber z.B. MQTT_GENERIC_BRIDGE nutzt das auch für das Erkennen von Perl-Kommandos ;) .

Zitat
wenn ich mir die existierenden Module ansehe, kommt wohl beides vor (teilweise nicht konsistent und gemischt - das finde ich grausam...).
fully agreed ;D .
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

xenos1984

Zitat von: Beta-User am 07 September 2021, 10:28:38
Hmm, setzt halt voraus, dass der "flow control" von UBUS aus gemacht wird; eigentlich war ich davon ausgegangen, dass das DevIo machen sollte und nur die timeout-Parameter ggf. beizusteuern wären.

Letzteres habe ich auch gedacht, wobei ich die derzeitige Funktionsweise so verstehe, dass DevIo das Gerät bzw. dessen Hash einfach nur in die %readyfnlist einträgt, wenn die Verbindung nicht vorhanden ist, und bei vorhandener Verbindung entfernt. Die ReadyFn wird dann periodisch von fhem.pl für alle Geräte auf der Liste aufgerufen. Darauf, wie oft das geschieht, scheint DevIo aber keinen Einfluss zu nehmen, insbesondere auch keinen Timeout / Begrenzung der Zahl oder Häufigkeit der Versuche. Das scheint auch gar nicht vorgesehen zu sein, es wird eben immer die ganze Liste in einem bestimmten Intervall abgearbeitet (s.u.).

ZitatHabe gestern noch ein wenig mit 00_MQTT gespielt und dabei teilweise die return-Werte von $callback (\&Ready) und \&Start geändert

So weit ich sehe, hängt davon ab, ob anschließend von fhem.pl ReadFn aufgerufen wird oder nicht:


833   foreach my $p (keys %readyfnlist) {
834     next if(!$readyfnlist{$p});                 # due to rereadcfg / delete
835
836     if(CallFn($readyfnlist{$p}{NAME}, "ReadyFn", $readyfnlist{$p})) {
837       if($readyfnlist{$p}) {                    # delete itself inside ReadyFn
838         CallFn($readyfnlist{$p}{NAME}, "ReadFn", $readyfnlist{$p});
839       }
840
841     }
842   }

Beta-User

...das deckt sich mit dem, wie es in https://wiki.fhem.de/wiki/DevIo#Allgemeine_Funktionsweise beschrieben ist. Stellt sich die Frage, ob eine "disabled" Verbindung dann überhaupt auf diese Weise detektiert werden kann...

Na ja, ein Blick in MQTT2_CLIENT zeigt: Rudi setzt anscheinend den timeout in der readyfn (MQTT2_CLIENT_connect). Da MQTT2_CLIENT das neueste der von Rudi selbst entworfenden Module ist, sollten wir (ich habe grade ein halbes Auge auf MYSENSORS) uns ggf. dann da mal näher umschauen.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

xenos1984

Scheint, als hätte ich den Schuldigen gefunden - der Hinweis hat geholfen, wenn auch indirekt. nextOpenDelay wird von DevIo als 60 Sekunden angenommen, wenn es nicht gesetzt ist - das scheint es also nicht zu sein. Aber beim nochmaligen Lesen des Wiki ist mir aufgefallen, dass ich vergessen habe, beim erneuten Verbindungsversuch das reopen-Flag in DevIo_OpenDev zu setzen. Jetzt habe ich Ready so geändert:


sub Ready
{
my ($hash) = @_;
my $name = $hash->{NAME};

return if IsDisabled($name) || $hash->{method} ne "websocket" || DevIo_IsOpen($hash);

Log3($name, 5, "UBUS ($name) - reconnect");

return DevIo_OpenDev($hash, 1, \&Init, \&Callback);
}


(DevIo wird ohnehin nur bei WebSocket URL benutzt.) Jetzt wird Ready zwar immer noch häufig aufgerufen, aber führt nicht mehr jedes Mal zu einem Verbindungsversuch, sondern brav einmal pro Minute:


2021.09.07 20:09:19 5: HttpUtils url=http://192.168.1.2:80/ NonBlocking via http
2021.09.07 20:09:19 4: IP: 192.168.1.2 -> 192.168.1.2
2021.09.07 20:09:22 1: UBUS (juci) - error while connecting: connect to http://192.168.1.2:80 timed out
2021.09.07 20:09:27 5: UBUS (juci) - reconnect
2021.09.07 20:09:32 5: UBUS (juci) - reconnect
2021.09.07 20:09:37 5: UBUS (juci) - reconnect
2021.09.07 20:09:42 5: UBUS (juci) - reconnect
2021.09.07 20:09:47 5: UBUS (juci) - reconnect
2021.09.07 20:09:52 5: UBUS (juci) - reconnect
2021.09.07 20:09:57 5: UBUS (juci) - reconnect
2021.09.07 20:10:02 5: UBUS (juci) - reconnect
2021.09.07 20:10:07 5: UBUS (juci) - reconnect
2021.09.07 20:10:12 5: UBUS (juci) - reconnect
2021.09.07 20:10:13 5: UBUS (juci) - reconnect
2021.09.07 20:10:18 5: UBUS (juci) - reconnect
2021.09.07 20:10:23 5: UBUS (juci) - reconnect
2021.09.07 20:10:23 5: HttpUtils url=http://192.168.1.2:80/ NonBlocking via http
2021.09.07 20:10:23 4: IP: 192.168.1.2 -> 192.168.1.2
2021.09.07 20:10:26 1: UBUS (juci) - error while connecting: connect to http://192.168.1.2:80 timed out


Übrigens habe ich auch noch eine Vermutung, was die unterschiedliche Frequenz der Ready-Aufrufe verursachen könnte. Hat dein Testsystem noch andere TCP-Verbindungen am Laufen? Bei mir ist es ein leeres System mit nur dem UBUS und FHEMWEB, das alle 5 Sekunden aktualisiert.

http://svn.fhem.de/trac/browser/trunk/fhem/FHEM/DevIo.pm#L487


487     # This part is called every time the timeout (5sec) is expired _OR_
488     # somebody is communicating over another TCP connection. As the connect
489     # for non-existent devices has a delay of 3 sec, we are sitting all the
490     # time in this connect. NEXT_OPEN tries to avoid this problem.


Aktueller Code ist angehängt.

Beta-User

OK, so langsam macht das auch für mich Sinn...

Wenn "Ready" so oft aufgerufen wird, sollte sie möglichst effizient sein. Daher sollte man m.E.:
- die Abfragen für das direkte return umdrehen (IsOpen, websocket, IsDisabled)
- Log3 auskommentieren (wir wissen ja jetzt (hoffentlich), dass die einfach in der Main-loop - optimalerweise mehrfach sekündlich - mitläuft).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files