NEWS
[gelöst] Datenpunkte zyklisch oder ereignisgesteuert lesen
-
@mickym said in Datenpunkte zyklisch oder ereignisgesteuert lesen:
@blockmove nun beim Scriptaufruf gebe ich Dir natürlich Recht, das stand nach meinem Verständnis gar nicht zur Debatte. Du wirst immer Pollen müssen, wenn sich etwas nicht aktiv meldet. Ich bin beim Skriptaufruf jetzt davon ausgegangen, dass dies zum Ermitteln von States zeitgesteuert aufgerufen wird. Also alles gut. Wie Du sagst das richtige Mittel zur richtigen Zeit und so habe ich den Threadtitel verstanden.
Dein Beispiel mit Tasmota spricht sogar mehr den zyklischen Aufruf als dagegegen:
Nehmen wir mal an du hast ein Tasmota-Device an einem Helligkeitssensor hängen der dir alle 100ms einen neuen Wert liefern kann. Unter Umständen hast du nun alle 100ms eine Wertänderung und einen Trigger und somit einen Scriptaufruf. Willst du nun dein Script "stabil" machen, musst du entsprechende Vorkehrungen treffen. Rufst du im Gegensatz dein Script nur alle 500ms auf, dann ist es deutlich einfacher..Die andere Möglichkeit ist die die Trigger innerhalb der 500ms zu ignorieren. Gibt immer mehrfache Wege. Letztlich geht es immer um Effizienz und das es nicht ins philosophische abgleitet. Eine ähnliche Diskussion hatte ich kürzlich bei einem Node Red Flow, wobei es sicher resourcenschonender war den Flow früher abzubrechen, sich das aber In diesem Fall auf einem iobroker System auf dem Raspberry sicher nicht mehr energetisch messen läßt.
Das Thema gibt es bei ganz vielen Systemen, nicht nur bei Node RED oder ioBroker.
Ich muss da auch immer schmunzeln. Da nimmt man ein schwachbrüstiges IoT-Gateway oder nen simplen Pi3 und packt Dinge drauf, dass einem schwindlig wird. Nachher wundert man sich, wenn Reaktionszeiten oder sonstiges Zeitverhalten nicht mehr nachvollziehbar sind.
Mein alter Chef hatte da nen schönen Spruch "Es ist nicht immer das Wass Schuld, wenn die Ente nicht schwimmen kann". -
@blockmove sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Ich programmiere beruflich SPS-Steuerungen. Dort werden Variablen im Prinzip generell zyklisch bearbeitet. Die Zykluszeit beträgt meist so um 10-30ms.
Hast du ein Script, dass auf viele Datenpunkte zugreift, dann vereinfacht die zyklische Bearbeitung das ganz erheblich. So definierst du dir einmal deinen zyklischen Aufruf, im anderen Fall brauchst du für jede relevante Variable einen Trigger. Im dümmsten Fall, hast du noch eine gegenseitige Beeinflussung, so dass du evtl. sogar Trigger sperren musst.
.....Du beschreibst so ziemlich genau meine Situation. Auch ich komme aus der Automatisierungstechnik und bin dadurch das zyklische Abarbeiten gewohnt.
Bei meiner Anwendung geht es um das Laden eines E-Autos mit überschüssiger PV-Energie, sogenanntes Überschussladen.
Mein Skript verarbeitet dabei relativ viele Datenpunkte, die größtenteils auch kombiniert werden müssen, bzw. voneinander abhängig sind.
Hier mal die Visu. mit ersten Werten (noch nicht vollständig).
-
@asgothian sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
.....
ich würde die Datenpunkte generell per On() auslesen und in Variablen speichern. Zusammen mit einem Auslesen beim Skriptstart hast du dann im Skript zu jedem Zeitpunkt ein sauberes Abbild der Datenpunkte und musst nicht zur Ermittlung der Werte an die Objektstates.
.....Danke für die ausführliche Erklärung.
Das Einlesen der Datenpunkte werde ich ereignisgesteuert ausführen.
Das restliche Programm als zyklische Routine, weil ich das leichter verstehe. -
@hub01 said in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Du beschreibst so ziemlich genau meine Situation. Auch ich komme aus der Automatisierungstechnik und bin dadurch das zyklische Abarbeiten gewohnt.
Bei meiner Anwendung geht es um das Laden eines E-Autos mit überschüssiger PV-Energie, sogenanntes Überschussladen.
Mein Skript verarbeitet dabei relativ viele Datenpunkte, die größtenteils auch kombiniert werden müssen, bzw. voneinander abhängig sind.Genau die selbe Anwendung habe ich auch.
Ich habe auch zuerst mit Triggern angefangen und nach dem die Variablen und Abhängigkeiten immer mehr wurden, habe ich auf eine zylische Bearbeitung umgestellt.
Mir also im Prinzip eine SPS im ioBroker nachgebaut.
Aus meiner Sicht für den Anwendungsfall deutlich einfacher und strukturierter als die Lösung mit zig Triggern. Einfach feste zeitliche Aufrufe mit konsitenten Daten. -
@hub01 sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Die Datenpunkte ändern sich unterschiedlich, von oft (sekündlich) bis selten (monatlich).
Wenn die DP sich sekündlich ändern, dann reicht es imho aus dass das Skript einmal pro Sekunde läuft, nicht 2mal.
Ich würde es ereignisgesteuert machen, weil das Skript dann nur läuft wenn es laufen muss, sprich wenn sich ein relevanter DP geändert hat. -
@amg_666 said in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Ich würde es ereignisgesteuert machen, weil das Skript dann nur läuft wenn es laufen muss, sprich wenn sich ein relevanter DP geändert hat.
Dann denk doch mal im Detail darüber nach:
Datenpunkte im ioBroker ändern sich nicht deterministisch.
Der Zeitpunkt an dem sich ein Datenpunkt ändert, ist quasi zufällig.
Beispiel: Mein Senec-Speicher liefert alle 3s neue Werte, die Wallbox etwa jede Sekunde, der Heizstab alle 500ms und das Auto alle x Minuten. Von all diesen Quellen sind aber bestimmte Datenpunkte relevant. Wenn ich sowas also per Trigger löse, weiß ich letztlich nichtmal wann und wie oft das Script aufgerufen wird. Die Wahrscheinlichkeit ist sehr, sehr groß, dass ich das Script deutlich häufiger aufrufe, wie bei einem zyklischen Aufruf alle 500ms.
Was ist nun besser? -
@hub01 sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
@asgothian sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
.....
ich würde die Datenpunkte generell per On() auslesen und in Variablen speichern. Zusammen mit einem Auslesen beim Skriptstart hast du dann im Skript zu jedem Zeitpunkt ein sauberes Abbild der Datenpunkte und musst nicht zur Ermittlung der Werte an die Objektstates.
.....Danke für die ausführliche Erklärung.
Das Einlesen der Datenpunkte werde ich ereignisgesteuert ausführen.
Das restliche Programm als zyklische Routine, weil ich das leichter verstehe.Gerade in diesem Fall ist eine zyklische Abarbeitung eher weniger Sinnvoll.
Letztendlich ist eine Aktion (Ändern des Ladevorgangs, Aktualisierung der Darstellung) nur Sinnvoll wenn sich Werte auch geändert haben. Dabei gibt es in dem was ich da sehe keinen Wert der sich nur aus Vorgabewerten und Zeit berechnen lässt.
Zum Thema komplizierter:
Du baust dir eine Funktion "Aktion_ausführen". In dieser verarbeitest du alle gespeicherten Variablen. Zusätzlich merkst Du dir in einer Variable "Timestamp" wann die Funktion gelaufen ist.
Diese Funktion rufst du aus jedem Trigger NACH dem aktualisieren der Variablen auf.
Aus dem Unterschied zwischen "jetzt" und "Timestamp" kannst du Berechnungen anstellen die auf den Zeitunterschied zwischen 2 Änderungen angewiesen sind.
-
@blockmove sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
@amg_666 said in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Ich würde es ereignisgesteuert machen, weil das Skript dann nur läuft wenn es laufen muss, sprich wenn sich ein relevanter DP geändert hat.
Dann denk doch mal im Detail darüber nach:
Datenpunkte im ioBroker ändern sich nicht deterministisch.
Der Zeitpunkt an dem sich ein Datenpunkt ändert, ist quasi zufällig.
Beispiel: Mein Senec-Speicher liefert alle 3s neue Werte, die Wallbox etwa jede Sekunde, der Heizstab alle 500ms und das Auto alle x Minuten. Von all diesen Quellen sind aber bestimmte Datenpunkte relevant. Wenn ich sowas also per Trigger löse, weiß ich letztlich nichtmal wann und wie oft das Script aufgerufen wird. Die Wahrscheinlichkeit ist sehr, sehr groß, dass ich das Script deutlich häufiger aufrufe, wie bei einem zyklischen Aufruf alle 500ms.
Was ist nun besser?Bleiben wir bei Deinem Beispiel:
der Scenec-Speicher ist wichtig - immer wenn der was ändert muss das Skript laufen.
der Heizstab ist bedingt wichtig - da kann das aktivieren der Berechnungen auf signifikante Änderungen begrenzt werden. Diese wird es nur selten geben. Das ist Ereignisgesteuert möglich.
Wallbox und Auto sind letztendlich abhängige Werte - auch hier kann man auf signifikante Änderungen reagieren, oder nur wenn die Werte "out of cycle" geändert werden rechnen.In dem in meinem vorigen Post bereitgestellten Beispiel kann zusätzlich das Durchführen der Berechnung über einen einfachen Zeitvergleich (wann zuletzt gelaufen mit jetzt) auf eine Maximalfrequenz eingestellt werden.
Damit bist du immer effektiver als mit einer reinen Zeitsteuerung. Insbesondere da du bei der Zeitsteuerung die Frequenz recht hoch wählen musst, damit du schnell genug auf eine relevante Änderung reagieren kannst.
A.
Nachtrag: Der grosse Vorteil des Event-gesteuerten Ansatzes ist ja gerade das durch die einzelnen Events fein auf die Notwendigkeiten reagiert werden kann und nicht blind alle x ms alles neu gemacht wird.
-
Du begrenzt also die Maximalfrequenz durch einen Zeitvergleich ... hmmm
Alternativ kann ich parallel zum star zyklischen Aufruf das Script auch durch einen Trigger eventgesteuert aufrufen. Letztlich funktioniert alles.Das Schöne ist ganz einfach, dass beide Aufrufvarianten möglich sind.
Wie schon geschrieben, haben beide Systeme ihre absolute Daseinsberechtigung und ihre Vor- und Nachteile. Wichtig ist einfach, dass man das Systemverhalten und die Auswirkungen weiß.
Ich kenne die Diskussion seit über 30 Jahren und bin da recht entspannt. Jeder soll das Verwenden, was ihm lieber ist. -
Hallo zusammen,
auf Grund der regen Diskussion habe ich mal die Zeit gemessen, die mein Skript in Anspruch nimmt.
Diese schwankt zwischen 2 und 4 Millisekunden.
Das Ganze läuft auf einem PC in VMware mit Windows 10 und 6GB Ram.
Wobei ich meine, dass mein Skript im Vergleich zu normalen Haus-Automatisierungen umfangreich und aufwändig ist.Für mich stellt sich deswegen nicht die Frage, ob das Skript zyklisch oder ereignisgesteuert aufgebaut sein soll, sondern wie im Eingangspost geschrieben, nur ob das Lesen der Datenpunkte besser ereignisgesteuert erfolgen sollte.
-
@amg_666 sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
@hub01 sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Die Datenpunkte ändern sich unterschiedlich, von oft (sekündlich) bis selten (monatlich).
Wenn die DP sich sekündlich ändern, dann reicht es imho aus dass das Skript einmal pro Sekunde läuft, nicht 2mal.
Ich würde es ereignisgesteuert machen, weil das Skript dann nur läuft wenn es laufen muss, sprich wenn sich ein relevanter DP geändert hat.Richtig, würde langen.
Ich habe auch einige Routinen, die z.B. nur alle 10 Sek. durchlaufen werden.Die 500ms verwende ich,
- um Rückmeldungen auf der Visu. zeitnah zu sehen
- um in Trendanzeigen zeitfolgerichtige Kurven zu bekommen
- um Verzögerungszeiten feiner auflösen zu können
-
@asgothian sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
.....
Gerade in diesem Fall ist eine zyklische Abarbeitung eher weniger Sinnvoll.Letztendlich ist eine Aktion (Ändern des Ladevorgangs, Aktualisierung der Darstellung) nur Sinnvoll wenn sich Werte auch geändert haben. Dabei gibt es in dem was ich da sehe keinen Wert der sich nur aus Vorgabewerten und Zeit berechnen lässt.
.....Ich weiß nicht, ob ich dich da richtig verstanden habe, aber hier mal 2 kurze Teilfunktion aus meiner Anwendung:
- wenn genügend Überschuss vorhanden ist, dann erhöhe den Ladestrom alle 15 Sekunden um 1 Ampere
- wenn 1-phasiges Laden aktiv ist und mit 16A geladen wird und 5 Minuten lang genügend Überschuss für die Phasenumschaltung vorhanden ist, dann schalte um
-
@hub01 sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
auf Grund der regen Diskussion habe ich mal die Zeit gemessen, die mein Skript in Anspruch nimmt.
Diese schwankt zwischen 2 und 4 Millisekunden.Mal vorweg - der effektive Lastunterschied in einzelnen Fällen ist auf jeden Fall minimal. Es geht hier eher um den generellen Ansatz. Ich habe mehrfach Systeme gesehen die durch eine grössere Anzahl von Heartbeat getriebenen Einzelfunktionen plötzliche Lastspitzen hatten - immer dann wenn durch den Heartbeat alle Skripte gleichzeitig arbeiten wollten.
@hub01 sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Ich weiß nicht, ob ich dich da richtig verstanden habe, aber hier mal 2 kurze Teilfunktion aus meiner Anwendung:
wenn genügend Überschuss vorhanden ist, dann erhöhe den Ladestrom alle 15 Sekunden um 1 Ampere
Ausgehend davon das sich der "Überschuss" häufiger als alle 15 Sekunden ändert:
- vorheriger wert =< "Genügend Überschuss für +1 A" > "Genügend Überschuss für +1 A" => Timeout setzen, 15 s. Wenn der auslöst, Ladestrom +1A
- aktueller Wert <= "Genügend Überschuss für +1 A" - Timeout löschen.
wenn 1-phasiges Laden aktiv ist und mit 16A geladen wird und 5 Minuten lang genügend Überschuss für die Phasenumschaltung vorhanden ist, dann schalte um
Wenn der Überschuss sich geändert hat nachschauen:
- vorheriger wert =< "Überschussgrenze für Phasenumschaltung" und aktueller Wert > "Überschussgrenze für Phasenumschaltung" => Timeout setzen, 5 min. Wenn der auslöst, Phasenumschaltung
- aktueller Wert <= "Überschussgrenze für Phasenumschaltung" - Timeout löschen.
-
@hub01 said in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Für mich stellt sich deswegen nicht die Frage, ob das Skript zyklisch oder ereignisgesteuert aufgebaut sein soll, sondern wie im Eingangspost geschrieben, nur ob das Lesen der Datenpunkte besser ereignisgesteuert erfolgen sollte.
Was meinst du mit Datenpunkte ereignisgesteuert lesen?
Das Lesen erfolgt doch dann über ein Script? Und dieses Script löst du dann eben mit einem Ereignis aus. -
@blockmove sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
@hub01 said in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Für mich stellt sich deswegen nicht die Frage, ob das Skript zyklisch oder ereignisgesteuert aufgebaut sein soll, sondern wie im Eingangspost geschrieben, nur ob das Lesen der Datenpunkte besser ereignisgesteuert erfolgen sollte.
Was meinst du mit Datenpunkte ereignisgesteuert lesen?
Das Lesen erfolgt doch dann über ein Script? Und dieses Script löst du dann eben mit einem Ereignis aus.Hi,
siehe 1. Beitrag -
Mal vorweg - der effektive Lastunterschied in einzelnen Fällen ist auf jeden Fall minimal. Es geht hier eher um den generellen Ansatz. Ich habe mehrfach Systeme gesehen die durch eine grössere Anzahl von Heartbeat getriebenen Einzelfunktionen plötzliche Lastspitzen hatten - immer dann wenn durch den Heartbeat alle Skripte gleichzeitig arbeiten wollten.
Das ist auf jeden Fall korrekt.
Schwallbildung, egal ob nun durch Heartbeat, abhängige Events oder eben sonstwas, ist nie gut.
Bei "großen" Systemen definiert man eben Ablaufgruppen um sowas zu vermeiden.
Angesichts der Leistungsfähigkeit heutiger Hardware, hatte ich das bei ioBroker noch nie gebraucht.
Da stolpere ich manchmal eher über das Thema synchron / asychron bei Javascript -
@blockmove sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Angesichts der Leistungsfähigkeit heutiger Hardware, hatte ich das bei ioBroker noch nie gebraucht.
Da stolpere ich manchmal eher über das Thema synchron / asychron bei JavascriptSchau mal im Forum wie viele Leute versuchen einen ioBroker auf einem PI3 oder sogar PIZero laufen zu lassen, und denk dann nochmal über das Thema Leistung aktueller Hardware nach
@blockmove sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Was meinst du mit Datenpunkte ereignisgesteuert lesen?
Das Lesen erfolgt doch dann über ein Script? Und dieses Script löst du dann eben mit einem Ereignis aus.Wenn sich in einem Skript mehrere "on ..." Befehle befinden dann wird nur der Code innerhalb des "on..." Ereignisgesteuert ausgeführt - nicht das gesamte Skript.
An dieser Stelle kämpft Deine Vorstellung ggf. wieder mit dem Thema Synchron / Asynchron. Ein Skript welches nur aus
var MyValue = "xy" on ... on ... on ... on ... schedule ...
besteht wird zur Laufzeit erst einmal nur wenig machen. Es stellt den Kontext zur Verfügung in dem die Variable MyValue definiert ist, hat die Trigger über die "on" Befehle mit einem Einsprungpunkt im eigenen Kontext versorgt (dito mit dem Zeitplan durch den "shedule" Befehl). Danach belegt es keine weitere Prozessorzeit, hält aber den Kontext aufrecht.
Wird das Skript beendet wird der Kontext gelöscht und die Einträge in den Schedule dispatcher und an den Triggerdatenpunkten entfernt.
Ansonsten wird immer nur der Teil des Skriptes aktiv ausgeführt der hinter dem Einsprungpunkt liegt, und das auch nur wenn seine Bedingung erfüllt ist (Trigger oder Zeitplan)
A.
-
@asgothian
Die Arbeitsweise von ioBroker beim Abarbeiten von Scripten ist mir schon klar.
Das zu Grunde liegende Konzept ist richtig gut umgesetzt.
Die Stabilität und Robustheit von ioBroker ist hervorragend.Ich bin nur nicht der größte Fan von Javascript / node.js.
Aber so hat halt jeder seine persönliche Vorlieben. -
@asgothian
Oder um es auf ein - dem Einen oder Anderen eher geläufiges - Windows zu münzen:
Man stelle sich eine Windows-Application mit 3 Button vor.
Hinter jedem der Buttons steht die Ereignisbehandlung für den Klick.procedure TForm3.Button1Click(Sender: TObject); begin // mach was end; procedure TForm3.Button2Click(Sender: TObject); begin // mach was anderes end; procedure TForm3.Button3Click(Sender: TObject); begin // mach was völlig anderes end;
Beim Start der Applikation (im ioB: Script) wird lediglich die entsprechende Ereignisbehandlung an den Button gebunden.
Solange keiner klickt, passiert auch nix und es wird auch keine Rechenzeit verbraten.
Erst wenn der Button angeklickt wird, wird dessen Ereignisbehandlung aufgerufen.
Und zwar genau dann, wenn geklickt wird. Da läuft kein "Scheduler", der alle x Millisekunden prüft ob ein Button geklickt wurde oder etwas in der Art. Sowas wäre reine Ressourcenverschwendung.Ersetzt man jetzt "ButtonClick" durch "DatenpunktÄnderung" hat man prizipiell das Verhalten im ioBroker.
Wohlgemerkt "prinzipiell", denn die Asynchronität macht einige Dinge ggf. etwas komplizierter.
-
@asgothian sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Mal vorweg - der effektive Lastunterschied in einzelnen Fällen ist auf jeden Fall minimal. Es geht hier eher um den generellen Ansatz. Ich habe mehrfach Systeme gesehen die durch eine grössere Anzahl von Heartbeat getriebenen Einzelfunktionen plötzliche Lastspitzen hatten - immer dann wenn durch den Heartbeat alle Skripte gleichzeitig arbeiten wollten.
das mit den Heartbeat habe ich nicht verstanden. Ist das nicht ein Problem der Adapter?
Oder könnte z.B. ein hängender Adapter mein Skript blockieren?Ausgehend davon das sich der "Überschuss" häufiger als alle 15 Sekunden ändert:
- vorheriger wert =< "Genügend Überschuss für +1 A" > "Genügend Überschuss für +1 A" => Timeout setzen, 15 s. Wenn der auslöst, Ladestrom +1A
- aktueller Wert <= "Genügend Überschuss für +1 A" - Timeout löschen.
Wenn der Überschuss sich geändert hat nachschauen:
- vorheriger wert =< "Überschussgrenze für Phasenumschaltung" und aktueller Wert > "Überschussgrenze für Phasenumschaltung" => Timeout setzen, 5 min. Wenn der auslöst, Phasenumschaltung
- aktueller Wert <= "Überschussgrenze für Phasenumschaltung" - Timeout löschen.
Deine vorgeschlagenen Lösungen habe ich soweit verstanden, aber Timeouts waren das erste, was ich aus meinen Skripten verbannt habe.
Für mich völlig unverständlich, wie ein hochmodernes System soweit danebenliegen/abweichen kann.
Auf der anderen Seite will ich bei Zeitverzögerungen diese auch als Fortschrittsbalken auf der Visu. sehen. (in meiner Hardcopy der Teil links oben / Schaltfreigaben)Beim Rest ist es oft schwierig, wenn man nicht das ganze Skript kennt.
Deswegen eine kurze Erklärung, warum ich zyklisch programmiere, unabhängig davon, dass ich es leichter verstehe.Fast alle Funktionen sind vom Überschuss abhängig. Der Überschuss wird aus den 3 Energiewerten vom Energiemeter gebildet. Diese ändern sich zw. 2 und bis zu 8 Sekunden. Die 2 Sekunden sind vermutlich die Pollzeit vom Adapter oder vom Energiemeter. Ereignisgesteuert würden meine Routinen somit im 2/3 bis 8/3 Sekundentakt laufen.
Meine zyklisches Programm teilt sich auf in:
- alle 0,5 Sekunden: Ein-/Ausschalten, Steuersignale und Zeitsignale bilden
- alle 2 Sekunden: Überschuss ermitteln
- alle 15 Sekunden: Routine für (langsames) Hochschalten
- alle 5 Sekunden: Routine für (schnelles) Runterschalten
Das Ein-/Ausschalten werde ich noch überdenken.
Beim Rest denke ich, dass ich langsamer und ressourcenschonender bin.