UoM default units and consequences

Then you should probably read the docs again:

The default conversion the framework will use is locale-based: 
The framework tries to convert a QuantityType to the default unit of the
configured locale. 
...
The metric system with SI units is used for the rest of the world.

And below the default for Length:
grafik

So it actually should convert 1km to 1000m

That docs quote is older than the recent change. And it’s just docs, not the spec, so it can be wrong without that the implementation is buggy.
At least it leaves room to interpretation.
It’s not the same kind of “default unit” what these docs and what we are talking about.
km and m have the same default unit, m that is - the k in km is just a scale prefix.
The “default unit of the configured locale” is something else, like C vs F or km vs mi.
I’d expect an item with a m value to display in miles or feet or whatever that default is if I switched to US locale.

For persistence - don’t care.
EDIT as this seems miscontrued. For persistence data - don’t care what form the openHAB internal data is in, it is how the database stores it (which will not be BigDecimal)
How the service stores its data is the part that counts.

You understand that people do retrieve stored data for other purposes, usage calculations etc.

Okay. I think I’m a bit confused about your proposal.
Is it -

All database storage will be in some pre-designated normalized unit for each type.
e.g. a Length will always be stored in m (nanometres and light-years will be converted)

Upon retrieval, the value will be converted to whatever this Item’s default is. (Hard luck with rounding errors from double conversion and scale limitations)

Woahh that’s really screwy.
If you post 1mm or 10km to a default Length you get 1mm or 10km - unit preserved
If you post 0.6mile to the same Item you get 985m - unit converted.

I would not call that expected behaviour.

Is this where it gets complicated and for default purposes we do not consider k, u etc, suffixes - km and mm are all “m default”? Hows that work with feet and inches?

What I expect openHAB to do was summed up by Rich the other day

UoM active at item

  • sending unitless values => that value with the active UoM
  • sending same unit values => that value with the active UoM
  • sending different unit values => value gets converted before reaching the item and is stored with the active UoM

dimensionless item

  • sending unitless values => that value
  • sending unit values => unit will be discarded, only value will be stored at item

What I do not expect: sending an unit different vom active UoM at the item: the item suddenly changes it’s active UoM.

So, the above example von Markus should qualify as a bug to me as the Number:Length item assumes a dimension from updating its value - I don’t want that.

I care! :wink:
And I think most users will. Because default persistence is rrd4j. That will work horrendously with nm stored in m. even storing mm (rain/snow precipitation standard) will not work out very well with m.

The active UoM should be stored - as it is already. (and the UoM must not change by sending another unit!)

I think the crucial point is that with a a UoM of “meters” one would expect that commands with a different scaling (“kilometeres”) is scaled appropriate.
Instead the scaling on the item changes which is very confusing.

This will also result in jumping values in the persistence service, e.g.
if a distance counter with a value of 999m increases and now is 1km.
Persistence:

Value X-1: 999
Value   X: 1

I would.
I used a DE locale. I’d guess on a US locale it would remain in miles.

See Add default units for all dimensions by J-N-K · Pull Request #3143 · openhab/openhab-core · GitHub

So the ‘default unit’ we have introduced in turn depends on locale, but just in some cases.
Boy are we liberal. Knowing that “the” original length and temp units are “meter” and “Celsius” (or “Kelvin)” and those are what Europeans still use, we even bend physics just for our U.S. friends :slight_smile:

No. BigDecimal will determine how large the rounding error is when a non-default-unit value (nm) is scaled to the base unit (m) before it persists that value (and persisting should not modify that any more, or at least not any different from what was implemented so far).

Hard claim, any proof ? As said the internal precision is very high and the number of conversions very much limited, plus nm are edge cases. No as I already responded to rossko that’s just FUD.

The bottom line is that we all would like to have the optimum solution which stores the unit in persistence, too.
BUT that would be a HUGE task to properly implement, affecting many interfaces, bindings and breaking lots of things along the way. This is why noone is daring to try.
Hence my proposal as it’s a lot less impacting/breaking change.

To repeat in complete context

Sometimes it normalizes the data, sometimes it doesn’t. I still would not expect that.
This is going to evolve into a discussion of specifying a default like “km” will only be taken into account so far as the “m” part goes.
Is there both a default measurement system (locale) and a separate default unit? What happens if we cross the streams!?

no proof as I don’t store a value with the only change in the tenth decimal in rrd (who would anyways?). But the way, rrd stores and rounds its data over time, there will be significant rounding problems with such values.

I don’t get, how it will be such a HUGE task. The actual behaviour (as of 3.3 - I’m not on 3.4 atm) is the one, which is a) simple and b) easy to understand for the user: the actual UoM of an item is the one, which gets persisted. end of story. => and that’s why it’s not expected behaviour for me, if an item changes its UoM just by sending a different unit with a value update.

I do, it IS a monster to co-erce units onto purely numeric storage.

Please see my explanation here regarding when and how units are handled.

2 Likes

I can imagine. But you don’t have to co-erce anything - just store the item’s value from its actual UoM at the time of persistence. I don’t expect persistence to calculate historic values, if I change the UoM later on. If I do I certainly can update the historic values myself in parallel as I change the UoM. (given, my persistence allows me to do that)

So you write in 2.

  1. A binding provides a value including unit (e.g. Netatmo) and is linked to a dimension item. We don’t need a default unit here. If the measurement system is different (e.g. your locale provides m but the value is ft), then the value is converted to the unit of you locale. If the unit is in the same measurement system, then nothing is converted (e.g. m and km).

does that mean - regardless, what I configure at item state, the default Unit of the itemType is used for persistence?
That would be a widely breaking change for me and nearly all of my items will return the “wrong” historic units. I nearly never stored items in the default ItemType’s dimension. e.g. all my weather data is stored in “mm” - but now it would be “m”…

Let me throw a monkey wrench into an already heated discussion: Convert units for bounds when compiling full state descriptions by ccutrer · Pull Request #3132 · openhab/openhab-core · GitHub

Basically, what I’m addressing there is that the binding provides a state description that says “this channel is in °C, and has a range of 20-40°C. Then my item has a unit of °F cause I’m a weirdo that lives in the US. The HomeKit addon automatically searches state descriptions for min and max values. But for temperatures, everything is in °C. So if a user configured “state description: °F, min 68, max 104”, HomeKit would happily present 20-40 by converting the state description values to C as well. This PR is the missing link so that the user doesn’t have to explicitly provide min/max if the binding provides them - in a different unit.

But in runs into issues - what happens if an item is linked to multiple channels that provide state descriptions? And this is where it gets relevant to the current discussion - what’s a number item’s unit if the user hasn’t specified one, but is linked to (multiple) channels that provides state descriptions with conflicting units?

1 Like

Just as a real-life example of scaling range for discussion, we have users with car integration and weather stations. Speed quantities used range from roadspeed in tens of km/h to rainfall in mm/h.

I imagine ‘normalized’ Speed storage would be in m/s.
I think that’s going to produce some really tiny numbers for rainfall?

Don’t run too many circles, it’s not that complex.
It does not normalize, never. It only converts imperial ↔ metric. When you force doing so like I did by sending miles to a metric type item, it uses the default unit (meter) of the target system even if the source value (miles) wasn’t using the default for that source system (= feet).

I’ve seen this issue earlier and went with profile which can control quantity passed to/from item after it leaves binding. It still does not solve problem of persistence services which can’t determine what would be base unit for some cases.

Wow, go to a movie with the family and get a night’s sleep and this thread exploded!

You keep saying this but I’m not sure I completely agree. Most measurement units are relatively arbitrary. Somewhat recently a number of SI units were retconed to be based on physics, but they are still arbitrary. There is nothing in the universe that says a meter must be exactly the distance light travels in a vacuum in 1/299792458 seconds. Why 1/299792458 seconds? Because that’s pretty much exactly the length of a meter prior to it’s redefinition.

So no, the units are not defined by physics. They are defined by convention. Most of the world exclusively uses SI units. Some parts of the world mostly use imperial units (which have not ben retconed and are still based on historic conventions) and some parts of the world that use SI units for some things and imperial units for other things.

I agree with @rossko57, it is not cut and dry.

That’s what I thought too, and it’d still be a problem if the binding doesn’t support units. But in the case where the binding does support units it is converting the °C to *F as expected. Even the charts are correct. To be specific,

  1. A plain number representing °C is published to an MQTT topic.
  2. I set the MQTT Channel’s unit property to “°C”
  3. I set the pattern in the State Description to “%.0f °F”

The value is converted from °C to °F and displayed with °F.

This is a bit of a concern of mine as well. But I haven’t sat down yet to think through whether or not this is a really big deal or not. My initial concern was repeated conversions between units on every restoreOnStartup which could result in the value drifting but I don’t think that will be the problem. At max only one conversion should occur on that initial save.

My understanding is:

  1. there is a default unit for every Number:X type Item
  2. that default unit is based on the locale (if you are in most of the world it means you’ll get SI units as the default, in the US and a few other places it means Imperial Units)
  3. when a value is persisted, no matter what units the Item is carrying, it will be converted to the default units for that Number:X type
  4. when restored, the Item’s state will carry that default unit, not what ever unit it had originally nor the unit defined by the state description
  5. however, you can change the way it appears with the state description pattern per usual and you can use toUnit() on the QuantityType to convert it to a desired unit in a rule

That’s the way it’s always worked before.

I’m not so sure it always works that way now though. For instance, if it still worked that way all the time, what’s converting my temperature Item to °F? I have confirmed that persistence is saving the converted value.

The binding is delivering to the Item °C. Maybe temperature works different from length?

I wouldn’t put too much weight on the docs right now. I’m not sure we ever really understood UoM well enough to make the docs correct in the first place and they haven’t been updated since these latest changes.

Not in rrd4j.

This is a good argument for normalizing the values to the same unit before persisting.

But what’s the precision of the database?

I can’t remember, it’s either feet or yards. A mile is closer in scale to the sorts of things you would measure with km. I tried to suggest defaults for the imperial units that were close in scale to the SI unit defaults.

It probably doesn’t. But a lot of systems will punt and just represent decimal fractions instead of inches and fractions of an inch. So you’d get something like 25.5 ft instead of 25 ft 6 in. Though it’d be pretty awesome if it did it right.

That’s not what @rossko57 means. What he meant is that the precision and range of BigDecimal doesn’t matter because the range and precision of the database itself is going to be less.

It depends. BigDecimal gets its range and precision by using an alternative to IEEE-754. But pretty much all databased I’m aware of use IEEE-754 to represent floating point numbers. So myBigDecimal.toFloat() or toDouble() gets called to convert from the internal BigDecimal format to IEEE-754 which is limited in precision in strange and interesting ways.

If it were feasible at all I would push for that approach. But as long as we support rrd4j storing the units with the values is simply not feasible.

This! I hate inconsistency more than anything. The behavior of UoM seems to be inconsistent. There may be good reasons but I think we need to look through the code and set up experiments to exactly nail down the current behavior and then move on to what the behavior should be.

It would touch pretty much everything, core, add-ons, and require a pretty significant rework on charting in MainUI.

It may be heated but, at least for now, I think it’s been productive.

However, if this starts to spin out of control with no progress, I’ll close it down. We’ve had threads run out of control before and caused harm to the community. I don’t want to let that happen again.

3 Likes

Okeydoke. So when a weather binding posts mph windspeed to a Speed Item it will end up as m/s or something, but you will be able to get that converted back for GUI display, and (by some mechanism I don’t understand) for charts.
All the persisted data will be in m/s but again you can convert back in rules using .toUnit()

The same binding posting mm/h rainfall to a Speed will get mm/h.
But it’ll be persisted as m/s.

Am I getting close?