Seite 1 von 1

Rule mit mehreren else if

Verfasst: 18. Apr 2020 12:00
von KlausGünther
Guten Morgen,

ich habe einen Fehler in einer Rule und finde den fehler nicht.
Folgendes soll passieren. Ich möchte alle 5min gucken wie die Außentemperatur ist und dann
je nach Außentemperatur eine Zahl per MQTT übermitteln. Auf der Gegenseite empfänt ein
ESP32 die Zahl und stellt dann anhand der Zahl an einem LED Streifen eine bestimmte Farbe ein.

Dummerweise landet er immer bei 9, sprich im Else Fall.

Bei der logInfo kommt folgendes raus:
2020-04-18 11:53:00.019 [INFO ] [smarthome.model.script.Temperature: ] - 20.13 °C

Dann müsste als Ergebnios ja eigtl. 5 rauskommt, aber egal was ich mache, er bleibt immer
bei der 9.

Code: Alles auswählen

rule "Temperatur an ESP321 anzeigen" 
when
        Time cron "0 0/5 * * * ?"
then 
		var State = (TF_Barometer_1_Temperatur.state)
		
		if  (State <= -10) {
       		MQTT_ESP321_Input.sendCommand(1)
		}
		else if  (State <= 0) {
        	MQTT_ESP321_Input.sendCommand(2)
		}
		else if  (State <= 10) {
        	MQTT_ESP321_Input.sendCommand(3)
		}
		else if  (State <= 18) {
        	MQTT_ESP321_Input.sendCommand(4)
		}
		else if  (State <= 25) {
        	MQTT_ESP321_Input.sendCommand(5)
		}
		else if  (State <= 30) {
        	MQTT_ESP321_Input.sendCommand(6)
		}
		else if  (State <= 40) {
        	MQTT_ESP321_Input.sendCommand(7)
		}
		else if  (State <= 51) {
        	MQTT_ESP321_Input.sendCommand(8)
		}
		else {
        	MQTT_ESP321_Input.sendCommand(9)
		logInfo("Temperature: ", State.toString())
		}

end        	
Ich habe es von der Logik mal umgehdreht, dann kommt gar kein Command mehr....


Code: Alles auswählen

rule "Temperatur an ESP321 anzeigen" 
when
        Time cron "0 0/1 * * * ?"
then 
		var State = (TF_Barometer_1_Temperatur.state)
		
		if  (State > 51) {
        	MQTT_ESP321_Input.sendCommand(9)
		}
		else if  (State <= 51) {
        	MQTT_ESP321_Input.sendCommand(8)
		}
		else if  (State <= 40) {
        	MQTT_ESP321_Input.sendCommand(7)
		}
		else if  (State <= 30) {
        	MQTT_ESP321_Input.sendCommand(6)
		}
		else if  (State <= 25) {
        	MQTT_ESP321_Input.sendCommand(5)
		}
		else if  (State <= 18) {
        	MQTT_ESP321_Input.sendCommand(4)
		}
		else if  (State <= 10) {
        	MQTT_ESP321_Input.sendCommand(3)
		}
		else if  (State <= 0) {
        	MQTT_ESP321_Input.sendCommand(2)
		}
		else if (State <=-10) {
       	 	MQTT_ESP321_Input.sendCommand(1)
		logInfo("Temperature: ", State.toString())
		}
end		

Was mache ich falsch ?

Re: Rule mit mehreren else if

Verfasst: 18. Apr 2020 12:46
von Darkwin101
Also erstmal muss das else auch immer in Eckige Klammer also immer else { if..... sonst werde einfach alle else nacheinander ausgeführt und da du nicht Bereiche abfragst ist es logisch das immer das letzte rauskommt denn -20 <= 51 ergibt wahr.
Ich würde ebenso Bereiche Abfragen also immer if(State >40 && <= 51) usw.
Hier mal als Beispiel für die Klammersetzung:

Code: Alles auswählen

if  (State <= -10) {MQTT_ESP321_Input.sendCommand(1)}
	else { if  (State <= 0) {MQTT_ESP321_Input.sendCommand(2)}
		else { if  (State <= 10) { MQTT_ESP321_Input.sendCommand(3)}
               		}
   	      }
end
Zudem musst du eventuell noch das °C entfernen

Code: Alles auswählen

var State = (TF_Barometer_1_Temperatur.state as Number).floatValue

Re: Rule mit mehreren else if

Verfasst: 18. Apr 2020 13:21
von KlausGünther
Ich habe das so umgesetzt und sage herzlich
DANKE!
Funktioniert. Logik-Fehlerverstanden!

Code: Alles auswählen

rule "Temperatur an ESP321 anzeigen" 
when
        Time cron "0 0/1 * * * ?"
then 
		var State = (TF_Barometer_1_Temperatur.state as Number).floatValue
		

		if  (State <= -10) {MQTT_ESP321_Input.sendCommand(1)}
			else { if  (State <= 0) {MQTT_ESP321_Input.sendCommand(2)}
					else { if  (State <= 10) { MQTT_ESP321_Input.sendCommand(3)}
               			 else { if  (State <= 18) { MQTT_ESP321_Input.sendCommand(4)}
               			 		else { if  (State <= 25) { MQTT_ESP321_Input.sendCommand(5)}
									else { if  (State <= 30) { MQTT_ESP321_Input.sendCommand(6)}
										else { if  (State <= 40) { MQTT_ESP321_Input.sendCommand(7)}
											else { if  (State <= 50) { MQTT_ESP321_Input.sendCommand(8)}
               			 						 else { if  (State > 50) { MQTT_ESP321_Input.sendCommand(9)}
               			 						 
													 }
												}
											 }
										  }
									 }					
						    	}
					}
   	      		 }		
end

Re: Rule mit mehreren else if

Verfasst: 18. Apr 2020 16:12
von udo1toni
Huh... das sieht aber schon etwas hässlich aus... :)

Die Logik für solche Wertebereiche ist aber eigentlich ganz einfach. Du musst allerdings auf das else verzichten, und die Reihenfolge ist nicht egal:

Code: Alles auswählen

rule "Temperatur an ESP321 anzeigen" 
when
    Time cron "0 0/5 * * * ?"
then 
    if(!(TF_Barometer_1_Temperatur.state instanceof Number)) {
        logWarn("esp321","kein gültiger Temperaturwert! ({})",TF_Barometer_1_Temperatur.state)
        return;
    }
    val Number nTemp = (TF_Barometer_1_Temperatur.state as Number).floatValue
    var Number nOut = 1
    if(nTemp > -10) nOut = 2
    if(nTemp >   0) nOut = 3
    if(nTemp >  10) nOut = 4
    if(nTemp >  18) nOut = 5
    if(nTemp >  25) nOut = 6
    if(nTemp >  30) nOut = 7
    if(nTemp >  40) nOut = 8
    if(nTemp >  51) nOut = 9
    logInfo("esp321","Temperatur: {}°C, Befehl: {}",nTemp,nOut)
    MQTT_ESP321_Input.sendCommand(nOut)
end
Im ersten Teil wird sichergestellt, dass eine gültige Temperatur geliefert wird. Man könnte hier auch noch eine Überprüfung auf Schlüssigkeit vornehmen (z.B. Temperatur über -30°C, weil der Temperaturfühler sich in einer Umgebung befindet, wo niedrigere Temperaturen nicht auftreten und eine solche Temperatur auf einen defekten Sensor hindeutet)
Im zweiten Teil wird der Number Konstanten nTemp die Temperatur zugewiesen, wobei, falls es sich um ein UoM (Units of Measurement) Item handelt, die Einheit entfernt wird.
Danach wir die Number Variable nOut mit 1 gefüllt. Nun wird die Variable immer mit einem neuen Wert gefüllt, solange die betreffende Bedingung erfüllt ist. z.B. bei einer Temperatur von 16 °C sind die ersten drei Bedingungen erfüllt, die Variable wird also bis zur 4 geändert, danach aber nicht mehr.
Zum Schluss wird eine passende Meldung ausgegeben und das Ergebnis an das Item gesendet.

Allerdings muss dieser Aufwand gar nicht sein, denn es gibt für genau diesen Zweck die Scale Transformation.
Die Scale Transformation muss dazu installiert sein.
Du definierst eine Datei transform/temp.scale mit folgendem Inhalt:

Code: Alles auswählen

[..-10]=1   // kleiner oder gleich -10
]-10..0]=2  // größer -10 und kleiner oder gleich 0
]0..10]=3   // ..
]10..18]=4
]18..25]=5
]25..30]=6
]30..40]=7
]40..51]=8
]51..]=9    // größer 51
NaN=0       // keine gültige Zahl
Bitte keine Leerzeichen zum Aufhübschen einfügen und auch hier die Reihenfolge beachten (die Datei wird von oben nach unten durchlaufen, der erste Eintrag, der matcht, wird verwendet). Die Kommentare kannst Du natürlich weg lassen, sie dienen nur der Erläuterung, wie eine Zeile zu verstehen ist.
Anschließend reicht in der Rule folgendes:

Code: Alles auswählen

rule "Temperatur an ESP321 anzeigen" 
when
    Time cron "0 0/5 * * * ?"
then 
    if(!(TF_Barometer_1_Temperatur.state instanceof Number)) {
        logWarn("esp321","kein gültiger Temperaturwert! ({})",TF_Barometer_1_Temperatur.state)
        return;
    }
    val Number nTemp = (TF_Barometer_1_Temperatur.state as Number).floatValue
    val Number nOut = transform("SCALE","temp.scale",nTemp)
    logInfo("esp321","Temperatur: {}°C, Befehl: {}",nTemp,nOut)
    MQTT_ESP321_Input.sendCommand(nOut)
end
um den gleichen Effekt zu erzielen. Der Witz ist allerdings, dass Du die Scale Transformation auch direkt in der Item Definition verwenden kannst. Vorausgesetzt, Du hast kein UoM Item, landet der jeweilige Wert direkt im Item.
Wahlweise kannst Du die Transformation auch nur im Label verwenden, die Einschränkung (kein UoM) gilt aber auch hier. Den letzten Eintrag (NaN) braucht man natürlich nur für den Fall, dass nicht sichergestellt ist, dass es sich um eine Zahl handelt. Für die Rule braucht man das also nicht, wohl aber, wenn man es in einem Item direkt verwendet.

Re: Rule mit mehreren else if

Verfasst: 18. Apr 2020 18:07
von KlausGünther
LÄUFT

DANKE für den super cleanen Code und die Möglichkeit dadurch mal wieder etwas zu lernen.

Re: Rule mit mehreren else if

Verfasst: 14. Feb 2023 13:11
von Thor4x
Keine Frage von mir, sondern nur ein "Danke" für den Lösungsvorschlag.

Ich schließe damit in Abhängigkeit von der Außentemperatur ein elektrisches Dachfenster, was wir ansonsten gerne mal vergessen zu schließen.

Code: Alles auswählen

rule "Dachfenster im Gäste-WC in Abhängigkeit von der Außentemperatur automatisch schließen"
when
	Item GaesteWC_Rollo_Dachfenster_Level changed from 100 to 0	
then 
    val Number nTemp = (localCurrentTemperature.state as Number).floatValue
    var Number nOut = 1
    if(nTemp > -50) nOut = 2
    if(nTemp >   5) nOut = 4
    if(nTemp >  10) nOut = 8
    if(nTemp >  15) nOut = 16
    if(nTemp >  20) nOut = 32
    if(nTemp >  25) nOut = 16
    if(nTemp >  30) nOut = 8
    logInfo("shutter" , "Außentemperatur: {}°C, Dachfenster wird in {} Minuten geschlossen.",nTemp,nOut)
	createTimer(now.plusMinutes(nOut)) [
		GaesteWC_Rollo_Dachfenster_Set.sendCommand(DOWN)
		logInfo("shutter" , "Außentemperatur: {}°C, Dachfenster wurde nach {} Minuten geschlossen.",nTemp,nOut)
		sendTelegram("x" , "Das Dachfenster wurde automatisch geschlossen.")		
	]
end
Der Code ist zwar nicht perfekt (z.B. die Namensgebung meiner Items sowie nicht mit previousState und newState gearbeitet), aber zielführend. :)