I gave up on OH 2.3 Unit of Measure (UM)

Iā€™m torn. Maybe thatā€™s a good idea, but maybe not.
We will see how this evolves.

ā€“ Christoph

Iā€™m having troubles with implementing UoM as well. :roll_eyes: Quick question: Is this supposed to work or am I doing something wrong? I am trying to do calculations with gas consumption, which is in cubic metres.

rule "Test"
when
    System started
then
    val n = 5|m3
end

The expected warning about the unused value aside: Iā€™m getting a:

[ERROR] [ntime.internal.engine.RuleEngineImpl] - Error during the execution of startup rule 'Test': unexpected token 8

Putting the cubic metres in quotes doesnā€™t help. Other units like ā€œWā€ or ā€œweekā€ work just fine.

Iā€™m on 2.5.0.M1 but 2.4.0 produces the same result.

Thanks a lot in advance for any input!

Can you try instead:

val n = 5|mĀ³

It doesnā€™t show the error for me when I use it this way in a rule.
If that also works for you the documentation needs to be updated. :slight_smile:

1 Like

Oh no! :man_facepalming: Yes that works. I feel a bit stupid now. :slight_smile: Although in my defense the ā€œpower of threeā€ isnā€™t even on the Mac keyboard and I hadnā€™t considered such a rare character to be working.

Thanks a million for the quick response! :+1:

1 Like

Excellent news that it now works! :smiley:

The documentation also contains several wrong unit symbols, so Iā€™ve created a PR to update it:

4 Likes

Thanks

Hi, itā€™s me again. I am using lots of Functions and Procedures and found that any UoM argument needs to be of QuantityType<Number> or the rule wouldnā€™t execute. E.g. QuantityType<Angle> wouldnā€™t work. Is there anything I can do about that or is that normal / ā€œstandard procedureā€?

Having said this, I found that a Procedure or Function doesnā€™t accept a negative angle as an argument. One use case is handing over a negative elevation (sun below horizon). In case anyone is wondering.

test.rules:

rule "Test"
when
    System started
then
    val Procedures$Procedure1<QuantityType<Number>> elevation = [ angle |
        logError("Test", "Elevation is: " + angle)
    ]

    // VSCode: Type mismatch: cannot convert from QuantityType<?> to QuantityType<Number>
    // Log:    Configuration model 'test.rules' has errors, therefore ignoring it: [xx,xx]: no viable alternative at input '|'   
    // elevation.apply(-5|Ā°)
    // elevation.apply((-5)|Ā°)
    
    // VSCode: Type mismatch: cannot convert from QuantityType<?> to QuantityType<Number>
    // Log:    Nothing logged (rule works)
    elevation.apply(5|Ā° * -1) // Elevation is: -5 Ā°
    elevation.apply(-5|"Ā°")   // Elevation is: -5.0 Ā°

    // No errors
    elevation.apply(5|Ā°)      // Elevation is: 5 Ā°
    elevation.apply(5|"Ā°")    // Elevation is: 5 Ā°
end

Iā€™m also curious about the sudden conversion to floating point in case of (-5|ā€œĀ°ā€).

It would be great if someone could shed light on this.

Thanks,
Jens

Take anything VScode says about this with a pinch of salt. These are new features and may not be fully recognized by the extension yet, so worth seeing what happens when you actually execute them.

Please keep experimenting and let us know!

I think thatā€™s just an oddity about rules use of Number and parsing - hyphen, it crops up all over the place unconnected with UoM.

1 Like

Thanks for the feedback! :+1: I did some further experiments and here is an updated version of the rule that does run successfully with a negative angle.

// VSCode goes up in flames, but Rules DSL is fine with the import
import org.eclipse.smarthome.core.library.dimension

rule "Test"
when
    System started
then
    // Strongly typing with Angle instead of Number makes the procedure
    // accept negative angles. VSCode and Angle are not friends, though.
    val Procedures$Procedure1<QuantityType<Angle>> elevation = [ angle |
        logError("Test", "Elevation is: " + angle)
    ]

    elevation.apply(-5|Ā°)
end

This is what happened: I once got an error by the Rules DSL which I thought was from the import and didnā€™t try that ever again because I thought the import wouldnā€™t work. So I stuck with Number. Turns out the import works fine. And with it,

QuantityType<Angle>

(etc.) can be used. The procedure in my example then accepts negative angles. I still think Number not accepting a negative angle is a bug. But it works now! And everythingā€™s strongly typed. Yay! :slight_smile:

1 Like

Iā€™ve not seen it do this. My example does not work.

Number:ElectricCurrent	 ffjj " Value [%.1f mA]"

Am I missing something? I cannot see it change when I give it a value of 100 or 0.1. Result printed is always mA

Apologies for hijack :slight_smile:

I think you need to more specific, like 100 A

EDIT - oh wait, did you mean automatically scaling a display, like Item vale 23005 A getting displayed as 23.005 kA? In theory [%f.3 %unit%] could do that, but I donā€™t think itā€™s implemented?

Hereā€™s another thing Iā€™ve learned. Persistence doesnā€™t return QuantityTypes so we sometimes need to convert a Number or primitive numerical value to QuantityType. This is how itā€™s done.

import org.eclipse.smarthome.core.library.unit.SIUnits

rule "Test"
when
    // Also triggered upon saving of file
    System started
then
    // This can be any item of type Number:Power (W)
    val item = WashingMachinePower

    // Its state is a QuantityType<Power> (W)
    val state = item.state
    logError("Test", "State: " + state)
    
    // Persistence produces a value of type DecimalType
    val average = item.averageSince(now.minusMinutes(5), "rrd4j")
    logError("Test", "Average: " + average)
    
    // Convert to QuanttyType using the constructor
    // QuantityType(Number, javax.measure.Unit)
    val averageTyped = new QuantityType(average, SIUnits.WATT)
    logError("Test", "Average (typed): " + averageTyped)

    // A way to convert to QuantityType from double using static
    // factory method
    val typed = QuantityType::valueOf(42, SIUnits.WATT)
    logError("Test", "Value 42 (typed): " + typed)
end

See also:

Now what we need is a bit of nifty code to interrogate the ā€œliveā€ Item to establish UoM, and automatically choose the ā€œrecreatedā€ value UoM.

I can see that causing odd issues when the unit of the live Item gets changed after some data already recorded. :crazy_face:

Haha! :slight_smile: Now that you mentioned it I got worried and checked my persisted values. Letā€™s say I have the following item. As the group name indicates is is persisted to DB every minute (for debugging).

Number:Power TestPower "Test [%d W]" (PersistDBEveryMinute)

When I do the following:

PowerItem.postUpdate(2000|W)

The number 2000 is written to DB. If I do the following:

PowerItem.postUpdate(2|kW)

You guessed it: The number 2 is written to DB. Shouldnā€™t the unit as defined in the item definition (in this case: W) be used? In my opinion this is really, really bad. It means that there either needs to be a proxy item for persistence or the postUpdate must never receive a different unit.

1 Like

I would suggest to have persistence store values in their canonical representation (SI units for most, imperial units for some). To avoid unit conversion errors, I would even adhere to persisting in SI, according to a defined convention (e.g. metre as canonical length unit).

Whenever UoM would be invoked, it would always know the starting unit. Any unit conversion requested would then use the proper factor.

1 Like

Oh. Um. That is ā€¦ undesirable. I mean, I understand the limitations of the persistence services not (yet) dealing with UoM properly, but thatā€™s a nasty consequence.

@rossko57, @shutterfreak Just fyi: I opened an issue over at GitHub.

2 Likes

This is indeed really, really bad. I would file this as a critical bug. The UoM seems to be causing more problems than it solves.

I totally understand your pain. Been there. Especially since there is no reason why rules have to fail.
IMHO that is something that should be fixed.
Some automatic type conversion would help.
I myself would not try the uom again until thats fixed.

Well, nothing is going to change for OH2.3 at this stage (the thread is from nearly four years ago).

Let us know if you want help with something specific.