openems
openems copied to clipboard
Add Timers: by Counting, by Cycles, by Time
Hallo Stefan, Hallo Community,
Dies ist eine der BaseComponents die unsere weiteren Wärmesektor Komponenten benötigen. Sie ermöglichen es ein einfaches Zeithandling zu erlauben zwischen Zyklen/Zeit/counting Da wir bspw auch Remote Kommunikation zwischen mehreren OpenEMS Edge zulassen und damit dezentralisiert steuern, brauchten wir u.a. eine Klasse die das Zeithandling für uns übernimmt und unseren Bedürfnissen gerecht wird.
Bei weiteren Fragen stehe ich zur Verfügung
LG
Hallo @DerStoecki,
vielen Dank schon mal für den ausgezeichneten, ausführlich dokumentierten Pull-Request. Ich verlinke an der Stelle auch gleich noch den sehr guten Erklärungsthread im Community Forum: https://community.openems.io/t/consolinnos-warmesektor-und-spater-emob-kommt-zu-openems-step-by-step/813?u=stefan.feilmeier
Die Funktion des Timers ist soweit klar und sinnvolll und können wir denke ich relativ schnell mergen. Deshalb würde ich gerne mit diesem Pull-Request anfangen.
Allerdings stellt sich mir noch die Frage, ob wir nicht auf joda-time verzichten können. Die Bibliothek sollte spätestens ab Java Version 11 nicht mehr notwendig sein - siehe z. B. https://www.baeldung.com/joda-time: "After the release of Java 8, authors consider the project to be mostly finished and advise to use the Java 8 API if possible." Wir nutzen sonst überall ZonedDateTime, LocalDateTime oder Instant; das wäre m.E. sinnvoll, wenn wir das vereinheitlichen.
Gruß, Stefan
Hallo @sfeilmeier,
Vielen Dank für deine Antwort. Das denke ich können wir sehr gerne tun und auf joda verzichten. Ich schau, dass ich das diese Woche noch erledigt bekomme. LG
Noch ein Punkt: den Namespace io.openems.*.api verwenden wir eigentlich für OpenEMS Natures, also Meter, ESS, etc. Den Timer könnten wir als Kern-Funktion von OpenEMS Edge auch in io.openems.edge.common verschieben. Gib Bescheid, wenn ich unterstützen kann/soll.
Ahh ich verstehe, ok dann bind ich das in die edge.common mit ein perfekt :)
Dankeschön
Ok, das mit io.openems.edge.common war leider nur die halbe Wahrheit. Services dürfen nicht im commons liegen, weil der geteilte Classpath hier zu Problemen führen würde. Die Implementierungen habe ich deshalb nach io.openems.edge.core verschoben.
In den Kommentaren habe ich gelesen, dass jeweils nur eine Instanz eines Timers aktiv sein muss. In diesem Fall solltest du die Komponente im @Designate direkt als factory = false deklarieren, dann bleibt es garantiert ein Singleton.
Edit: ich weiß jetzt nicht genau, wie die Timer dann in echten Komponenten verwendet werden. Falls es je Timer ein Singleton geben kann, wäre es evtl. sinnvoll nicht nur ein Timer-Interface zu haben, sondern jeweils eines. Darauf könnte man dann direkte @References verlinken. Wenn es so funktioniert, wie ich mir vorstelle, dann müssten die Timer nicht mal OpenemsComponents sein, man könnte die Configs weglassen und immediate auf false setzen. Dann werden die Timer-Komponenten vom OSGi-Framework nur nach Bedarf erstellt, falls sie von einer anderen Komponente benötigt werden - ganz ohne explizite Konfiguration.
Erstmal vielen Dank für deinen Kommentar und dein approve. Ich möchte kurz auf deinen letzten Kommentar eingehen
"Ok, das mit io.openems.edge.common war leider nur die halbe Wahrheit. Services dürfen nicht im commons liegen, weil der geteilte Classpath hier zu Problemen führen würde. Die Implementierungen habe ich deshalb nach io.openems.edge.core verschoben."
Das ist sehr gut zu wissen, danke!
"n den Kommentaren habe ich gelesen, dass jeweils nur eine Instanz eines Timers aktiv sein muss. In diesem Fall solltest du die Komponente im @Designate direkt als factory = false deklarieren, dann bleibt es garantiert ein Singleton."
Stimmt daran hätte ich denken können, jeder dieser "Timer" sollte nur 1x zur Laufzeit vorhanden sein...dan hätte ich factory false machen können. Kann ich dann trotzdem eigentlich die "id" mit angeben?
"ich weiß jetzt nicht genau, wie die Timer dann in echten Komponenten verwendet werden. Falls es je Timer ein Singleton geben kann, wäre es evtl. sinnvoll nicht nur ein Timer-Interface zu haben, sondern jeweils eines."
Jede konkrete Implementierung eines Timers sollte 1x vorhanden sein. Konfigurierbare Komponenten können Timer verschiedener Implementierung nutzen (konfig abhängig) Komponenten erstellen sich einen Timerhandler und sagen diesem, welchen Timer sie nutzen wollen für einen bestimmten usecase und wie lange die "maxWaitTime" ist
Beispielsweise haben wir einen Wärmeerzeuger der aktiviert werden soll. Dieser Wärmeerzeuger braucht ein "EnableSignal" was ihm sagt, dass dieser angehen soll. Soltle der Erzeuger an gewesen sein, und danach das EnableSignal "fehlen" soll er bspw 30 sekunden warten bis er tatsächlich auf aus geht.
Das heißt also er sagt dem TimerHandler -> TimerByTime, 30 sekunden und einen "Identifier" dass "jeder weiß" welche Zeit abgefragt werden muss...in diesem Beispiel also "EnableSignalTime".
An anderer Stelle erwartet der Erzeuger etwas anderes nach spätestens 20 zyklen, also nimmt er den "TimerByCycles" her, überreicht dem TimerHandler 20 zyklen und einen Identifier "etwas anderes"
Der Wärmeerzeuger kann wann immer er es braucht, seinen Timerhandler abfragen (der die timer abfragt) ist meine Zeit bei Identifier (EnableSignalTime oder "etwas anderes") abgelaufen? wenn ja -> mach ich etwas.
Eventuell wird das beispiel klarer, wenn ich eine PR starte, die tatsächlich den TimerHandler / die Timer nutzt.
"Darauf könnte man dann direkte @references verlinken. Wenn es so funktioniert, wie ich mir vorstelle, dann müssten die Timer nicht mal OpenemsComponents sein, man könnte die Configs weglassen und immediate auf false setzen. Dann werden die Timer-Komponenten vom OSGi-Framework nur nach Bedarf erstellt, falls sie von einer anderen Komponente benötigt werden - ganz ohne explizite Konfiguration."
Also das würde natürlich auch gehen. Denke ich... also ein "Timer" interface und extendend "TimerByTime" "TimerByCycles" "TimerByCounting"
Der TimerHandler würde dann die @Reference bekommen...für jeden timer...und wenn eine Komponente dann den TimerType angibt und nicht mehr ne id...könnte der TimerHandler entscheiden....
Kann ich gerne wenn du möchtest testen.
Hallo Stefan, Entschuldige bitte, ich konnte mich leider erst später als gedacht mit der Thematik auseinandersetzen. Ich habe die Änderungen die du vorgeschlagen hast einmal umgesetzt und hoffe ich hab dich da richtig verstanden und das war so richtig :D
Hi @sfeilmeier kurze Frage da die Timer bei den utility Klassen gebraucht werden... Werden die timer noch gemerged oder sollen wir, weil die PR so alt ist nochmal drüber gucken, ob das noch so passt usw? Danke schon mal!
Hallo zusammen, die Programmierung sieht schon mal wirklich gut aus.
Ich habe jedoch zwei verschiedene Konzepte Counter und Timer erkannt, die nicht getrennt werden.
Ich würde daher die folgende Unterscheidung treffen:
Counter: zählt nach oben oder unten je nach Ereignis.Timer: misst die reale Zeit und sendet die Ereignisse zeitbasiert.
Man sollte auch programmieren können, dass ein Counter durch einen Zeitintervall (Timer) erhöht/erniedrigt wird.
Es wäre auch ein guter Zeitpunkt, um die PR zu erfrischen :D
hey hey,
der Timer wurde stark überarbeitet.
würde bei uns intern das thema mit dem Counter durch zeitintervall erhöhen / erniedrigen ansprechen.
Würde dann die PR hier erstmal schließen @clehne wir könnten ja die neue Implementierung des Timers als PR stellen