Geht diese rule so?
-
- Beiträge: 55
- Registriert: 18. Sep 2018 17:43
Geht diese rule so?
Hallo Zusammen, ich möchte mit dieser Rolle einfach das Flurlicht nach zwei Minuten ausschalten!
wie kann ich sagen das er das nur in der Zeit von Morgens 8 Uhr bis 16:30 Uhr durchgeführt werden soll und in der Zeit ab 16:30 Uhr bis 23:00 Uhr soll der Timer dann 10 Minuten laufen!
Danke für die Mühe! vG. Isostar
rule "Flurunten wird nach 2 Minuten ausgeschaltet"
when
Item GF_Flur_Licht received command ON
then
{
createTimer(now.plusSeconds(120)) [
sendCommand(GF_Flur_Licht, OFF)
]
}
end
wie kann ich sagen das er das nur in der Zeit von Morgens 8 Uhr bis 16:30 Uhr durchgeführt werden soll und in der Zeit ab 16:30 Uhr bis 23:00 Uhr soll der Timer dann 10 Minuten laufen!
Danke für die Mühe! vG. Isostar
rule "Flurunten wird nach 2 Minuten ausgeschaltet"
when
Item GF_Flur_Licht received command ON
then
{
createTimer(now.plusSeconds(120)) [
sendCommand(GF_Flur_Licht, OFF)
]
}
end
- udo1toni
- Beiträge: 15243
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Geht diese rule so?
Ja, die Rule wird so funktionieren. Allerdings gibt es da noch ein paar Dinge zu beachten. openHAB arbeitet komplett asynchron, das bedeutet auf Rules bezogen, die Rule kann beliebig oft hintereinander aufgerufen werden. Wenn Du nun spaßeshalber das Licht alle 10 Sekunden einschaltest (z.B. kommt der Einschaltimpuls von einem Bewegungsmelder), wird das Licht nach zwei Minuten ausgeschaltet, wenn Du es dann aber direkt wieder einschaltest, wird es spätestens zehn Sekunden später wieder ausgeschaltet, weil für jeden Einschaltimpuls ein unabhängiger Timer angelegt wurde.
Richtig geht es so:
Es gibt jetzt eine globale Variable, über die man Kontrolle über den Timer hat. Die Rule prüft, ob ein Timer aktiv ist (Variable ist nicht null), falls das der Fall ist, wird der Timer abgebrochen. Anschließend wird ein neuer Timer angelegt und der Variablen zugewiesen.
Deine Schreibweise für createTimer() (mit den eckigen Klammern nach dem createTimer() ) ist zwar korrekt, ich habe trotzdem eine andere Schreibweise gewählt (eckige Klammern innerhalb der Klammern als zweiter Parameter), weil dadurch klar ist, dass das Lambda (der Inhalt der eckigen Klammern) zu der Funktion gehört und nicht unabhängig davon ist.
Weiterhin habe ich die Methode GF_Flur_Licht.sendCommand(OFF) verwendet, anstatt der Action sendCommand(GF_Flur_Licht, OFF). Die Methode ist grundsätzlich die bessere Wahl, die Action erwartet als Argumente immer zwei Strings, während die Methode alles annehmen sollte, was an Typen sinnvoll ist. die Action macht also aus dem übergebenen Item einen String, der den Namen des Items enthält und aus dem übergebenen Status einen String, der den Status als Text enthält. Oft funktioniert das, unter bestimmten Umständen klappt diese Typwandlung aber nicht wie vorgesehen.
Wenn der Timer abläuft (also der Code im Lambda ausgeführt wird) wird zum Schluss die Variable reinitialisiert, so dass die Prüfung auf einen aktiven Timer wieder funktioniert.
Du möchtest das Ganze erweitert haben, so dass uhrzeitabhängig verschiedene Laufzeiten für den Timer verwendet werden, das ist einfach realisierbar. Allerdings hast Du nicht geschrieben, was von 23 Uhr bis 8 Uhr passieren soll. Ich setze da jetzt einfach mal eine dritte Schaltlänge ein:
Ich habe also lediglich eine weitere Variable definiert, diesmal innerhalb der Rule. Beim Initialisieren bekommt sie einen Default von 300 zugewiesen.
Sollte die aktuelle Zeit zwischen 8:00 Uhr und 16:29:59.999 Uhr liegen, bekommt sie den Wert 120 zugewiesen. Sollte die aktuelle Zeit zwischen 16:30 Uhr und 22:59:59.999 Uhr liegen, bekommt sie den Wert 600 zugewiesen.
Anschließend verwende ich die Variable anstatt eines fixen Wertes.
Es gibt übrigens auch die Eigenschaften .getHourOfDay und .getMinuteOfHour, aber im Allgemeinen ist bei minutengenauen Angaben das .getMinuteOfDay bequemer. Man kann natürlich auch direkt 990 statt 16*60 +30 schreiben, so wird aber sofort klar, was die Zahl bedeutet.
Richtig geht es so:
Code: Alles auswählen
var Timer tLichtFlurGF = null // globale Variable für den Timer
rule "Flur unten wird nach 2 Minuten ausgeschaltet"
when
Item GF_Flur_Licht received command ON
then
if(tLichtFlurGF !== null) tLichtFlurGF.cancel
tLichtFlurGF = createTimer(now.plusSeconds(120), [
GF_Flur_Licht.sendCommand(OFF)
tLichtFlurGF = null
])
end
Deine Schreibweise für createTimer() (mit den eckigen Klammern nach dem createTimer() ) ist zwar korrekt, ich habe trotzdem eine andere Schreibweise gewählt (eckige Klammern innerhalb der Klammern als zweiter Parameter), weil dadurch klar ist, dass das Lambda (der Inhalt der eckigen Klammern) zu der Funktion gehört und nicht unabhängig davon ist.
Weiterhin habe ich die Methode GF_Flur_Licht.sendCommand(OFF) verwendet, anstatt der Action sendCommand(GF_Flur_Licht, OFF). Die Methode ist grundsätzlich die bessere Wahl, die Action erwartet als Argumente immer zwei Strings, während die Methode alles annehmen sollte, was an Typen sinnvoll ist. die Action macht also aus dem übergebenen Item einen String, der den Namen des Items enthält und aus dem übergebenen Status einen String, der den Status als Text enthält. Oft funktioniert das, unter bestimmten Umständen klappt diese Typwandlung aber nicht wie vorgesehen.
Wenn der Timer abläuft (also der Code im Lambda ausgeführt wird) wird zum Schluss die Variable reinitialisiert, so dass die Prüfung auf einen aktiven Timer wieder funktioniert.
Du möchtest das Ganze erweitert haben, so dass uhrzeitabhängig verschiedene Laufzeiten für den Timer verwendet werden, das ist einfach realisierbar. Allerdings hast Du nicht geschrieben, was von 23 Uhr bis 8 Uhr passieren soll. Ich setze da jetzt einfach mal eine dritte Schaltlänge ein:
Code: Alles auswählen
var Timer tLichtFlurGF = null // globale Variable für den Timer
rule "Flur unten wird nach x Minuten ausgeschaltet"
when
Item GF_Flur_Licht received command ON
then
if(tLichtFlurGF !== null) tLichtFlurGF.cancel // falls ein Timer läuft, abbrechen
var Integer iSekunden = 300 // default Länge des Timers
if(now.getMinuteOfDay >= 8 * 60 && now.getMinuteOfDay < 16 * 60 +30 ) iSekunden = 120 // zwischen 8 und 16:30
if(now.getMinuteOfDay >= 16 * 60+30 && now.getMinuteOfDay < 23 * 60 ) iSekunden = 600 // zwischen 16:30 und 23
tLichtFlurGF = createTimer(now.plusSeconds(iSekunden), [
GF_Flur_Licht.sendCommand(OFF) // Licht aus!
tLichtFlurGF = null // Timer reinitialisieren
])
end
Sollte die aktuelle Zeit zwischen 8:00 Uhr und 16:29:59.999 Uhr liegen, bekommt sie den Wert 120 zugewiesen. Sollte die aktuelle Zeit zwischen 16:30 Uhr und 22:59:59.999 Uhr liegen, bekommt sie den Wert 600 zugewiesen.
Anschließend verwende ich die Variable anstatt eines fixen Wertes.
Es gibt übrigens auch die Eigenschaften .getHourOfDay und .getMinuteOfHour, aber im Allgemeinen ist bei minutengenauen Angaben das .getMinuteOfDay bequemer. Man kann natürlich auch direkt 990 statt 16*60 +30 schreiben, so wird aber sofort klar, was die Zahl bedeutet.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet
-
- Beiträge: 55
- Registriert: 18. Sep 2018 17:43
Re: Geht diese rule so?
Super und vielen Dank udo1toni für diese tolle Antwort funktioniert!
ich habe noch eine Frage zum Astrobinding, ist es richtig, dass sich wenn ich es wie unten mache, wir uns in der Dämmerung befinden und wie könnte ich diese Regel vereinfachen? Sorry fange gerade erst an! Lieben Dank!
rule "Bewegungsmelder Flur hat Bewegung erkannt und es ist Dunkel"
when
Item FF_Flur_Bewegungsmelder received update
then
if(astro_sun_home_civilDusk_start)
if(FF_Flur_Bewegungsmelder.state == ON && FF_Flur_Steckdoseoben.state == OFF){
sendCommand(FF_Flur_Steckdoseoben, ON)
}
end
rule "Bewegungsmelder Flur wird nach 2 Minuten ausgeschaltet"
when
Item FF_Flur_Steckdoseoben received command ON
then
if(FF_Flur_Bewegungsmelder.state == ON){
createTimer(now.plusSeconds(120)) [
sendCommand(FF_Flur_Steckdoseoben, OFF)
]
}
end
ich habe noch eine Frage zum Astrobinding, ist es richtig, dass sich wenn ich es wie unten mache, wir uns in der Dämmerung befinden und wie könnte ich diese Regel vereinfachen? Sorry fange gerade erst an! Lieben Dank!
rule "Bewegungsmelder Flur hat Bewegung erkannt und es ist Dunkel"
when
Item FF_Flur_Bewegungsmelder received update
then
if(astro_sun_home_civilDusk_start)
if(FF_Flur_Bewegungsmelder.state == ON && FF_Flur_Steckdoseoben.state == OFF){
sendCommand(FF_Flur_Steckdoseoben, ON)
}
end
rule "Bewegungsmelder Flur wird nach 2 Minuten ausgeschaltet"
when
Item FF_Flur_Steckdoseoben received command ON
then
if(FF_Flur_Bewegungsmelder.state == ON){
createTimer(now.plusSeconds(120)) [
sendCommand(FF_Flur_Steckdoseoben, OFF)
]
}
end
- udo1toni
- Beiträge: 15243
- Registriert: 11. Apr 2018 18:05
- Wohnort: Darmstadt
Re: Geht diese rule so?
Es gibt zwei unterschiedliche Funktionen des Astro Bindings.
Zum einen gibt es normale Channel, die z.B. die Uhrzeit enthalten, zu der am aktuellen Tag ein bestimmtes astronomisches Ereignis eintritt. Diese Channel musst Du einem passenden Item zuweisen, dann kannst Du den Status des Items innnerhalb einer Rule abfragen.
Zum anderen gibt es event Channel, die zum Eintreten des Ereignisses einen Trigger senden, mit dem dann eine Rule getriggert werden kann.
Wenn Du einen Blick auf das Astro Thing "sun" wirfst, kannst Du z.B. verschiedenste Sonnen Auf- und Untergänge finden, jeweils mit Start, Ende, Dauer und dem Range Event, welches dann zum Startzeitpunkt mit START triggert, zum Endzeitpunkt mit END.
Start und Ende ergeben sich dadurch, dass das Ereignis als Berührung des Himmelskörpers mit einer gedachten Linie definiert ist. Die Sonne ist aber kein Punkt, sondern ein Kreis (zweidimensional betrachtet), so dass es einen Zeitpunkt gibt, zu dem die Berührung beginnt, und einen Zeitpunkt, zu dem die Berührung endet.
Nehmen wir an, Du möchtest auf CivilDusk triggern, die Sonne sinkt unter -6° Höhe am Horizont. Eine Rule dazu sähe dann so aus:
Die andere Variante ist, ob wir uns zum Zeitpunkt des Triggers innerhalb der Dunkelheit zwischen Abend- und Morgendämmerung befinden.
Dazu brauchen wir zwei Items:
und in der Rule müssen wir uns mit der Umrechnung der Zeiten herumschlagen.
Elegant an diesem Ansatz ist, dass man im Astrobinding auch Offsets für jeden Channel definieren kann, man kann das Ereignis also statisch um eine beliebige Zeit nach vorne oder hinten verschieben, außerdem kann man Ober- und Untergrenze definieren.
Hässlich ist, dass es wirklich keinen Spaß macht, die nötigen Konvertierungen durchzuführen, vor allem, weil an dem Datenmodell in letzter Zeit herumgeschraubt wurde. Ich bin mir nicht mal sicher, ob der oben verwendete Ausdruck nicht schon deprecated ist.
Deshalb ist hier eventuell ein einfacherer Ansatz besser, denn das Astrobinding liefert auch die Position der Sonne in Richtung und Höhenwinkel. Wie oben erwähnt ist die Bürgerliche Dämmerung ab -6°. es reicht jetzt ein Item:
In der Rule wird das jetzt so berücksichtigt:
Alternativ kannst Du auch die Einheit mit in den Vergleich nehmen:
Beides sollte funktionieren, der erste Ansatz ist praktischer, falls man mit dem Zahlenwert noch Berechnungen anstellen will, da ist es oft nur lästig, Einheiten mit rumzuschleppen.
Zum einen gibt es normale Channel, die z.B. die Uhrzeit enthalten, zu der am aktuellen Tag ein bestimmtes astronomisches Ereignis eintritt. Diese Channel musst Du einem passenden Item zuweisen, dann kannst Du den Status des Items innnerhalb einer Rule abfragen.
Zum anderen gibt es event Channel, die zum Eintreten des Ereignisses einen Trigger senden, mit dem dann eine Rule getriggert werden kann.
Wenn Du einen Blick auf das Astro Thing "sun" wirfst, kannst Du z.B. verschiedenste Sonnen Auf- und Untergänge finden, jeweils mit Start, Ende, Dauer und dem Range Event, welches dann zum Startzeitpunkt mit START triggert, zum Endzeitpunkt mit END.
Start und Ende ergeben sich dadurch, dass das Ereignis als Berührung des Himmelskörpers mit einer gedachten Linie definiert ist. Die Sonne ist aber kein Punkt, sondern ein Kreis (zweidimensional betrachtet), so dass es einen Zeitpunkt gibt, zu dem die Berührung beginnt, und einen Zeitpunkt, zu dem die Berührung endet.
Nehmen wir an, Du möchtest auf CivilDusk triggern, die Sonne sinkt unter -6° Höhe am Horizont. Eine Rule dazu sähe dann so aus:
Code: Alles auswählen
rule "civilDusk Trigger"
when
Channel 'astro:sun:home:civilDusk#event' triggered START
then
logInfo("astro","Bürgerliche Abenddämmerung erreicht!")
end
Dazu brauchen wir zwei Items:
Code: Alles auswählen
DateTime CivilDawnStart "Sonnenaufgang Bürgerl." <sunrise> { channel="astro:sun:home:civilDawn#start" }
DateTime CivilDuskStart "Sonnenuntergang bürgerl." <sunset> { channel="astro:sun:home:civilDusk#start" }
Code: Alles auswählen
rule "trigger innerhalb bürgerlicher Dämmerung"
when
Item blah received update
then
val Number cDusk = (CivilDuskStart.state as DateTimeType).calendar.timeInMillis
val Number cDawn = (CivilDawnStart.state as DateTimeType).calendar.timeInMillis
if(now.millis < cDawn || now.millis > cDusk) {
// alternativ kann man auch eine Funktion von now() verwenden
// if(now.isBefore(cDawn) || now.isAfter(cDusk)) {
logInfo("astro","Trigger innerhalb der bürgerlichen Dämmerung!")
}
end
Hässlich ist, dass es wirklich keinen Spaß macht, die nötigen Konvertierungen durchzuführen, vor allem, weil an dem Datenmodell in letzter Zeit herumgeschraubt wurde. Ich bin mir nicht mal sicher, ob der oben verwendete Ausdruck nicht schon deprecated ist.
Deshalb ist hier eventuell ein einfacherer Ansatz besser, denn das Astrobinding liefert auch die Position der Sonne in Richtung und Höhenwinkel. Wie oben erwähnt ist die Bürgerliche Dämmerung ab -6°. es reicht jetzt ein Item:
Code: Alles auswählen
Number:Angle Elevation "Sonnenhöhe [%.1f°]" <sun>{ channel="astro:sun:home:position#elevation" }
Code: Alles auswählen
rule "trigger innerhalb bürgerlicher Dämmerung"
when
Item blah received update
then
if((Elevation.state as as QuantityType<Number>) <-6) {
logInfo("astro","Trigger innerhalb der bürgerlichen Dämmerung!")
}
end
Code: Alles auswählen
rule "trigger innerhalb bürgerlicher Dämmerung"
when
Item blah received update
then
if(Elevation.state <-6|°) {
logInfo("astro","Trigger innerhalb der bürgerlichen Dämmerung!")
}
end
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet
-
- Beiträge: 55
- Registriert: 18. Sep 2018 17:43
Re: Geht diese rule so?
Super Danke für die ausführliche Erklärung! vG. Isostar
-
- Beiträge: 197
- Registriert: 23. Sep 2018 19:43
Re: Geht diese rule so?
Ich habe es noch ein klein wenig anders gelöst.
Ein Item definiert:
Und dann zwei Regeln:
Ich kann in anderen Regeln dann einfach auf "EventDaylight.state == ON" oder "EventDaylight.state == OFF"' abfragen.
Ein Item definiert:
Code: Alles auswählen
Switch EventDaylight
Code: Alles auswählen
rule "Tageslicht endet"
when
Channel "astro:sun:home:daylight#event" triggered END
then
logInfo("Tageslicht-Rule","Tageslicht endet")
EventDaylight.sendCommand(OFF)
end
rule "Tageslicht beginnt"
when
Channel "astro:sun:home:daylight#event" triggered START
then
logInfo("Tageslicht-Rule","Tageslicht startet")
EventDaylight.sendCommand(ON)
end