Seite 1 von 2

nach Update auf OH4 geht eine Rule nicht mehr

Verfasst: 18. Jul 2023 22:27
von domjo75
Hallo zusammen,

in meinen ersten Wochen mit Openhab habe ich, mit Hilfe von Udo eine Taupunktberechnung für unseren Wäschekeller entwickelt.
Seit dieser Zeit tat das Script klaglos seinen Dienst.

Jetzt ist mir gestern die SSD von meinem System verreckt und ich musste neu aufsetzen.
Zum Glück hatte ich ein relativ aktuelles Backup. Trotzdem ist das eine Menge Arbeit.

Jedenfalls hat er mit direkt OH4 installiert und das Taupunkt-Script funktioniert nicht mehr.
Ich vermute, dass er jetzt Probleme mit der Funktion, die die Berechnung an sich macht.
Alleine steige ich da nicht durch. Vielleicht bekomme ich das mit Eurer Hilfe gelöst.
Das könnte ja eventuell auch für andere interessant sein.

Hier das Script:

Code: Alles auswählen

val org.eclipse.xtext.xbase.lib.Functions$Function2<Double, Double, Double> getDewPoint = [
	
	Double Temperature, 
	Double Humidity 
	
	|

	var Double a
	var Double b
	var Double SDD
	var Double DD
	var Double v
	var Double t = Temperature
	var Double h = Humidity
	
	if (t >= 0.0){ // T >= 0 °C
		a = 7.5
		b = 237.3
	} else { // T < 0 °C über Wasser
		a = 7.6
		b = 240.7
	}
	SDD=(6.1078 * Math::pow(10.0, ((a*t)/(b+t))))
	DD = (h/100.0*SDD)
	v = Math::log10((DD/6.107))
	return ((b*v)/(a-v))

]

rule "Klima - Taupunktberechnung Außen" // calculation of outdoor dewpoint
when

	Item Out_THSensor_Temp received update or
	Item Out_THSensor_Hum received update or
	System started

then

	if (Out_THSensor_Dew.state == NULL) {Out_THSensor_Dew.postUpdate(0)}
	
	if ((Out_THSensor_Temp.state != NULL) && (Out_THSensor_Hum.state != NULL))
	{

		var t = (Out_THSensor_Temp.state as QuantityType<Number>).doubleValue
		var h = (Out_THSensor_Hum.state as QuantityType<Number>).doubleValue
		
		// OutsideThermometerCombined.sendCommand(String::format("%.1f°C / %.0f%%", t, h))
	
		Out_THSensor_Dew.postUpdate(getDewPoint.apply(t, h))
			
	}

end

rule "Klima - Taupunktberechnung Innen" // calculation of basement dewpoint
when

	Item In_THSensor_Temp received update or
	Item In_THSensor_Hum received update or
	System started

then
	if (In_THSensor_Dew.state == NULL) {In_THSensor_Dew.postUpdate(0)}

	if ((In_THSensor_Temp.state != NULL) && (In_THSensor_Hum.state != NULL))
	{

		var t = (In_THSensor_Temp.state as QuantityType<Number>).doubleValue
		var h = (In_THSensor_Hum.state as QuantityType<Number>).doubleValue
		
		// OutsideThermometerCombined.sendCommand(String::format("%.1f°C / %.0f%%", t, h))
	
		In_THSensor_Dew.postUpdate(getDewPoint.apply(t, h))
			
	}

end

rule "Klima - Taupunktdifferenz berechnen" // for statistics: dewpoint difference
when
	Item In_THSensor_Dew changed or
	Item Out_THSensor_Dew changed
then
	var dewpoint_keller = (In_THSensor_Dew.state as Number).doubleValue
	// var dewpoint_keller = In_THSensor_Dew.state
	var dewpoint_aussen = (Out_THSensor_Dew.state as Number).doubleValue
	// var dewpoint_aussen = Out_THSensor_Dew.state
	Taupunkt_Differenz.postUpdate(dewpoint_keller - dewpoint_aussen)
end
Die Fehlermeldung hierzu sieht so aus:

Code: Alles auswählen

2023-07-18 14:05:40.899 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'Klima_Taupunktberechnung-1' failed: cannot invoke method public abstract java.lang.Object org.eclipse.xtext.xbase.lib.Functions$Function2.apply(java.lang.Object,java.lang.Object) on null in Klima_Taupunktberechnung
2023-07-18 14:05:40.899 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'Klima_Taupunktberechnung-2' failed: cannot invoke method public abstract java.lang.Object org.eclipse.xtext.xbase.lib.Functions$Function2.apply(java.lang.Object,java.lang.Object) on null in Klima_Taupunktberechnung
Ich freue mich mal wieder was zu lernen :)

Re: nach Update auf OH4 geht eine Rule nicht mehr

Verfasst: 19. Jul 2023 05:41
von udo1toni
Ich denke, im großen und Ganzen sollte die Rule eigentlich funktionieren.
Es kann aber gut sein, dass einzelne Items einen ungültigen Status haben. Die Differenzberechnung verlässt sich darauf, dass beide Items gültig sind, was definitiv zu Beginn nicht der Fall ist. Kann also gut sein, dass Du inzwischen keine Fehlermeldung mehr bekommst.
Falls Du die Items persistierst und mit restoreOnStartup beim Start wiederherstellst, wäre das beim ersten Start natürlich nicht der Fall, weil diese Daten vermutlich durch das Upgrade auf 4.0.0 unbrauchbar geworden sind (verändertes Verhalten der Persistence in Bezug auf UoM Items)

Anbei mal die "moderne" Fassung der Rules:

Code: Alles auswählen

/* openHAB sollte selbst erkennen, 
ob es sich um Function oder Procedure handelt 
Deshalb einfach so...
*/

val getDewPoint = [ Double Temperature, Double Humidity | 
    var Double a
    var Double b
    var Double SDD
    var Double DD
    var Double v
    var Double t = Temperature
    var Double h = Humidity
    
    if(t >= 0) { // T >= 0 °C
        a = 7.5
        b = 237.3
    } else { // T < 0 °C über Wasser
        a = 7.6
        b = 240.7
    }
    SDD = (6.1078 * Math.pow(10, a * t / (b + t)))
    DD = (h / 100 * SDD)
    v = Math.log10(DD / 6.107)
    return b * v / (a - v)
]

rule "Klima - Taupunktberechnung Außen"              // calculation of outdoor dewpoint
when
    Item Out_THSensor_Temp changed or                // changed ist hinreichend
    Item Out_THSensor_Hum changed                    // System started ist hier nicht sinnvoll!
then
    if(!(Out_THSensor_Dew.state instanceof Number)) {  // Besser als Prüfung auf NULL
        logDebug("taupunkt","Out_THSensor_Dew ungültig, setze 0")
        Out_THSensor_Dew.postUpdate(0)
    }
    if(!(Out_THSensor_Temp.state instanceof Number)) {
        logWarn("taupunkt","Out_THSensor_Temp ungültig, Abbruch!")
        return;
    }
    if (!(Out_THSensor_Hum.state instanceof Number)) {
        logWarn("taupunkt","Out_THSensor_Hum ungültig, Abbruch!")
        return;
    }
    val t = (Out_THSensor_Temp.state as QuantityType<Number>).doubleValue
    val h = (Out_THSensor_Hum.state as QuantityType<Number>).doubleValue
    
    // OutsideThermometerCombined.postUpdate(String.format("%.1f °C / %.0f %%", t, h))

    Out_THSensor_Dew.postUpdate(getDewPoint.apply(t, h))
end

rule "Klima - Taupunktberechnung Innen" // calculation of basement dewpoint
when
    Item In_THSensor_Temp changed or
    Item In_THSensor_Hum changed
then
    if(!(In_THSensor_Dew.state instanceof Number)) {
        logDebug("taupunkt","In_THSensor_Dew ungültig, setze 0")
        In_THSensor_Dew.postUpdate(0)
    }
    if(!(In_THSensor_Temp.state instanceof Number)) {
        logWarn("taupunkt","In_THSensor_Temp ungültig, Abbruch!")
        return;
    }
    if(!(In_THSensor_Hum.state instanceof Number)) {
        logWarn("taupunkt","In_THSensor_Hum ungültig, Abbruch!")
        return;
    }
    val t = (In_THSensor_Temp.state as QuantityType<Number>).doubleValue
    val h = (In_THSensor_Hum.state as QuantityType<Number>).doubleValue
    
    In_THSensor_Dew.postUpdate(getDewPoint.apply(t, h))
end

rule "Klima - Taupunktdifferenz berechnen" // for statistics: dewpoint difference
when
    Item In_THSensor_Dew changed or
    Item Out_THSensor_Dew changed
then
    if(!(Out_THSensor_Dew.state instanceof Number)) {
        logWarn("taupunkt","Out_THSensor_Dew ungültig, Abbruch!")
        return;
    }
    if(!(In_THSensor_Dew.state instanceof Number)) {
        logWarn("taupunkt","In_THSensor_Dew ungültig, Abbruch!")
        return;
    }
    val dewpoint_keller = (In_THSensor_Dew.state as Number).doubleValue
    val dewpoint_aussen = (Out_THSensor_Dew.state as Number).doubleValue

    Taupunkt_Differenz.postUpdate(dewpoint_keller - dewpoint_aussen)
end
Hauptunterschiede: Die Definition der Funktion kann wesentlich schlanker und "ansehnlicher" erfolgen, vor allem kann openHAB (schon lange) selbst entscheiden, ob es nun Procedure oder Function bauen muss. Die Anzahl und der Typ der übergebenen Variablen ist ebenfalls bekannt, muss also nicht doppelt definiert werden.
Beim Aufruf der Taupunktberechnung ist es nicht sinnvoll, auf received update zu triggern. Wenn sich kein Ausgangswert ändert, muss der Zielwert auch nicht erneut berechnet werden.
Ebenso kann System started entfallen, denn bei Systemstart sind die Items eventuell noch gar nicht mit sinnvollen Werten gefüllt. Sobald ein Item jedoch einen sinnvollen Wert enthält, tritt ein changed Ereignis auf und die Rule wird ohnehin getriggert. Das gilt übrigens auch, wenn das Item aus einer Persistence per restoreOnStartup seinen Initialen Status erhält
Der Test auf gültige Werte geschieht besser auf instanceof Number, statt auf != NULL, denn ein Number Item (auch die vom Typ UoM) kann sehr wohl noch weitere ungültige Werte enthalten, z.B. UNDEF, was halt nicht NULL ist.
Und wenn wir schon auf ungültige Werte prüfen, wäre es ja schick, das überall zu tun, wo nicht absolut sicher ist, dass jederzeit ein gültiger Wert anliegt (Taupunktdifferenz...) sowie die Rule abzubrechen, nachdem eine entsprechende Warnung ausgegeben wurde.
Ansonsten habe ich diverse unnötige Klammern entfernt und die "modernere" Notation Math.pow, statt Math::pow (usw.) verwendet. Diese sollte auch schon eine Weile funktionieren (macht letztlich keinen Unterschied, sieht aber hübscher aus...)

Wie gesagt, ich gehe davon aus, dass die Berechnung ohnehin nur initial fehlgeschlagen ist, weil entweder In_- oder Out_THSensor_Dew den Status NULL oder UNDEF hatten.

Falls es dennoch hartnäckig nicht funktionieren will, wäre mein Tipp, die Itemdefinitionen insbesondere der UoM Items sehr genau zu überprüfen und davor das komplette Changelog seit OH3.4.4 zu lesen, vor allem den für Milestone 3, das ist der mit den Breaking Changes UoM betreffend.

Re: nach Update auf OH4 geht eine Rule nicht mehr

Verfasst: 19. Jul 2023 20:39
von domjo75
Hallo Udo,
Danke für die Anpassung. Ich probiere das morgen mal aus.
Du hast Recht, dass der Fehler nur zum System-Start auftritt.
Aber die Ermittlung der Taupunkt-Temperatur rechnet neuerdings falsch.
Beide DEW Items habe -41,x Grad als Value. Das ist im Sommer nicht so realistisch 🤭

Re: nach Update auf OH4 geht eine Rule nicht mehr

Verfasst: 20. Jul 2023 05:59
von udo1toni
Da wäre mein Tipp, dass die Wertübernahme an einer Stelle nicht klappt und in der Folge zumindest einer der werte (vermutlich aber beide...) 0 ist (also Temperatur und Luftfeuchte). Auch das kann mit der unzureichenden Prüfung auf gültige Werte zu tun haben...

Re: nach Update auf OH4 geht eine Rule nicht mehr

Verfasst: 20. Jul 2023 08:40
von domjo75
So, ich hab mir das jetzt mal angeschaut.
Das ITEM OUT_THSensor_Temp zeigt heute morgen 21 Grad an.
Das ITEM Out_THSensor_Hum zeigt mir 0,57 an. Wenn ich in der UI das ITEM öffne, wird mir allerdings 57% angezeigt.
Ich vermute, dass sich ein Rechenfehler aufgrund der 0,57 ergibt. Ich weiss aber auch nicht, wie das unter OH3.x war.

Ich switche dann mal zum neuen Script und schau was passiert.

Edit: es gibt schon mal keine Fehler im LOG. Allerdings sind die Taupunktwerte noch immer bei -41 Grad.
@Udo: Weisst Du noch wo wir die Formel her hatten? Dann könnte man ja rückwärts rechnen und den Fehler ermitteln?!

Re: nach Update auf OH4 geht eine Rule nicht mehr

Verfasst: 20. Jul 2023 22:44
von udo1toni
Die Formel sollte ja weiterhin passen, wichtiger ist also, die Daten aus der Rule heraus zu loggen. Ich habe in der aktualisierten Version ja schon ein wenig logging eingebaut :) Also ein paar zusätzliche Zeilen...

Code: Alles auswählen

val getDewPoint = [ Double Temperature, Double Humidity | 
    var Double a
    var Double b
    var Double SDD
    var Double DD
    var Double v
    var Double t = Temperature
    var Double h = Humidity
    
    log.debug("taupunkt","Funktion: t = {} °C, h = {} %", t, h)                            // <--- gerne auch hier
    if(t >= 0) { // T >= 0 °C
        a = 7.5
        b = 237.3
    } else { // T < 0 °C über Wasser
        a = 7.6
        b = 240.7
    }
    SDD = (6.1078 * Math.pow(10, a * t / (b + t)))
    DD = (h / 100 * SDD)
    v = Math.log10(DD / 6.107)
    return b * v / (a - v)
]

rule "Klima - Taupunktberechnung Außen"                                                    // calculation of outdoor dewpoint
when
    Item Out_THSensor_Temp changed or                                                      // changed ist hinreichend
    Item Out_THSensor_Hum changed                                                          // System started ist hier nicht sinnvoll!
then
    if(!(Out_THSensor_Dew.state instanceof Number)) {                                      // Besser als Prüfung auf NULL
        logDebug("taupunkt","Out_THSensor_Dew ungültig, setze 0")
        Out_THSensor_Dew.postUpdate(0)
    }
    if(!(Out_THSensor_Temp.state instanceof Number)) {
        logWarn("taupunkt","Out_THSensor_Temp ungültig, Abbruch!")
        return;
    }
    if (!(Out_THSensor_Hum.state instanceof Number)) {
        logWarn("taupunkt","Out_THSensor_Hum ungültig, Abbruch!")
        return;
    }
    val t = (Out_THSensor_Temp.state as QuantityType<Number>).doubleValue
    val h = (Out_THSensor_Hum.state as QuantityType<Number>).doubleValue
    log.debug("taupunkt","Außen: Temperatur = {} °C, Luftfeuchte = {} %", t, h)            // <--- hier
    // OutsideThermometerCombined.postUpdate(String.format("%.1f °C / %.0f %%", t, h))

    Out_THSensor_Dew.postUpdate(getDewPoint.apply(t, h))
end

rule "Klima - Taupunktberechnung Innen" // calculation of basement dewpoint
when
    Item In_THSensor_Temp changed or
    Item In_THSensor_Hum changed
then
    if(!(In_THSensor_Dew.state instanceof Number)) {
        logDebug("taupunkt","In_THSensor_Dew ungültig, setze 0")
        In_THSensor_Dew.postUpdate(0)
    }
    if(!(In_THSensor_Temp.state instanceof Number)) {
        logWarn("taupunkt","In_THSensor_Temp ungültig, Abbruch!")
        return;
    }
    if(!(In_THSensor_Hum.state instanceof Number)) {
        logWarn("taupunkt","In_THSensor_Hum ungültig, Abbruch!")
        return;
    }
    val t = (In_THSensor_Temp.state as QuantityType<Number>).doubleValue
    val h = (In_THSensor_Hum.state as QuantityType<Number>).doubleValue
    log.debug("taupunkt","Innen: Temperatur = {} °C, Luftfeuchte = {} %", t, h)            // <--- hier
    
    In_THSensor_Dew.postUpdate(getDewPoint.apply(t, h))
end

rule "Klima - Taupunktdifferenz berechnen" // for statistics: dewpoint difference
when
    Item In_THSensor_Dew changed or
    Item Out_THSensor_Dew changed
then
    if(!(Out_THSensor_Dew.state instanceof Number)) {
        logWarn("taupunkt","Out_THSensor_Dew ungültig, Abbruch!")
        return;
    }
    if(!(In_THSensor_Dew.state instanceof Number)) {
        logWarn("taupunkt","In_THSensor_Dew ungültig, Abbruch!")
        return;
    }
    val dewIn = (In_THSensor_Dew.state as Number).doubleValue
    val dewOut = (Out_THSensor_Dew.state as Number).doubleValue
    log.debug("taupunkt","Diff: Taupunkt Innen = {} °C, Taupunkt Außen = {} °C", dewIn, dewOut) // <--- hier

    Taupunkt_Differenz.postUpdate(dewIn - dewOut)
end
Und dann musst Du natürlich noch das Logging aufdrehen, damit die debug Meldungen auch geloggt werden, über die Karaf Konsole

Code: Alles auswählen

log:set DEBUG org.openhab.core.module.script.taupunkt
Falls Du nicht weißt, wie das mit der Karaf Konsole funktioniert und es jetzt auch nicht rausfinden willst (schade...), ändere die logDebug Anweisung nach logInfo ab (Parameter sind identisch).
Das Logging in der Funktion ist im Prinzip alternativ zu den Aufrufen in den Rules, da dort identische Werte kommen sollten. :)
Die naheliegende Vermutung wäre ja, dass die Luftfeuchte um Faktor 100 verkehrt übernommen wird, das würde die extrem tiefe Temperatur erklären. Dann wird allerdings der Messwert im Item ebenfalls verkehrt sein, was zum Problemfeld UoM hervorragend passen würde. Du müsstest also im Zweifel das Item korrekt konfigurieren (korrekt im Sinne von: In openHAB4 korrekt).

Re: nach Update auf OH4 geht eine Rule nicht mehr

Verfasst: 21. Jul 2023 14:28
von domjo75
Danke, Udo... Das versuche ich mal heute Abend einzubauen.
Wenn mein Luftfeuchtesensor plötzlich Werte liefert, die um den Faktor 100 abweichen, ist das vermutlich ein Fehler im HomeMatic Bindng.
Aber sehen wir dann...

Re: nach Update auf OH4 geht eine Rule nicht mehr

Verfasst: 21. Jul 2023 15:20
von udo1toni
Nein, das wird ein Konfigurationsfehler sein, wie gesagt, es gab exakt an dieser Stelle Breaking Changes die zu exakt diesem Fehlerbild führen, das ist nicht unerwartet. Du musst für das Item im Zweifel die In-Einheit genauso mit angeben wie die Anzeige-Einheit, und die In-Einheit muss zur gelieferten Größe des Channels passen.

Re: nach Update auf OH4 geht eine Rule nicht mehr

Verfasst: 22. Jul 2023 13:44
von domjo75
so, kurzes Update.

Geht jetzt wieder. wenn man ein bisschen Ruhe hat und sich da einliest, klappt das auch.
Am Ende steht alles in den ReleaseNotes:
https://github.com/openhab/openhab-dist ... g/4.0.0.M3

War jetzt halt nen bisschen blöd, dass mich das so kalt erwischt hat. Aber vermutlich hätte ich es auch so überlesen.

Ich musste einfach nur meine definierten ITEMS mit unit="%.0f %%", formatieren:

Code: Alles auswählen

Number:Dimensionless  In_THSensor_Hum  "Innen Luftfeuchte [%.0f %%]"  <Humidity>  (Waschkueche)	[Measurement,Humidity]	{unit="%.0f %%", channel="homematic:HM-WDS40-TH-I-2:3014F711A0001F9A499D39C6:MEQ1652741:1#HUMIDITY"}

Number:Dimensionless  Out_THSensor_Hum "Aussen Luftfeuchte [%.0f %%]" <Humidity>  (Garten)	[Measurement,Humidity]	{unit="%.0f %%", channel="homematic:HM-WDS10-TH-O:3014F711A0001F9A499D39C6:MEQ1600501:1#HUMIDITY", homekit="HumiditySensor"}
Ich persönlich hätte es schöner gefunden, wenn man statt NUMBER:DIMENSIONLESS gleich NUMBER:HUMIDITY nutzen könnte. Für Temperature geht das ja aus. Aber wir brauchen ja Luft nach oben.

Danke UDO für die, wiedermal, hilfreiche Unterstützung. :)

Re: nach Update auf OH4 geht eine Rule nicht mehr

Verfasst: 22. Jul 2023 14:25
von udo1toni
domjo75 hat geschrieben: 22. Jul 2023 13:44 Ich persönlich hätte es schöner gefunden, wenn man statt NUMBER:DIMENSIONLESS gleich NUMBER:HUMIDITY nutzen könnte. Für Temperature geht das ja auch. Aber wir brauchen ja Luft nach oben.
Ja, aber nein.
Es ist "Zufall", dass es Number:Temperature heißt.
Gemeint ist die zu verwendende Einheit, das sind bei Temperaturen halt die möglichen Einheiten für Temperaturen, °C, °F und K (ohne °).
Für die Luftfeuchte gibt es aber keine "eigene" Einheit, dort wird nur % verwendet. Die Einheit ist also dimensionslos.
Es gibt noch viele andere Einheiten, wo es auch nicht unbedingt naheliegend ist, wie das korrekte Schlüsselwort lautet, aber man kann das ja sehr gut über die UI heraus finden, notfalls schaut man in die verhasste Dokumentation, die hier wirklich auskunftsfreudig ist :)