Seite 1 von 1

[Rule]Fenster vergessen

Verfasst: 8. Jul 2020 12:39
von JDog1895
Hallo,

nachdem ich nun schon viele Tipps hier über das Forum erhalten habe, bin ich nun an einem Punkt angekommen, wo ich entweder zu doof bin oder aber den Wald vor lauter Bäumen nicht mehr sehe.

Ich bin noch relativ neu bei openHAB und versuche mich nun in der ein oder anderen Regel. Irgendwie fehlt mir die eine Lösung, damit der Knoten platzt und ich weiterkomme.

Ich versuche eine einfache Fenster-Alarm-Regel zu erstellen. Wird morgens (6-10 Uhr) das Fenster geöffnet, dann soll ein Timer für 20 Minuten laufen. Nach Ablauf dieser Zeit soll ein Sound abgespielt werden (dies klappt soweit). Die weitere Überlegung war, ich warne noch einmal nach 5 Minuten, falls das Fenster noch immer geöffnet ist, aber eigentlich muss ich eher prüfen, ob das Fenster geschlossen wurde. Und falls das nicht der Fall sein sollte, wird alle 5 Minuten weiter gewarnt.

Das Fenster ist über die Nacht angekippt. Morgens wird es richtig geöffnet (dabei bekommt der Sensor kurz ein CLOSE).

Letztlich scheue ich mich immer in Foren Fragen zu stellen, aber ich hoffe, mit der Lösung verstehe ich eher, wo mein Fehler liegt und ich kann die Logik bei zukünftigen Regeln verwenden.

Hier nun mein Code:

Code: Alles auswählen

rule "Schlafzimmerfenster Alarm"

when
    Item XiaomiDoorSensorSchlafzimmerIsOpen changed to OPEN
then
        if ((now.getHourOfDay > 6) && (now.getHourOfDay < 10)){
            var Timer Schlafzimmer_timer = null
            Schlafzimmer_timer?.cancel // the ? will skip this line if Schlafzimmer_timer is null
            Thread::sleep(3000)
            logInfo("Schlafzimmer_timer", "Das Schlafzimmerfenster ist " + XiaomiDoorSensorSchlafzimmerIsOpen.state)
        
            Schlafzimmer_timer = createTimer(now.plusMinutes(20), [ |
                                sendCommand(XiaomiMiSmartHomeGatewayVolume, 10)
                                sendCommand(XiaomiMiSmartHomeGatewaySound, 10001)   //10001 ist Fenster zu lange geöffnet.
                                Thread::sleep(1000)
                                logInfo("Schlafzimmer_timer", "Das Schlafzimmerfenster ist zu lange geöffnet!") ])
            
            //var Timer Schlafzimmer_timer2 = null
            //Schlafzimmer_timer2?.cancel
            //Schlafzimmer_timer2 = createTimer(now.plusMinutes(1), [ |
             //   sendCommand(XiaomiMiSmartHomeGatewayVolume, 10)
             //   sendCommand(XiaomiMiSmartHomeGatewaySound, 10002)   //10002 ist Fenster zu lange geöffnet, letztmalige Warnung.
             //  logInfo("Schlafzimmer_timer", "Das Schlafzimmerfenster ist zu lange geöffnet!") ])
 
        }

end
Ich weiß, da fehlt einiges an Code, aber wie gesagt, irgendwie komme ich nicht weiter. Wahrscheinlich muss ich irgendwie mit Flags arbeiten, aber da kam ich auch nicht weiter.

Viele Grüße
Matthias

Re: [Rule]Fenster vergessen

Verfasst: 9. Jul 2020 00:20
von udo1toni
Also, wichtig ist zunächst einmal, zu verstehen, dass Schlafzimmer_timer ein Handle ist, um auf den Timer zugreifen zu können. Da der Timer unabhängig von der Rule läuft, muss der Handle ebenfalls unabhängig von der Rule sein, das heißt, die Definition

Code: Alles auswählen

var Timer Schlafzimmer_timer = null
muss außerhalb der Rule stehen (genauer: sie muss vor der ersten Rule innerhalb der selben Datei wie die Rule stehen)
Zweitens ist die Idee eines Timers, unnötige Sleeps zu verhindern. Mir ist klar, dass es an dieser Stelle eventuell darum geht, dass der Zustand des Items sich nochmals ändert, aber das ist Schmuh ;)
Besser sollte diese Variante funktionieren:

Code: Alles auswählen

// Globale Variablen zu Beginn der Datei definieren!
var Timer Schlafzimmer_timer = null
var Number nCount = 0

rule "Schlafzimmerfenster Alarm"
when
    Item XiaomiDoorSensorSchlafzimmerIsOpen changed
then
    Schlafzimmer_timer?.cancel                               // the ? will skip this line if Schlafzimmer_timer is null
    logInfo("Schlafzimmer_timer", "Das Schlafzimmerfenster ist {}", XiaomiDoorSensorSchlafzimmerIsOpen.state)
    if(XiaomiDoorSensorSchlafzimmerIsOpen.state == OPEN) {
        logInfo("Schlafzimmer_timer", "Starte Timer")
        if(now.getHourOfDay > 6 && now.getHourOfDay < 10) {  // zwischen 7 Uhr und 10 Uhr
            nCount = 0
            Schlafzimmer_timer = createTimer(now.plusMinutes(20), [ |
                nCount = nCount + 1
                logInfo("Schlafzimmer_timer", "Das Schlafzimmerfenster ist zu lange geöffnet! {}.te Meldung.",nCount)
                XiaomiMiSmartHomeGatewayVolume.sendCommand(10)
                if(nCount == 1) 
                    XiaomiMiSmartHomeGatewaySound.sendCommand(10001)             //10001 ist Fenster zu lange geöffnet.
                else
                    XiaomiMiSmartHomeGatewaySound.sendCommand(10002)             //10002 ist Fenster zu lange geöffnet, letztmalige Warnung.
                Schlafzimmer_timer.reschedule(now.plusMinutes(5))
            ])
        }
    } else
        logInfo("Schlafzimmer_timer", "Breche Timer ab.")
end
Es gibt zwei globale Variablen, die erste ist für den Timer, die zweite ist ein Zähler, in dem sich der Timer merkt, wie oft er schon ausgelöst wurde. Das ist hier zur Unterscheidung für den Alarm wichtig (oder vielleicht auch nicht? Egal, nettes Feature...) ;)
Die Rule triggert sowohl bei CLOSED als auch bei OPEN.
Egal, welche Variante es ist, wird ein eventuell laufender Timer abgebrochen (bei OPEN dürfte der Timer gar nicht existieren, aber sicherheitshalber).
Es folgt die Ausgabe des Kontakt-Zustands.
Falls der Zustand OPEN ist, wird auf die Uhrzeit geprüft. Ist diese Bedingung ebenfalls erfüllt, wird der Counter auf 0 gesetzt und der Timer gestartet.
Läuft der Timer ab, so wird der Counter hochgezählt, der Sound ausgegeben, und der Timer neu geplant (fünf Minuten später).
Der Timer wird also immer wieder ausgeführt, bis jemand sich erbarmt und das Fenster schließt (womit der Kontakt auf CLOSED wechselt und der Timer abgebrochen wird).

Re: [Rule]Fenster vergessen

Verfasst: 9. Jul 2020 15:10
von JDog1895
Udo, ich weiß nicht was ich sagen kann. Vielen vielen Dank! Es funktioniert perfekt.

Die Möglichkeiten, die man mit dem Rule-Editor hat, erschließen sich für mich nur sehr langsam. Sehr interessant ist das "reschedule", welches ich bis eben nicht kannte.

Auch haben mir deine Hinweise gerade geholfen, dass eine andere Regel keine Fehler mehr auswirft... mal davon abgesehen davon, dass sie nur halb funktioniert, wie sie soll, aber da bin ich noch dran und versuche den Fehler zu finden.

Jetzt wo ich sehe, wie die Schleife gebaut wurde, sieht es so logisch aus, gerade auch, wie man sie wieder verlässt.

Also noch einmal. Vielen Dank, Udo. Du leistest hier unglaubliche Arbeit mit deinen ausführlichen und informativen Antworten.

Re: [Rule]Fenster vergessen

Verfasst: 9. Jul 2020 17:16
von udo1toni
Freut mich :) Danke für das Kompliment.

Re: [Rule]Fenster vergessen

Verfasst: 9. Jul 2020 23:29
von mokkinger
Hi JDog & Udo,

sehr schöne Anwendung, habs grade auch schnell ausprobiert mit einem Fenster;
und da ich gerade 7 Sensoren im EG an 7 Fenstern verbaut habe, die Frage, wie man das am einfachsten für eine Gruppe Fenster-Sensoren (gSensors) umbauen kann;
when Member of gSensors changed >>> und dann? pro Fenster einen separaten timer aufmachen, mit dem jeweiligen Fenster-Name? kann man das dynamisch lösen, oder lege ich dann oben pro fenster einen separaten Timer handle an, und rufe den in der rule jeweils auf? oder übersehe ich da etwas, und lege besser diese rule jeweils pro fenster separat an?

Danke für gedanken, ob das sinnvoll ist...
Mark

Re: [Rule]Fenster vergessen

Verfasst: 10. Jul 2020 10:51
von udo1toni
Bei sieben Kontakten bietet es sich an, eine HashMap zu verwenden.
Such mal im englischen Forum nach „val HashMap Timer“, da solltest Du fündig werden.
Ein Problem bei der Angelegenheit kann sein, wenn man Klartext Namen für die Meldung haben möchte, aber nur die Itemnamen der Kontakte vorliegen. Entweder, man nutzt dafür eine global definierte Map, um jedem Contact Itemnamen der Gruppe einen String zuzuordnen, den man dann nachschlagen kann, oder man benennt die Items dergestalt, dass man den Namen bequem extrahieren kann, z.B. Contact_Fenster_Wohnzimmer_links, dann kann man Mit Item.name.split(“_“).get(2)+“ “+ Item.name.split(“_“).get(3) den Namen zusammensetzen. Natürlich müssen alle Namen diesem fixen Schema (oder halt einem anderen, welches ähnlich angelegt ist) entsprechen, also im Beispiel muss der 3. und 4. Teil (die Nummerierung ist 0-basiert) den Namen enthalten.

Die größte Herausforderung bei generalisierten Rules ist, die gewünschten Informationen indirekt abzurufen :) aber nach ein paar erfolgreich umgesetzten Rules dieser Art bekommt man Übung.
Der Lohn ist eine Rule für beliebig viele Items. Die Größe der Rules-Dateien macht sich in der Startzeit des Systems bemerkbar, und da kann das bei vielen gleichartigen Rules schon mal ein paar Minuten Unterschied machen.


Gesendet von iPad mit Tapatalk

Re: [Rule]Fenster vergessen

Verfasst: 18. Jul 2020 09:48
von JDog1895
Mit HashMap ist natürlich noch einmal eine ganz andere Herausforderung.

Ich freue mich aber, dass mein Problem noch jemandem helfen konnte.

Dank Udos Grundlage konnte ich meine Regel noch ein wenig verfeinern (ich nutze tatsächlich aktuell für jedes Fenster eine separate Regel; HashMap behalte ich aber im Hinterkopf).

Falls es noch von Interesse ist, hier mein aktueller Code:

Code: Alles auswählen

// Globale Variablen zu Beginn der Datei definieren!
var int windowtime = 0                  // Allgemein, um die Öffnungszeiten der Fenster anzupassen
val currMonth = now.getMonthOfYear      // Allgemein, um die Öffnungszeiten der Fenster anzupassen, indem der Monat abgefragt wird
var Timer Schlafzimmer_timer = null     // Variable verfügbar machen
var Number nCount = 0                   // Counter für Schlafzimmer

// Schlafzimmerfenster Alarmierung, falls zu lange geöffnet

rule "Schlafzimmerfenster Alarm"
when
    Item XiaomiDoorSensorSchlafzimmerIsOpen changed
then
    Schlafzimmer_timer?.cancel                               // the ? will skip this line if Schlafzimmer_timer is null
    logInfo("Schlafzimmer_timer", "Das Schlafzimmerfenster ist {}", XiaomiDoorSensorSchlafzimmerIsOpen.state)
    if(XiaomiDoorSensorSchlafzimmerIsOpen.state == OPEN) {
                if(currMonth == 1 || currMonth == 2 || currMonth == 12) {
					windowtime = 5
				}
				else if(currMonth == 3 || currMonth == 11) {
					windowtime = 10
				}
				else if(currMonth == 4 || currMonth == 9) {
					windowtime = 15
				}
				else if(currMonth == 5 || currMonth == 10) {
					windowtime = 20
				}
				else if(currMonth == 6 || currMonth == 7 || currMonth == 8) {
					windowtime = 25
                }
        logInfo("Schlafzimmer_timer", "Starte Timer mit {} Minuten.",windowtime)
        if(now.getHourOfDay > 6 && now.getHourOfDay < 11) {  // zwischen 7:00 Uhr und 10:59 Uhr
            nCount = 0
            Schlafzimmer_timer = createTimer(now.plusMinutes(windowtime), [ |
                nCount = nCount + 1
                logInfo("Schlafzimmer_timer", "Das Schlafzimmerfenster ist zu lange geöffnet! {}.te Meldung.",nCount)
                XiaomiMiSmartHomeGatewayVolume.sendCommand(10)
                if(nCount == 1)
                    say("Das Fenster im Schlafzimmer ist zu lange geöffnet.", "marytts:bits3hsmm")         
                else
                    say("Das Fenster im Schlafzimmer ist zu lange geöffnet. Dies ist die Erinnerung.", "marytts:bits3hsmm")
                Schlafzimmer_timer.reschedule(now.plusMinutes(5))
            ])
        }
    } else
        logInfo("Schlafzimmer_timer", "Breche Timer ab.")
end
Ich habe es heute endlich geschafft meine Squeezebox als Soundausgabegerät zu verwenden und komme so Stück für Stück vom Xiaomi-Gateway weg. Was ich noch interessant fand, die Anpassung des Timers auf Grundlage der Jahreszeit.

Viele Grüße
Matthias