UoM default units and consequences

don’t want to hijack this thread (again), but my pure-MQTT channel in 3.3 doesn’t show units for configuration. Perhaps it’s “homie-device-only”.

I’m pretty sure I’ve been using units for longer than the last six months but could be wrong. I only use Generic MQTT Things.

ah. Guess I was blind. found it.

PS: Thanks @mstormi for moving this into a new thread.

Indeed, I in fact had the menu open to do this myself and got distracted.

I’d think it’s time for a wrap up first.
Now with defaults to apply for every UoM item, taking the unit from the display pattern should no longer be needed or relevant.
If the new defaults apply first (then there always is a unit so the pattern will be ignored), I believe we should be fine and won’t need any fix in OH4.
Only if there’s situations where a unit isn’t set yet (such as after persistence restoreOnStartup) AND the pattern applies BEFORE new defaults apply, this might result in a problem and it would be a good idea to now remove that old behavior. I wouldn’t know of any modification that could apply before the new default does, but I don’t know the code well enough to verify or falsify my assumption.
Maybe @rossko57 you could setup a small test bed with 3.4 and try to figure that out ?

Also as a reminder to complicate any analysis even further, @J-N-K (who implemented this) mentioned there had been UoM defaults for some types/dimensions before this 3.4 change, temperature I believe being one of them. So probably not the best idea to try and test with right that.

I’m not sure that covers all the use cases and I fear getting into a situation where something is messed.

What’s the unit of the Item under these circumstances?

  1. no unit provided
  2. unit provided, same as system default
  3. unit provided, different from system default
Unit Provided No SD SD Same SD Different
None Default NA NA
Provided Default? with or without conversion? Provided SD? with or without conversion?

It’s that bottom right cell that causes problems. When the units provided from the binding is different from the units in the State Description. In the past, it was completely wrong (IMO) and it would apply the SD units without conversion, so my 22 °C becomes 22 °F.

I think it’s clear that it should do the conversion to SD at some point, but where? Before assigning the state to the Item? At display time only?

And of course persistence is a wholly different kettle of fish but there’s already an issue open to address that so let’s ignore that for the moment.

I do like the profile idea, at least as a stopgap until a particular binding can be fixed to either send the correct units, or be configured for flexible data to send the correct units.

Shameful plug here that technically JSR223 languages can be used to write profiles in 3.4 without having to wait for a new profile to be added to core. Using my own (as-of-yet-unreleased) version of the helper libraries with JRuby (see documentation at https://ccutrer.github.io/openhab-jrubyscripting/main/OpenHAB/DSL.html#profile-class_method), this could be implemented as:

profile :set_uom do |event, callback:, state: nil|
  next true unless event == :state_from_handler # only handle state updates from handlers
  next true unless state.is_a?(DecimalType) # if it sent a QuantityType, process as normal. Could also possibly process this to discard the unit, and re-interpret -- not convert -- as a different unit.

  callback.send_update(state | "°F") # forward the update, but as a QuantityType with unit °F
  false # let it know we already processed the event, and it doesn't need to be handled again
end
Number:Temperature MyTempWithNonUnitValueFromBindig "I prefer Celsius [%d °C]" { channel="something"[profile="ruby:set_uom"] }

It’s been working fantastically for me for at least a few months. It was definitely buggy in 3.2, and probably 3.3 as well. The whole MQTT-to-openHAB-then-exposed-via-HomeKit should work quite well with UoM in 3.4 now though.

:person_facepalming: there it is. Beautiful.

Simple - the Item state would assume the default unit for this Item.
(and so no conversion or scaling is ever done)

Follow-on - what is the default for this Item?
If present, derived from this Items ‘pattern’ currently.
If not present, use system-wide default for this type.
(This system default may be locale dependent e.g. C/F)
Prior to 3.4 - no system default for some types - indeterminate results.

Same case really (assuming valid units)
The updating value is auto-converted to this Items default unit before applying to Item state.
If the units are the same. its a “null” no-op conversion obviously.

See above for “what is this Items default unit”.

I think that’s all fine and needs no functional change.
3.4 has tidied away the one indeterminate case where there might be no default. Hurrah.

I am not at all convinced about this. The implication is that every Item state could only ever be expressed in that type’s default unit.

Let’s say the default for Number:Length is “m”.
My particle physics binding has a channel reporting in nanometres, “nm”
A value 5nm ends up in the Item as 0.000000005m
That’s technically correct, but looks rubbish.
That’s okay you say, use the ‘pattern’ to display in m!
My logs and rules are still full of the rubbish.
My chart scales look crap.
My rrd4j persistence is having increasing rounding errors dealing with those tiny numbers rather than 4 or 5

What I would like is to be able to specify a default unit on a per-Item basis.
This is already possible, hurrah! (and the priority about which to use is already established)

But
that per-Item default unit is derived from a purely display ‘pattern’. We’re breaking good design practice by making a presentation feature serve extra duty as a data design feature.
Does that matter?
Well, I cannot change my temperature display from C to F without trashing years of historic data recorded using that ‘pattern’ defined default.

What I’d like to see is a dedicated means to assign a default unit to individual Items, instead of deriving it fron presentation 'pattern.
With the metadata that was not available in OH2, this should not be too difficult now.

This can be implemented in a non-breaking way, in the algorithm that derives unit
first, use “new” definition
if none, use ‘pattern’ derived
if none, use system type default
At some later date (OH5) you could remove the legacy ‘pattern’ lookup.

The implication here is that you set the Item state unit in one place, which will govern its behaviour in logs/rules/persistence, anywhere that raw state is used - including binding channels.
That need not be the same as the UI presentation unit.
And neither are constrained to be the system default unit.

This would take care of people who may have extensive historic records in some non-system-default unit, because the Item’s default unit is what is used when retrieving.

3 Likes

Having a pattern for presentation separate from the item’s unit would also be useful for something have a large range of values - like power and energy (mW, W, kW; mWh, Wh, kWh, and up to MWh). I plan on writing a script transform at some point so that the display for such values auto-ranges to an appropriate unit. But I can’t do that if I need to use the pattern to convince openHAB of the proper unit I want values stored in.

2 Likes

I’m not sure the defaults are documented anywhere. It should be apparent though once you start using them.

There’s another untidy case that has been done away with too. Number Items will strip off the units if one is passed to them. So if it’s a plain number, it won’t magically start carrying units because some binding decided to publish units or the like.


dancing with the stars celebrity GIF

Because we know it’s going to happen. What if I want to use it in my system as one unit but display it in a different unit? I can’t imagine why someone would want that but I’m 100% sure someone will be mad because they can’t. They may just have accept their use case can’t be handled.

Or, since we are talking OH 4 and breaking changes are OK, drop the State Description pattern from the chain entirely and let the break happen. I think that would be cleaner overall. Why wait for OH 5?

There might be something else we can do to help with this, such as scripts to normalize the historic data and the like.

Note: I got a chance to set it and it does appear to work as expected when using the unit in the MQTT Channel config. I set °C as the unit and it converts it to °F on the Item which has %.0f °F for the State Description pattern. Woohoo! This is the only transformation I have in my system. :smiley: Unlike the rest of the world, I try to eliminate transformations and profiles instead of rules. :rofl:

1 Like

Not at all.
You don’t ever change the Number itself. You only change the representation for display,

I’m not getting why you would need this.
Note the default unit only applies once, initially, when you have no unit yet and assign a value but no unit through either a binding or a rule. Subsequent assignment without unit will reuse the item’s existing unit, NOT the default again.

Well, it also happens on persistence restore, but that’s a little bit different discussion.
For that I’ve agreed with @J-N-K to not put it into 3.4 but discuss in a separate issue first and introduce in OH4 as it comes with a breaking change.
I’m there asking to have a base unit for every type and every value would need to be converted to that base before storing it to persistence. That base unit is usually defined by physics. For your nm example the base would be m so the persistence value stored is 0.0000005.
For temperatures we would need to define it as either C or K I think.

Yes here there will be a one time breaker when you have been using and persisting a value as a non-base unit version such as nm or °F and now introduce a base m or K. That jump in scale cannot be avoided but that ONLY happens for persistence of non-base units and is no valid reason not to take this step forward.
You can convert your old data if you are so really keen on keeping and displaying it in one chart together with your new data.

But in all other cases, in rules you can convert as needed (.toUnit()) and afaik in charts, too, you can set the scale to whatever you want to see the chart in so it looks fine.

I think that a “UNIT” profile is very easy, it should

  • from handler to item: add the defined unit to the DecimalType, making it a QuantityType
  • from item to handler: convert the value (QuantityType to the defined unit and strip it (DecimalType)
1 Like

Heh. :slight_smile:

I try to eliminate transformations for core data paths, but am okay with them for display purposes (i.e. I use a string item to represent “A/V Source”, with value like “1.3” meaning “coming from room 1, input 3”. the transformation will translate into a human-readable value of “Living Room - SHIELD”).

I try to eliminate proxy items if they can be handled by some other native functionality, like proper UoM handling or profiles.

I tried to eliminate a profile usage (okay, I hadn’t even though of using profiles until later) to “veto” commands by using rules, but my PR got shot down ;).

1 Like

I’m afraid I do not believe that.
At the very least, retrieving persisted data currently depends on the default for that Item to reconstruct the quantity from numeric-only records.

But I don’t believe regular updates work like that either - state updates in arbitrary units are auto-converted to the Item’s given default. Try it, just postUpdate from a rule.

I don’t think that’s a good idea. While we would rarely find nm or light-years in home automation, we do find both km and mm.

What happens if someone moves, changes locale?

I do understand the whole persistence-with-UoM is a difficult business to resolve,

Real-life example of data source µg/m³ wildly different from quantity type default

You’re right, it applies the default (again). I misinterpreted a statement in the PR.

I created a Number:Length item mtest. No pattern, no stateDescription. 3.4 of course.

openhab> openhab:status mtest
NULL
openhab> openhab:send mtest 6
Command has been sent successfully.
openhab> openhab:status mtest
6 m
openhab> openhab:send mtest 6km
Command has been sent successfully.
openhab> openhab:status mtest
6 km
openhab> openhab:send mtest 7
Command has been sent successfully.
openhab> openhab:status mtest
7 m

As you see the applied default is m.
But as you also can see setting mtest to 7km does not set it to 7000m (that’s how I understood your statement you think it would).

So what? You can today and will continue to represent any km or mm value in m.

I don’t think you got the point of my proposal.
It’s just about the unit that is implicitly used for persistence storage. As units aren’t persisted we have to define the storage unit and apply it on restoration. If the current item unit is different, we need to convert the value accordingly before persisting it.
But my proposal does not change the item value, it just scales the value to match the base unit and that value then is written to persistence.
Read on conversion to base unit on persisting · Issue #3167 · openhab/openhab-core · GitHub
The recent change will ensure that on restore, any item will get the default unit assigned right away.

The base unit is defined by physics, and it is independent of locale. If you globally change locale or pattern per item neither will change the value, only the display.

1 Like

I stand corrected then, I think this has changed.

That kind of blows up Rich’s use-case, where a sensor reports say in F and he’d like the Item in C.
Can’t be done, you must have the state update in F regardless of default, though you can choose to display in C

This isn’t some artefact of sending a command and relying on Autoupdate to generate state, is it?

Makes you wonder why have km or mm at all …

I’ve tried to suggest that various sub-systems, like persistence, will give slightly different rounding errors with data 0.00000005m and data 5um.

Speculation only, ‘simple’ charts become harder to configure with sensible scales.

It just feels like a bad idea. I do appreciate it looks like a solution to a difficult problem, I do not think it is good enough though.

So there won’t be locale dependent C/F anymore?

Or you’re talking a system type default and another base type default below that?

1 Like

That’s probably a bug

If you read the docs it exactly describes Rich’s use case and that it can be done with UOM:

A weather binding which reads temperature values in °C would use the QuantityType to 
indicate the unit as °C. The framework is then able to convert the values 
to either °F or Kelvin according to the configuration of the system. 

And it works:
item:

Number:Temperature    TestTemp     "Temperature [%.1f °C]"   

grafik


This is the only useful application of the whole UOM system:
Implicit state transformations from one unit to the other without having to manually do all the calculations.

FWIW let’s change from a technical perspective to a more functional description on how users would like to have their UoM handled?
I’ll start:

  1. I’m fine with having a default UoM per itemType

  2. I must be able to define the actual UoM of a device’s data per item

  3. I must be able to define a per presentation UoM in case I want to do some fancy sh… with graphs or sitemaps or whatever.
    ** If I don’t define a UoM on my presentation layer (sitemap, UI, whatever) I’ll also get a default presentation UoM (I’m fine with having that attached to the actual UoM of the item)
    ** If I do define a UoM for my presentation layer I can do so somehow within that layer or OH let’s me define UoM for API, dashboard, sitemap, …

  4. I must be able to know exactly the unit the item persistence UoM will be, perhaps this is the actual UoM or it is also configurable

  5. on a different note: it must be well documented, how all that works, where to find/see default UoMs and how to use UoM in rules. Right now this info is clattered across the forum, some docs and perhaps some github discussions?

forgot something?

My 2cents on edge cases like “someone’s moving to different locale” or “suddenly I’m using another UoM for my item and my persistence gets messed up” shouldn’t be of concern. They can be adressed by those who like accordingly with some effort, but shouldn’t be part of the actual requirements here.

Actually it’s even easier since we are talking only UoM about items here.
We agree on almost almost everything but I’m trying to rephrase so it’s (imho) easier

Each UoM item has a unit (that’s why it’s a UoM item)

  • The unit can be set per item (optional)
  • The unit of the graphical representation can be set per item (optional)
  • The unit of the graphical representation doesn’t have any other impacts
  • The persisted value is always the value of the item (in the unit of the item)

With these rules we get the following:

  • If no unit is explicitly supplied a default is picked
  • If no unit for graphical representation is supplied a default is picked
  • It’s possible to have persisted values in the (for the user) correct unit, e.g. I can persist values in °F or km/h even though the system default is different

It’ll even cover one of your corner cases (“I’m moving to a different locale”) because the unit of the item can be explicitly set to the unit before the locale change.

Another point (not sure if it’s better to start a new thread for this): If using UoM Items to get historical data (lets say a graph of energy consumption) and changing the Item e.g. to use kWh instead of Wh, this will result in a skip of factor 1000. So the line drops to the new level and old values are wrong of factor 1000.