Working with Number:Temperature Items in rules

Oh come on …you didn’t tell us what you used second time. :smiley:
There’s no cheating, there’s just ambiguous notation and unexpected results.
Anyway, easy enough to repeat the exercise. OH2-with-old-UoM-library still differs from your K results.

    var t = 20|°C
    var t2 = 68|°F

    var t8 = t2 * t / t2     // result 20 °C
    var t9 = t2 * t.toUnit(t2.getUnit) / t2    // result 68.00 °F
    var t10 = t2.toUnit(t.getUnit) * t / t2.toUnit(t.getUnit)  // result 20 °C
    var t11 = t2.toUnit(t.getUnit) * t / t2   // result 5.882352941176470588235294117647059 °C²/°F

t11 is :crazy_face:

This can be duplicated with constants, for better clarity

    var t8 = 68|°F * 20|°C / 68|°F     // result 20 °C
    var t9 = 68|°F * 68|°F / 68|°F    // result 68.00 °F
    var t10 = 20|°C * 20|°C / 20|°C  // result 20 °C
    var t11 = 20|°C * 20|°C / 68|°F   // result 5.882352941176470588235294117647059 °C²/°F

Unsurprisingly, t9 and t10 confirm that sticking to one unit “works”.

Is t8 “working” a mystery, then?
I’ll make the assumption that auto-conversion for mixed units is not applied in the divide case (in OH2).
We can test that -

var divpart = 20|°C / 68|°F  // result 0.2941176470588235294117647058823529 °C/°F

Yep, it’s just done maths on the numeric parts and made up a unit.
Hmm, curious now …

var divsame = 68|°F / 68|°F  // result 1

Aha - at some point in the processing the framework is smart enough to realize that °F/°F is a null unit and discard it.
While °C/°F is not null and is retained.
Here’s the difference we’ve been looking for I reckon.

What about multiply?

var multpart = 20|°C * 68|°F // result 1360 °C·°F
var square = 20|°C * 20|°C // result 400 °C²

Just as daft units, but the point is that we will always get a unit of some kind.
But now we can see what’s going on, if we fill partial results.

        // we can sneak weird units past the validator as a string
    var t8p = 68|°F * 0.2941176470588235294117647058823529 | "°C/°F"     // result 20.00000000000000000000000000000000 °C
    var t11p = 20|°C * 0.2941176470588235294117647058823529 | "°C/°F"   // result 5.882352941176470588235294117647058 °C²/°F

So the t8p result is “good”. It’s not identical to the “full” t8 calculation, with all those trailing zeros; perhaps just differences in number type handling when parsed.

And the t11p result can be understood. It’s just done simple maths with the numerics, no conversions, same as t8p.
But t8p units would be °F * °C/°F - framework is smart enough to cancel °°F/°F leaving just °C.
t11p units would be °C * °C/°F - no cancelling can be done, leaving °C²/°F

In summary, all mathematically correct, but probably not useful. 5.88°C²/°F is a “correct” answer but not in units we can use.
Maybe this is why UoM library has been updated.

OH2 users can manage all this in real life by following the golden rule “use the same units throughout”

That’s good info.
Maybe 3.1 UoM has a new policy of sorting out conflicting units in some ‘base’ unit, which would reasonably be K. Note that t/t2 has ‘unit/unit’ dimension if they are expressed in the same units, so t * t/t2 represents a conflict between t with unit and divide with unit/unit.

But your K results suggest it is making a right mess of this policy here.

1 Like

How do I specify a speed unit in km/h? When I try: if (speedItem.state > 5|km/h) I get the following error:

Script execution of rule with UID ‘somfy-4’ failed: The name ‘h’ cannot be resolved to an item or type; line 222, column 129, length 1 in somfy

Is there a way to cast the unit out? I’ve also tried using if ((speedItem.state as Number) > 5), but it does not seem to work either…

Maybe you have to escape the ‘/’ ?
if (speedItem.state > 5|km\/h)

Just throwing the idea …

/ is a maths operator, so we’ll have to hide it from the rules interpreter.

if ( speedItem.state > 5 | "km/h" ) 

There are methods shown in the first post to
extract the numeric part in whatever-units-it-come-in
extract the numeric part in some-unit-you-designate
extract the unit symbol

Heads up, openHAB will have concept of relative unit conversion Add QuantityType.toUnitRelative by ccutrer · Pull Request #3177 · openhab/openhab-core · GitHub that should help dealing with temperature units

openhab 3.3
openhab-js

I have the following Power Items defined:

Number:Power    El_GenPower     "PV Power"   (El_Generation)   ["Measurement","Power"]  
Number:Power  El_GridPower      "Active Grid Power"   (El_Grid)  ["Measurement","Power"]                             
    {channel="homewizard:p1_wifi_meter:__P1:active_power" , stateDescription="PG" [pattern="%.0f %unit%"]}
Number:Power  El_ActiveLoad "Active Load"   (El_Load) ["Measurement","Power"]                                 
    {stateDescription="PL" [pattern="%.0f %unit%"]}

El_GenPower is set by a rule and that works
El_GridPower is linked to a channel (of my smart power meter)

I want to determine El_ActiveLoad as the sum of the two other Powers, using a rule in openhab-js, where I do the following calculation in a ECMA-2021 script:

var load = ( (items.getItem('El_GridPower').state as QuantityType<Power>) + (items.getItem('El_GenPower').state as QuantityType<Power>) ) ;

items.getItem("El_ActiveLoad").postUpdate(load);

why does the variable definition and calculation fail with:

org.graalvm.polyglot.PolyglotException: SyntaxError: <eval>:5:50 Expected ) but found as
var load = ( (items.getItem('El_GridPower').state as QuantityType<Power>) + (items.getItem('El_GenPower').state as QuantityType<Power>) ) ;
                                                  ^

Per the reference docs for the JS Scripting Add-on (which should always be the first place you look) JavaScript Scripting - Automation | openHAB, items.getItem() returns a JavaScript Item Object. The JavaScript Item Object’s .state is a String.

But even if it were JavaScript doesn’t have an as operator and doesn’t really do casting. If it did, it’s certainly not going to understand the QuantityType<Power> notation which is a Java syntax. Finally, JavaScript doesn’t support operator overloading so you’ll never be able to just use + to do math with a QuantityType. you’ll have to use the .add() method to add them together.

For this old of an OH version, something like this might work OK.

var load = items.getItem('El_GridPower').rawState.add(items.getItem('El_GenPower').rawState);
items.getItem('El_ActiveLoad').postUpdate(load.toString()); // sendCommand and postUpdate always takes a string

In the most recent version of openhab-js, native JS support for QuantityTypes using the Quantity library has been provided. So something like this would work:

var load = items.El_GridPower.quantityState.add(items.El_GenPower.quantityState);
items.El_ActiveLoad.postUpdate(load.toString());

Continuing the discussion from Working with Number:Temperature Items in rules:

I read a few times the first post but am still struggeling with the math topic in rules:

I tried to do a calculation similar to this one:

var avg = ( (tempItemC.state as QuantityType<Temperature>) + (tempItemF.state as QuantityType<Temperature>) ) / 2 
 // returns 1.66666666666666666666666666666665 °C

My items are:

Number:Temperature		NE4_Wohnen_Temperatur			"Temperatur" 		<temperature> 		(NE4_WohnenEssen, gActpointN)	{channel="knx:device:bridge:EGN_NE4w_Taster:Temperatur", unit="°C", stateDescription=""[pattern="%.1f %unit%"]}
Number:Temperature		NO1_Bad_Temperatur				"Temperatur"  		<temperature>       (NO1_Bad, gActpointN)			{channel="knx:device:bridge:OGN_NO1_Taster:Temperatur", unit="°C", stateDescription=""[pattern="%.1f %unit%"]}

My rule:

    var avgC = ( (NE4_Wohnen_Temperatur.state as QuantityType<Temperature>) + (NO1_Bad_Temperatur.state as QuantityType<Temperature>) ) / 2
    logInfo("default.rules","Temperatur: " + avgC)

The current values of the temperatures are 18.5 °C and 18.8 °C.
The result of this simple average is “-117.925 °C”.
What am I doing wrong?

on openHAB 4.x? See Adjust QuantityType calculations for temperatures by mherwege · Pull Request #3792 · openhab/openhab-core · GitHub

@rossko57 the original post may need to be updated to avoid confusion to future readers

1 Like

Thanks for the info!

Converting to Kelvin and Converting back to degree after calculation is working fine :slight_smile:

    var avgC = (( (NE4_Wohnen_Temperatur.state as QuantityType<Temperature>).toUnit("K") + (NO1_Bad_Temperatur.state as QuantityType<Temperature>).toUnit("K") ) / 2).toUnit("°C")
    logInfo("default.rules","Temperatur: " + avgC)