Seite 1 von 1

Anzahl der Regeln optimieren

Verfasst: 22. Dez 2020 20:45
von shaggy0815
Hallo liebes Forum,

ich wollte versuchen die Anzahl meiner verwendeten Regeln zu optimieren.

Beispielsweise habe ich diverse Bewegungsmelder im Einsatz, welche mir auch einen Temperaturwert liefern. Für diese habe ich bisher jeweils eine
separate Regel geschrieben welche mir eine Meldung per Telegram schicken, wenn ein bestimmter Schwellenwert unterschritten wird.

Alle diese Bewegungsmelder sind in der Gruppe gTemperatur

Ich habe folgende Items:

Code: Alles auswählen

Number:Temperature   LowerHallSensorTemperature    "Temperatur Flur unten 1 [%.1f °C]"  <temperature> (gTemperatur)   {channel="hue:0302:1:tsFlurUnten1:temperature"}
Number:Temperature   LowerHallSensorTemperature2    "Temperatur Flur unten 2 [%.1f °C]"  <temperature> (gTemperatur)   {channel="hue:0302:1:tsFlurUnten2:temperature"}
Number:Temperature   UpperHallSensorTemperature    "Temperatur Flur oben [%.1f °C]"  <temperature> (gTemperatur)     {channel="hue:0302:1:tsFlurOben:temperature"}
Switch               hs_LowLowerHallSensorTemperature
Switch               hs_HighLowerHallSensorTemperature
Switch               hs_LowLowerHallSensorTemperature2
Switch               hs_HighLowerHallSensorTemperature2
Switch               hs_LowUpperHallSensorTemperature
Switch               hs_HighUpperHallSensorTemperature
Und folgende Regel geschrieben:

Code: Alles auswählen

val telegramAction = getActions("telegram","telegram:telegramBot:Telegram_Bot")

rule "Temperatur Bewegungsmelder zu niedrig"
when 
    Member of gTemperatur changed
then
    var Schwellenwert = 15|°C
    if((triggeringItem.state < Schwellenwert) && ("hs_Low"+triggeringItem.state != ON)){
    val telegramAction = getActions("telegram","telegram:telegramBot:Telegram_Bot")
    telegramAction.sendTelegram(triggeringItem.name.toString + " zu niedrig") 
    //"hs_Low"+triggeringItem.sendCommand("ON")  
    //"hs_High"+triggeringItem.sendCommand("OFF")   
    sendCommand("hs_Low"+triggeringItem, "ON")
    sendCommand("hs_High"+triggeringItem, "OFF")
    logInfo("Temperatur", triggeringItem.name.toString + " zu niedrig")     
    }
end
Die Telegram Meldungen funktionieren damit so wie gewünscht. Allerdings bekomme ich jetzt alle 5 Minuten die gleiche Meldung,
wenn einer der Schwellenwerte unterschritten wurde (weil der Entsprechende Bewegungsmelder alle 5 Minuten aktualisiert).

Dafür waren die mit hs_Low... bzw. hs_High... beginnenden Hilfsswitches gedacht. Diese habe ich absichtlich so benannt, dass ich
an das eigentliche Bewegungsmelder Item lediglich diese Präfixe angehangen habe.

Wenn jetzt z.B. der Schwellenwert vom Item LowerHallSensorTemperature unterschritten wird, soll der Hilfsswitch
hs_LowLowerHallSensorTemperature auf ON gehen und mir damit weitere Meldungen unterdrücken.

Mit meinen Einzelregeln hat das auch perfekt funktioniert. In meiner neuen Regel versuche ich mir quasi das Item
hs_LowLowerHallSensorTemperature zusammenzubauen, damit die Regel allgemeingültig funktioniert. Siehe if-Teil der Regel.
Offensichtlich geht das im if-Teil nicht.

Weiter unten baue ich mir das Item hs_LowLowerHallSensorTemperature für den sendCommand() Befehl nach gleichem Schema auf
und es funktioniert. Das entsprechende Item wechselt zu ON wenn der Schwellenwert unterschritten wird.

Warum geht das also im if-Teil nicht? Vielleicht gibts ja auch noch eine bessere Lösung das gewünschte Verhalten zu realisieren. Also
die wiederholten Meldungen zu unterdrücken.

PS:
Ich hätte natürlich dann noch eine Zweite Regel die mir beim überschreiten des Schwellenwertes eine Meldung schickt, dass die
Temperatur wieder ok ist. Welche dann jeweils das Item mit dem Präfix hs_High... auf ON setzen würde.

Ich hoffe das war jetzt nicht zu umständlich beschrieben und man kann verstehen was ich meine.

In diesem Sinne, besten Dank schon mal fürs Durchhalten bis hier hin und für eventuelle Lösungsansätze.

Re: Anzahl der Regeln optimieren

Verfasst: 23. Dez 2020 00:19
von udo1toni
Die Zeile

Code: Alles auswählen

    if((triggeringItem.state < Schwellenwert) && ("hs_Low"+triggeringItem.state != ON)){
kann schon mal nicht korrekt sein, wenn, dann müsste es ("hs_Low"+triggeringItem.name).state heißen. Allerdings funktioniert das so nicht, denn ("hs_Low"+triggeringItem.name) ist nur ein einfacher String, Du benötigst aber ein Item. Am einfachsten geht das über eine weitere Gruppe, in der Du alle Items zusammenpackst. Nennen wir die Gruppe mal gSwitchLH. Alle SwitchItems aus Deinem Post packst Du in diese Gruppe. Und diese (eine) Rule:

Code: Alles auswählen

rule "Temperatur Bewegungsmelder"
when 
    Member of gTemperatur changed
then
    val itemLow  = gSwitchLH.members.filter[i|i.name=="hs_Low"  + triggeringItem.name].head
    val itemHigh = gSwitchLH.members.filter[i|i.name=="hs_High" + triggeringItem.name].head
    val thLow = 15|°C
    val thHigh = 25|°C
    val telegramAction = getActions("telegram","telegram:telegramBot:Telegram_Bot")

    if(triggeringItem.state < thLow && itemLow.state != ON) {
        telegramAction.sendTelegram(triggeringItem.name + " zu niedrig") 
        itemLow.postUpdate(ON)
        if(itemHigh.state != OFF) itemHigh.postUpdate(OFF)
        logInfo("Temperatur", "{} zu niedrig",triggeringItem.name)
    } else if(triggeringItem.state > thHigh && itemHigh.state != ON) {
        telegramAction.sendTelegram(triggeringItem.name + " zu hoch") 
        if( itemLow.state != OFF)  itemLow.postUpdate(OFF)
        itemHigh.postUpdate(ON)
        logInfo("Temperatur", "{} zu hoch",triggeringItem.name)
    } else if(triggeringItem.state < thHigh && triggeringItem.state > thLow) {
        if( itemLow.state != OFF)  itemLow.postUpdate(OFF)
        if(itemHigh.state != OFF) itemHigh.postUpdate(OFF)
        logInfo("Temperatur", "{} ok",triggeringItem.name)
    }
end
Die "Magie" geschieht in den ersten beiden Zeilen, dort wird jeweils das passende Item für Unter- bzw. Obergrenze aus der Gruppe herausgesucht.
Es gibt drei Möglchkeiten; Die gemeldete Temperatur ist zu niedrig, zu hoch oder im Temperaturfenster. In letzterem Fall werden beide Grenzitems zurückgesetzt (natürlich nur, falls sie aktiv waren). In den anderen beiden Fällen muss (wie in Deiner Rule auch) noch zusätzlich geprüft werden, ob das Verlassen des Temperaturfensters neu ist. Der Rest ist ein wenig optimiert, z.B. ist triggeringItem.name bereits ein String.

Edit: ich habe den Rest Deines Postings nicht aufmerksam genug gelesen... Grundsätzlich wirst Du aber vermutlich ohnehin eine Hysterese einbauen wollen...

Re: Anzahl der Regeln optimieren

Verfasst: 23. Dez 2020 10:47
von shaggy0815
Hallo Udo,

vielen Dank für Deine Hilfestellung.

Ich denke ich hab es auch soweit verstanden. Nur eine kleine Frage hätte ich noch zu der Zeile die das Wunder bewirkt.

Code: Alles auswählen

val itemLow  = gSwitchLH.members.filter[i|i.name=="hs_Low"  + triggeringItem.name].head
Ich verstehe, hiermit wird die Gruppe durchsucht auf den Zusammengesetzten Namen "hs_Low"+triggeringItem.name. Dieser ist
aber bis dahin noch immer ein String. Wodurch wird jetzt daraus ein Item? Durch das .head am Ende dieser Code-Zeile?

Im Prinzip war das mein Problem. Ein Item zu bekommen wenn ich nur einen String habe.

Ich hatte ursprünglich sogar nur an zwei Bereiche gedacht. Temperatur zu niedrig oder Temperatur ok. Das eine Präfix hätte ich
dann besser hs_OK nennen sollen. Aber deine Variante mit den drei Bereichen gefällt mir besser.

Edit:
Habe jetzt die Regel von Dir am laufen und wie sicherlich zu erwarten, funktioniert alles einwandfrei. Dann werde ich
versuchen das gelernte auf weitere Regeln von mir anzuwenden. Vielen Dank nochmals...

Re: Anzahl der Regeln optimieren

Verfasst: 23. Dez 2020 13:45
von udo1toni
Das Group Item hat die Eigenschaft .members.

Die Eigenschaft .members liefert eine Liste aller unmittelbaren Teilnehmer. Jedes einzelne Element der Liste ist vom Typ Item.
Mit der Methode .filter[] wird nun die Liste gefiltert, und zwar auf solche Elemente die den Bedingungen innerhalb des Lambdas entsprechen. Dabei wird das Lambda für jedes Item einzeln überprüft. Vor dem | steht, wie das Listenelement substituiert wird (im Beispiel durch den Buchstaben i) Das heißt, jedes Listenelement wird jeweils als i eingesetzt und die Bedingung auf der rechten Seite des | überprüft. Trifft die Bedingung zu, so wird dieses Element weitergereicht, trifft sie nicht zu, so wird das Element unterdrückt.
Nun gibt es grundsätzlich 3 Möglichkeiten, die alle abgedeckt werden müssen: 1. Es gibt mehrere Einträge, die gültig sind. 2. Es gibt exakt einen Eintrag, der gültig ist. 3. Es gibt keinen Eintrag, der gültig ist. Damit es einfach bleibt, ist das Ergebnis des Filters immer noch eine Liste, denn das funktioniert für alle drei Fälle.

Nun wollen wir aber genau ein Item als Ergebnis haben. Wir wissen auch (im Gegensatz zu openHAB...), dass die Liste immer exakt einen Eintrag hat, denn wir haben ja den Filter entsprechend definiert :). Deshalb nehmen wir uns einfach den obersten Eintrag der Liste (das ist .head) und haben nun ein Item. Dieses befindet sich nach der Zuweisung in der Variablen, die also als Objekt alle Eigenschaften vom Item erbt.


Gesendet von iPad mit Tapatalk

Re: Anzahl der Regeln optimieren

Verfasst: 24. Dez 2020 12:59
von shaggy0815
Besten Dank für die ausführliche Erklärung.

Ich versuche ja eigentlich immer erstmal zu googeln wie die Dinge funktionieren. Aber so ausführlich wie Du mir das jetzt erklären
konntest, finde ich speziell zu dem Thema Methoden etc. in openHAB nie was.

Wahrscheinlich kann man das alles wirklich nur über solche Foren wie dieses hier erlernen...

Wenn ich Gruppen benutze, enthalten diese ja immer Items. Also komm ich über Gruppen auch immer nur an ein Item ran. Dessen
Methoden wirken dann also immer nur auf Item-Ebene, wenn ich das jetzt richtig verstanden habe.

Wenn ich nun allgemeingültig auf Things zugreifen möchte. Gibt es da etwas ähnliches? Also beispielsweise um den Status von
Lampen anzupassen wenn diese hart Ausgeschaltet wurden.

Bisher hab ich da für jede Lampe auch immer eine einzelne Regel, weil ja immer die UID der einzelnen Lampe benötigt wird.

Re: Anzahl der Regeln optimieren

Verfasst: 25. Dez 2020 17:09
von udo1toni
In der Rules DSL gibt es dazu leider nichts passendes, da müsstest Du auf die NG Rules ausweichen. Allerdings möchte ich empfehlen, dann erst mal auf OH3 upzugraden, falls das möglich ist (d.h. man nutzt keine V1 Bindings...). OH3 läuft sehr stabil, ich bin nur deshalb noch nicht produktiv damit, weil ich tatsächlich noch einen Showstopper habe, das ist das VDR Binding. Wenn ich passenden Ersatz (z.B. mit exec oder mqtt...) gebastelt habe, steige ich auch um. Bis dahin spiele ich nur im Testsystem...

Re: Anzahl der Regeln optimieren

Verfasst: 28. Dez 2020 22:40
von mcdandrew
Mit dem Umstieg auf Openhab 3 versuche ich auch gleichzeitig meine Rules zu optimieren und die bisher ungenutzten Groups einzuführen.

Folgende Situation...

Ich habe auf meinem Grundstück 4 Webcams verteilt und möchte informiert werden falls eine Webcam nicht mehr erreichbar ist.
Bisher habe ich dafür 4 verschiedene Rules erstellt und und dies geprüft. Nun habe ich alle Webcams in eine Gruppe gepackt und löse ein Event aus wenn sich ein Mitglied dieser Gruppe ändert. Eigentlich funktioniert alles wie gewünscht, wollte nur kurz fragen ob es eventuell eine einfachere Möglichkeit gibt....bin mir nicht sicher ob das mit der Liste wirklich notwendig ist.

Code: Alles auswählen

//
Group:Switch:OR(ON,OFF) gwebcam "Webcam"
Switch	 WebcamEinfahrt_Online		"Webcam Einfahrt"		(gwebcam)	{channel="network:pingdevice:WebcamEinfahrt_Online:online"}
Switch	 WebcamCarport_Online		"Webcam Carport"		(gwebcam)	{channel="network:pingdevice:WebcamCarport_Online:online"}
Switch	 WebcamSpielhaus_Online		"Webcam Spielhaus"		(gwebcam)	{channel="network:pingdevice:WebcamSpielhaus_Online:online"}
Switch	 Webcam_Garten_Online		"Webcam Garten"		(gwebcam)	{channel="network:pingdevice:WebcamGarten_Online:online"}

Code: Alles auswählen

rule "webcam_offline"
when
	Member of gwebcam changed from ON to OFF
	then
		//ITEM der Gruppe mit Status OFF auslesen
		val lastItem = gwebcam.members.filter[i | i.state==OFF ].head
		//Label für Ausgabe
		val labelOfItem = lastItem.label
		
		val telegramAction_bot = getActions("telegram","telegram:telegramBot:bot")
		telegramAction_daniel.sendTelegram(labelOfItem  + " nicht mehr erreichbar") 
end
Das Problem sehe ich nun auch wenn es mehrere nicht mehr erreichbare Kameras gibt.
Ich hatte es erst mit "triggeredItem" probiert doch das klappte nicht.

Re: Anzahl der Regeln optimieren

Verfasst: 29. Dez 2020 20:27
von udo1toni
Die implizite Variable heißt triggeringItem, nicht triggeredItem. Mit openHAB3 gilt diese nur für Rules, die mit Member of als Trigger arbeiten, nicht jedoch bei Item als Trigger.

Ansonsten möchtest Du vielleicht tatsächlich nicht nur über die zuletzt offline gegangene Camera informiert werden, sondern über alle, also z.B. so:

Code: Alles auswählen

rule "webcam_offline"
when
    Member of gwebcam changed from ON to OFF
then
    var strCams = ""
    val iList = gwebcam.members.filter[i | i.state==OFF ]
    if(iList.size==1)
        strCams = iList.head.name 
    else
        iList.forEach[j,k|
            strCams = strCams + j.name 
            if(k == iList.size - 1)
                strCams = strCams + "und "
            else if(k == iList.size)
                strCams = strCams + " "
            else
                strCams = strCams + ", "
        ]
    val telegramAction_bot = getActions("telegram","telegram:telegramBot:bot")
    telegramAction_daniel.sendTelegram(labelOfItem  + "nicht mehr erreichbar") 
end
ungetestet...