NEWS
[gelöst] Datenpunkte zyklisch oder ereignisgesteuert lesen
-
Ich habe ein Skript, dass alle 500ms abgearbeitet wird.
In diesem Skript werden mehrere Datenpunkte an mehreren Stellen, teilweise auch mehrmals benötigt.
Dazu kopiere ich die Datenpunktwerte in interne Variablen.
Die Datenpunkte ändern sich unterschiedlich, von oft (sekündlich) bis selten (monatlich).Das Lesen der Datenpunkte kann ich zyklisch mit getState() oder ereignisgesteuert mit on() ausführen.
Welche Variante wäre zu bevorzugen?
Wo liegen die Vor- und Nachteile? -
Ich kann mir keine Situation vorstellen, dass man Scripte 2 x pro Sekunde laufen lässt.
Vielleicht mal drüber nachdenken ob dies notwendig ist.Ansonsten würde ich on bevozugen. Denn dies reagiert ja nur auf Veränderungen.
-
@hub01 sagte: Skript, dass alle 500ms abgearbeitet wird.
Bei einem Skript kein Problem. Viele solcher Skripte treiben die Auslastung hoch und kurze Tastenbetätigungen / Impulse werden trotzdem nicht sicher erkannt.
-
@bahnuhr sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Ich kann mir keine Situation vorstellen, dass man Scripte 2 x pro Sekunde laufen lässt.
Vielleicht mal drüber nachdenken ob dies notwendig ist.Ansonsten würde ich on bevozugen. Denn dies reagiert ja nur auf Veränderungen.
Ich könnte sicherlich auch langsamer arbeiten.
Da es bei mir nur dieses eine Skript ist, habe ich da kein Problem gesehen.on():
Mein Gedanke war, auch die on()-Funktion muss die Änderung ja irgendwie erkennen und somit auch zyklisch nachschauen, ob sich was geändert hat.
Vermutlich auch wesentlich schneller, als ich es momentan mit getState mache.@paul53 sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
@hub01 sagte: Skript, dass alle 500ms abgearbeitet wird.
Bei einem Skript kein Problem. Viele solcher Skripte treiben die Auslastung hoch und kurze Tastenbetätigungen / Impulse werden trotzdem nicht sicher erkannt.
Ein Skript langsamer machen, damit man kurze Bedienungen/Impulse mitbekommt, ist für mich keine Lösung.
Gerade auf PC-basierten Systemen kann immer mal ein Dienst oder irgendwas länger dauern.
Dann wird das Signal trotz langsamen Skript wieder verschluckt.Dies löse ich momentan so:
Bei Tastenbedienungen wird ein Datenpunkt gesetzt, das Skript liest den Datenpunkt und löscht danach den Datenpunkt.
So habe ich bisher immer jede Bedienung mitbekommen.Aber unabhängig von der Skript-Geschwindigkeit, welche Vor- bzw. Nachteile gibt es sonst noch?
-
@paul53 sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
@hub01 sagte: Skript, dass alle 500ms abgearbeitet wird.
Bei einem Skript kein Problem. Viele solcher Skripte treiben die Auslastung hoch und kurze Tastenbetätigungen / Impulse werden trotzdem nicht sicher erkannt.
heißt das, mit der on()-Funktion würde dieses Problem nicht bestehen?
-
@hub01 mit den Systemtriggern fährst du immer besser, da diese darauf optimiert sind. Insofern ist ein zyklisches Abfragen für mich nicht nur r edundant, sondern reiner Blödsinn. Es langt schon wenn manche Adapter pollen müssen, da die Hardware eigene Firmware nichts aktiv reportet.
Sprich das System trackt automatisch, wer an welchen Datenpunkten interessiert ist und informiert diese Interessenten über jede Aktualisierung, was jede eigene Abfrage überflüssig macht. Das getState nutzt man nur wenn man einen Status eines Datenpunktes unabhängig von seiner Aktualisierung braucht. Aber eine zyklische Abfrage belastet das System nicht nur unnötig sondern ist total überflüssig.
-
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.
Das Einlesen der Datenpunkte in interne Variablen mache ich auch. Das Prinzip gibt es in den SPS-Steuerung auch. Dort nennt man es Prozessabbild. Der Vorteil ist, dass man während der Script-Abarbeitung konsistente Daten hat.Eine weitere Anwendung für zyklische Bearbeitung sind Regler. Ein PI- oder PID-Regler lässt sich mit einem festen Aufrufintervall viel einfacher programmieren als mit einem Trigger auf Ist- / Sollwertänderung. Beim festen Intervall brauche ich für den I- und D-Anteil mich nicht noch mit den Zeiten rumplagen.
Fazit:
Ich finde zyklische Bearbeitung klasse, aber jeder darf so programmieren, wie er mag. -
@blockmove nur fragt der iobroker sicher intern bereits zyklisch die states ab, deswegen kann man das meines Erachtens nicht vergleichen. Es ist einfach nur redundant und unnötig. Bei einem SPS System ist das was wahrscheinlich ganz andres - da kann es ja sein, dass es für die Statusabfrage gar kein System gibt, aber da kennst du dich sicher besser aus, deswegen halte ich mich da zurück- denn SPS kenne ich nur vom Namen zur Industriemaschinensteuerung, hab damit aber nie was gemacht.
Auch wenn man einen Adapter baut macht das Sinn, aber sicher nicht bei iobroker Datenpunkten. Ich behauptete sogar, hängt natürlich von der Hardware ab, dass alles was unter 100ms abläuft bekommst im iobroker eh nur unzuverlässig mit. Auch meine Tasmota geflanschten Steckdosen bringe ich schnell zum Absturz, wenn ich da Befehle mehrfach unter 100ms sende. Die ganze Hardware spielt doch bei diesen #überlegungen eine wesentliche Rolle.
-
@hub01 sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
Das Lesen der Datenpunkte kann ich zyklisch mit getState() oder ereignisgesteuert mit on() ausführen.
Welche Variante wäre zu bevorzugen?
Wo liegen die Vor- und Nachteile?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.
Ob du dann deine Aktion alle 500 ms ausführen musst oder nicht wäre noch zu bewerten. Ich würde auch diese auf den Prüfstand stellen. Ist es eine Aufgabe bei der eigentlich nur eine Aktion notwendig ist wenn sich mindestens einer der Werte geändert hat dann würde ich die ganze Bearbeitung mit an den Trigger hängen und die Zeit-Funktion über die Änderungshistorie verwalten.
Zu den Vor- und Nachteilen :
- eine Zyklische Abarbeitung erzeugt eine gewisse (statische) Grundlast.
- das Zyklische Abfragen der Werte direkt aus dem Objektbaum erhöht diese Last, dieser steigt mit grösser werdendem Objektbaum. (Auch statische Last)
- Je nach Einstellung des Adapters kostet das Abfragen der Werte auch dynamisch Zeit. Mehr dazu weiter unten. Je nach Anzahl der abzufragenden Werte und Frequenz der Abarbeitung kann es passieren das das gleiche Skript mehrfach parallel läuft !!!
- Arbeiten mit on{} erzeugt eine dynamische Last - immer nur wenn werte Geändert werden.
- Auch beim Arbeiten mit on{} kann es passieren das das gleiche Skript parallel mehrfach läuft, insbesondere wenn die Abarbeitung des Skriptes länger dauert als das Intervall zwischen 2 Triggern.
Noch 2 Punkte zum Thema Ressourcen:
Man kann am JS Adapter einstellen ob alle States zu Adapterstart abonniert werden sollen. Wird das gemacht, dann trägt sich der JS Adapter für jeden State als Empfänger der Änderung ein und speichert für jeden State die entsprechenden Änderungen intern. Dieses belegt signifikant Speicher, insbesondere bei grossen Objektbäumen, erlaubt es aber das "getState" synchron mit minimalem Zeitaufwand ausführen zu können. In dem Moment wo das nicht gesetzt ist müssen die States asynchron abgefragt werden, was mehr Zeit bei der Skriptausführung benötigt, dafür aber weniger Speicherbedarf für den JS Adapter.Zu dieser Aussage:
@mickym sagte in Datenpunkte zyklisch oder ereignisgesteuert lesen:
@blockmove nur fragt der iobroker sicher intern bereits zyklisch die states ab, deswegen kann man das meines Erachtens nicht vergleichen.
Bei der Abarbeitung der Trigger ist zu bedenken das der JS Controller (meines Wissens) nicht zeitgesteuert alle Werte auf Änderung / Aktualisierung überprüft. Statt dessen kann an jedem State ein Skript eingetragen werden welches über die Änderung/Aktualisierung aufgerufen wird. Die Aktualisierung eines Wertes wird ja schon durch einen Event ausgelöst - der JS Controller leitet diesen Event nur an die Skripte weiter.
Aus diesem Grund ist ein Arbeiten mit On{} prinzipiell günstiger als ein arbeiten mit regelmässiger Abarbeitung.A.
-
@mickym
Es geht hier primär um den Script-Aufruf.
Und hier kann man eben unterscheiden zwischen zyklischen Aufruf und ereignisgesteuerten Aufruf. Das hat erstmal nichts mit der internen Verarbeitung von Datenpunkten im ioBroker zu tun. Natürlich gibt es jede Menge Adapter, die einfach in einem festen Zeitraster Daten von Geräten lesen oder Daten schreiben.
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.
Unabhängig davon muss ich auch nicht im jedem Aufruf eines Scripts einen Datenpunkt beschreiben. ioBroker liefert ja den Timestamp eines Datenpunktes und so kann ich auch beim zyklischen einen Mindestzeitabstand einhalten.Ich will eigentlich nur darauf hinweisen, dass sowohl Ereignissteuerung als auch der zyklische Aufrufe ihre Daseinsberechtigung und ihre Vor- und Nachteile haben.
Als Programmierer sollte man einfach beides kennen und je nach Anforderung einsetzen.
Es gilt die uralte Regel: Für jede Arbeit das richtige Werkzeug zu nehmen.
War schon in der Steinzeit so und ist heute nicht anders -
@asgothian Bei der Abarbeitung der Trigger ist zu bedenken das der JS Controller (meines Wissens) nicht zeitgesteuert alle Werte auf Änderung / Aktualisierung überprüft.
Na falls ich das behauptet habe, dann war das natürlich falsch. Ich dachte ich hätte irgendwo geschrieben dass nur die Datenpunkte überwacht werden, die subscribed wurden und der JS Adapter sich wie ein MQTT Broker verhält und deshalb effizient in Zyklen Datenpunkte auf Aktualisierung oder Änderungen überprüft.
-
@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.
-
@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.