Rule für Lüften Warnung basierend auf Änderung der Gruppenmitglieder

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

technick90
Beiträge: 39
Registriert: 24. Jul 2019 16:56
Answers: 1

Rule für Lüften Warnung basierend auf Änderung der Gruppenmitglieder

Beitrag von technick90 »

Hallo,

meine Rule für die Warnung zum Lüften (Fenstersensoren) bestand bisher aus einer Regel pro Sensor.

Das habe ich nun deutlich abgekürzt.

Code: Alles auswählen

rule "Fenster Status"
when                                          
  Member of Fenstersensoren changed                      
then 
val String itemLabel = triggeringItem.label.toString
val String itemName = triggeringItem.name.toString
val String itemNameSperren = itemName.replace("Kontakt","Sperren")
var Number nCount = 0 
var Timer nTimer = null
  if (triggeringItem.state == "Offen") {
      nCount = 0
	  nTimer = createTimer(now.plusMinutes(13), [|              
		nCount = nCount + 1
		if (nCount == 1) 
			{
			AlexaWohnzimmer_Ankuendigung.sendCommand(itemLabel + "ist seit 13 Minuten geöffnet")
			logInfo(itemNameSperren)
			}
        if (nCount > 1)
			{
			AlexaWohnzimmer_Ankuendigung.sendCommand(itemLabel + "ist länger als 13 Minuten geöffnet")
			}
		nTimer.reschedule(now.plusMinutes(5))
      ])                                                         
  }
  else {
	nTimer.cancel
	nTimer = null
   }
end
Jedoch habe ich ein Item um die Regel außer Kraft zu setzen.

Das war in der alten Rule wie folgt berücksichtigt:

Code: Alles auswählen

rule "Wohnzimmer-Fenster Status"
when                                          
  Item MQTTSensorWohnzimmerTerrasse_Kontakt changed                        
then          
  if ( (MQTTSensorWohnzimmerTerrasse_Kontakt.state == "Offen") && (MQTTSensorWohnzimmerTerrasse_Sperren.state != ON) ) {
      nCountWohnzimmerFenster = 0
	  nTimerWohnzimmerFenster = createTimer(now.plusMinutes(13), [|              
		nCountWohnzimmerFenster = nCountWohnzimmerFenster + 1
		if (nCountWohnzimmerFenster == 1) 
			{
			AlexaWohnzimmer_TTS.sendCommand("Terassentür im Wohnzimmer ist seit 13 Minuten geöffnet")
			}
        if (nCountWohnzimmerFenster > 1)
			{
			AlexaWohnzimmer_TTS.sendCommand("Terassentür im Wohnzimmer ist länger als 13 Minuten geöffnet")
			}
		nTimerWohnzimmerFenster.reschedule(now.plusMinutes(5))
      ])                                                         
  }
  else {
	nTimerWohnzimmerFenster.cancel
	nTimerWohnzimmerFenster = null
   }
end
Den Namen des Items zum Sperren ermittle ich bereits in meiner Rule. Aber das ist dann ein Stringobjekt, mit dem kann ich nicht den Wert des entsprechenden Items abrufen.
Wie kann ich also den in der Variable gespeicherten Namen des Item verwenden um für diesen Item den Wert (state) zu ermitteln?

Gruß

Robert
von udo1toni » 13. Jan 2023 21:53
Ah, Du hast nichts davon geschrieben, dass Du die Meldung mehrfach raushauen willst...

Code: Alles auswählen

import org.openhab.core.model.script.ScriptServiceUtil
import java.util.Map
val Map<String, Timer> contactTimers = newHashMap
val Map<String, Boolean> contactList = newHashMap

rule "Fenster Status"
when
    Member of Fenstersensoren changed
then
    val String itemLabel = triggeringItem.label
    val String itemName = triggeringItem.name
    val String itemNameSperren = itemName.replace("Kontakt","Sperren")
    val GenericItem SperrenItem = ScriptServiceUtil.getItemRegistry?.getItem(itemNameSperren) as GenericItem
    var vName = triggeringItem.name.split("_").get(1)
    var vTimerName = "timer_" + vName
    contactTimers.get(vTimerName)?.cancel;
    if((triggeringItem.state == "Offen") && (SperrenItem.state != ON)) {
        contactList.put(vTimerName,true)
        contactTimers.put(vTimerName, createTimer(now.plusMinutes(13)) [|
            var text = itemLabel + "ist "
            if(contactList.get(vTimerName)) {
                contactList.put(vTimerName,false)
                text = text + "seit "
            } else
                text = text + "länger als "
            text = text + " 13 Minuten geöffnet"
            AlexaWohnzimmer_Ankuendigung.sendCommand(text)
            AlexaBad_TTS.sendCommand(text)
            AlexaArbeitszimmer_TTS.sendCommand(text)
            AlexaKueche_TTS.sendCommand(text)
            sendNotification("abc@googlemail.com", text, "contact", "Info")
            contactTimers.get(vTimerName)?.reschedule(now.plusMinutes(5))
        ])
    } else
        contactTimers.get(vTimerName)?.cancel
end
Gehe zur vollständigen Antwort
Zuletzt geändert von technick90 am 13. Jan 2023 20:16, insgesamt 1-mal geändert.

technick90
Beiträge: 39
Registriert: 24. Jul 2019 16:56
Answers: 1

Re: Status eines Items basierend auf Variable

Beitrag von technick90 »

Ich habe fleißig weiter gegoogelt und die Lösung selbst gefunden.

Code: Alles auswählen

import org.openhab.core.model.script.ScriptServiceUtil

rule "Fenster Status"
when                                          
  Member of Fenstersensoren changed                      
then 
val String itemLabel = triggeringItem.label.toString
val String itemName = triggeringItem.name.toString
val String itemNameSperren = itemName.replace("Kontakt","Sperren")
val GenericItem SperrenItem = ScriptServiceUtil.getItemRegistry?.getItem(itemNameSperren) as GenericItem

var Number nCount = 0 
var Timer nTimer = null
  if ((triggeringItem.state == "Offen") && (SperrenItem.state != ON)) {
      nCount = 0
	  nTimer = createTimer(now.plusMinutes(13), [|              
		nCount = nCount + 1
		if (nCount == 1) 
			{
			AlexaWohnzimmer_Ankuendigung.sendCommand(itemLabel + "ist seit 13 Minuten geöffnet")
			}
        if (nCount > 1)
			{
			AlexaWohnzimmer_Ankuendigung.sendCommand(itemLabel + "ist länger als 13 Minuten geöffnet")
			}
		nTimer.reschedule(now.plusMinutes(5))
      ])                                                         
  }
  else {
	nTimer.cancel
	nTimer = null
   }
end
Es kann natürlich trotzdem mal jemand über das Script schauen. Denn z. B. beim Schließen gibt es einen Fehler im Log wegen nTimer.cancel.

technick90
Beiträge: 39
Registriert: 24. Jul 2019 16:56
Answers: 1

Re: Status eines Items basierend auf Variable

Beitrag von technick90 »

Ich korrigiere. Die Rule funktioniert noch nicht wie gewünscht.
Die Geschichte mit dem Timer funktioniert in dieser Konstellation wohl nicht wie gewünscht.
Für heute ist mein Kopf dicht.

Benutzeravatar
udo1toni
Beiträge: 15248
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: Status eines Items basierend auf Variable

Beitrag von udo1toni »

Dein Problem besteht darin, dass Du die Variable, in der Du den Zeiger auf den Timer speicherst, lokal definierst. Damit ist die Variable nicht mehr gültig, wenn die Rule beendet ist (das ist nach ein paar Millisekunden, nicht erst, wenn der Timer abläuft).

Der Weg über die Itemregistry ist eine Möglichkeit, das passende Item zu finden, Du kannst aber auch eine Group nutzen, in der Du alle betroffenen Items versammelst. Dann kannst Du mit

Code: Alles auswählen

GroupItem.members.filter[i|i.name == derberechnetestring].head
auf genau dieses Item als Item zugreifen.
.members liefert eine Liste aller Member von GroupItem. .filter[] liefert eine Liste (!) aller Items, auf die die angegebene(n) Bedingung(en) gilt/gelten.
.head schließlich liefert das erste Element der Liste, und zwar als natives Element, also in diesem Fall, da es eine Liste von Items ist, als Item. Du kannst diesen Bandwurm einfach einer Variablen zuweisen, um nacheinander auf verschiedene Aspekte des Items zuzugreifen, also z.B. .name, .state und vielleicht noch ein .sendCommand()
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

technick90
Beiträge: 39
Registriert: 24. Jul 2019 16:56
Answers: 1

Re: Status eines Items basierend auf Variable

Beitrag von technick90 »

Habe mich gerade noch zu global scope und local scope belesen. In meiner alten Rule habe ich die Variablen am Anfang definiert, dadurch ist es dann wohl global scope.
Dort gab es aber eine Variable pro Fenster, Beispiel:

Code: Alles auswählen

var Number nCountWohnzimmerFenster = 0
var Number nCountBadFenster = 0  
var Timer nTimerWohnzimmerFenster = null 
var Timer nTimerBadFenster = null  
Das möchte ich bei der neuen rule natürlich nicht mehr.
Wenn ich jetzt aber nur nTimer und nCount als global scope Variable definiert wird doch der Wert bei 2 gleichzeitig geöffneten Fenstern überschrieben oder nicht?
Anders formuliert, beim 2. geöffneten Fenster wird die Regel ja ein 2. Mal ausgeführt und überschreibt die Variable oder nicht?
Oder ordnet er die Variable und deren Wert trotzdem der Laufzeit jedes einzelnen Scripts zu?

Benutzeravatar
udo1toni
Beiträge: 15248
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: Status eines Items basierend auf Variable

Beitrag von udo1toni »

So genau hatte ich mir Deine Rule gar nicht angeschaut... Wenn Du mehrere voneinander unabhängige Timer brauchst, musst Du die als Array definieren und in der Rule jeweils den passenden Timer ermitteln.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

technick90
Beiträge: 39
Registriert: 24. Jul 2019 16:56
Answers: 1

Re: Status eines Items basierend auf Variable

Beitrag von technick90 »

Das mit dem Timer klappt nun.

Code: Alles auswählen

import org.openhab.core.model.script.ScriptServiceUtil
import java.util.Map
val Map<String, Timer> contactTimers = newHashMap

rule "Fenster Status"
when                                          
  Member of Fenstersensoren changed                      
then 
val String itemLabel = triggeringItem.label.toString
val String itemName = triggeringItem.name.toString
val String itemNameSperren = itemName.replace("Kontakt","Sperren")
val GenericItem SperrenItem = ScriptServiceUtil.getItemRegistry?.getItem(itemNameSperren) as GenericItem

var vName = triggeringItem.name.split("_").get(1)
var vTimerName = "timer_" + vName

contactTimers.get(vTimerName)?.cancel;

  if ((triggeringItem.state == "Offen") && (SperrenItem.state != ON)) {
	  contactTimers.put(vTimerName, createTimer(now.plusMinutes(13)) [|             
			AlexaWohnzimmer_Ankuendigung.sendCommand(itemLabel + "ist seit 13 Minuten geöffnet")
      ])     
	}
  else {
contactTimers.get(vTimerName)?.cancel
   }
end
Nun fehlt mir aber noch der Count. Der wird benötigt um nach dem ersten Hinweis (hier 13) Minuten den Timer neu zu starten und nach erneuten Ablauf einen geänderten Text zu wiedergeben.
Sprich nach 13 Minuten soll die Meldung kommen: Fenster ist seit 13 Minuten geöffnet.
Nach 18 Minuten soll die Meldung kommen: Fenster ist länger als 13 Minuten geöffnet.

Ich weiß das ich das auch mit einem Array lösen muss, ich weiß aber nicht wie.

Benutzeravatar
udo1toni
Beiträge: 15248
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: Status eines Items basierend auf Variable

Beitrag von udo1toni »

Na ja, Du musst Dir halt genau wie beim Timer eine globale Map anlegen. Innerhalb des Lambda (der Code zwischen [| und ] musst Du zum einen prüfen, ob der passende Eintrag vorhanden ist, zum anderen musst Du je nach Ergebnis Deine Ausgabe abwandeln. Außerdem musst Du, wenn der Timer zum ersten Mal abläuft, den Timer per reschedule erneut ausführen lassen.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

technick90
Beiträge: 39
Registriert: 24. Jul 2019 16:56
Answers: 1

Re: Status eines Items basierend auf Variable

Beitrag von technick90 »

Den Gedanken verstehe ich, aber trotz zahlreichen Googeln muss ich gestehen das ich es nicht hinbekomme.

Kann mir jemand mein Script entsprechend anpassen?

Benutzeravatar
udo1toni
Beiträge: 15248
Registriert: 11. Apr 2018 18:05
Answers: 242
Wohnort: Darmstadt

Re: Status eines Items basierend auf Variable

Beitrag von udo1toni »

Na hier:

Code: Alles auswählen

contactTimers.get(vTimerName)?.cancel;

  if ((triggeringItem.state == "Offen") && (SperrenItem.state != ON)) {
	  contactTimers.put(vTimerName, createTimer(now.plusMinutes(13)) [|             
			AlexaWohnzimmer_Ankuendigung.sendCommand(itemLabel + "ist seit 13 Minuten geöffnet")
      ])     
	}
  else {
contactTimers.get(vTimerName)?.cancel
   }
end
ergänzen...

Code: Alles auswählen

contactTimers.get(vTimerName)?.cancel;
if((triggeringItem.state == "Offen") && (SperrenItem.state != ON)) {
    contactList.put(vTimerName,true)
    contactTimers.put(vTimerName, createTimer(now.plusMinutes(13)) [|             
        if(contactList.get(vTimerName)) {
            contactList.put(vTimerName,false)
            AlexaWohnzimmer_Ankuendigung.sendCommand(itemLabel + "ist seit 13 Minuten geöffnet")
            contactTimers.get(vTimerName)?.reschedule(now.plusMinutes(5))
        } else {
            AlexaWohnzimmer_Ankuendigung.sendCommand(itemLabel + "ist seit mehr als 13 Minuten geöffnet")
        }
    ])     
} else {
    contactTimers.get(vTimerName)?.cancel
}
end
Und natürlich musst Du contactList global als Map anlegen, analog zu contactTimers.

Falls Du wiederkehrend alls 5 Minuten eine Warnung haben möchtest, musst Du das reschedule einfach außerhalb des if-Blocks verschieben, so dass es immer ausgeführt wird.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Antworten