Any UoM item has a default unit but that default you cannot change, so you have to apply displayState pattern to override wherever you want to get to see it converted into a specific unit or with specific formatting.
In groups you cannot aggregate items of differing type or UoM.
One is speed, the other is intensity. No that’s different even when the physical measurement units match so there is no conversion code available.
No, it also gets taken into account for Units defaults. I think it was already conveniently there before UoM were added, and they didn’t want to add yet another new Item property.
If you post a numeric-only value to a Quantity type Item, the unit in ‘pattern’ will be added on.
However, I’d missed you were talking Group. You cannot post anything to Group state, it relies on the aggregation function. So the idea of a default unit is sort of moot - like the state, it should be derived from member Items.
I’m not convinced that works at all, though.
What problem is this giving you? In most cases it doesn’t matter what unit a value stored with in Item state, as it’seasy to control how it gets presented for display or use in rules.
Well, perhaps we should clarify if the Group and its members are different types? They’re all Number:Speed, right?
For something like a SUM, picking the “right” unit is non-trivial. It would be legitimate to SUM mph and m/s, but how should the result be expressed? I think deriving result units from members is a no-go.
In a rule, you’ve got options to control all this - but not in a SUM aggregation, unless more parameters are invented (which seems unlikely to gain support).
So that leaves UoM defaults.
Some (not all) Quantity types get a system default unit, controlled by metric/imperial locale setting.
I think Speed is one that does and is the source of the km/h here.
For ordinary Items, you can override default (or add one for non-system-default types) by giving a unit in the Item pattern metadata.
That relies on the OH framework using it.
If that is not working for a Group type, or rather not working in aggregation maths functions, it would be a sensible enhancement to make it so.
But again, what is the actual problem here, since whatever the state is can be converted for display to any unit?
I can see persistence/charting might be an issue.
Not really unless you explicitly configure them to be that, yes.
See Units Of Measurement | openHAB : rain intensity mm/h is actually the same what is also measured as l/min (or l/h) i.e. a VolumetricFlowRate, not Speed.
Btw: you can deploy a proxy item of Number:Speed type and update it on any rain intensity change then group aggregration should work if all members are of this type. Not sure if aggregation works for UoM at all, though.
When using units, state consists of a number, a space and a unit, neatly rendered in a string.
If the Group aggregation uses a different unit than the aggregated Items, then we end up comparing apples and oranges as you cannot safely assume that the same units will be used. For instance when rendering the rain forecast items as progress bars with a value scaled to the aggregated item.
In this particular case, it is very hard to design a custom widget in Main UI for instance, since whenever a state with unit is returned, it must first be normalised with respect to the units used.
So items.itemName.state would be hard to work with since we don’t control the units used when itemName represents a Group item with an aggregation function.
Ideally there would be a means to get a state in a specific unit, e.g. by means of toUnit(‘mm/h’). Probably we can’t rely on using org.eclipse.smarthome.core.library.unit.SIUnits for non-SI units (e.g., mm/h). Or we have a means to define units similar to what exists in BIM IFC where units can be ‘assembled’ by providing base units, their multipliers and a power, as in:
convert m to mm means: divide by 1000
convert seconds to hours means: divide by 3600; ‘per second’ hence power is -1
There is: the display pattern is. Put the default you want to be used into the metadata pattern of the item. Note you can also override/specify that in the widget YAML code.
Put mm/h or l/min in the pattern to see.
A caution here; we still haven’t found out if your Group Item has a “subtype” of Number:Speed.
This is important if you try to retrieve state in UI by specifying units in ‘pattern’ I.e. it doesn’t do conversions unless you get this right.
It should though and if it’s not then that needs to be fixed. I can report that MIN and MAX does indeed work with Dimensionless %%. I don’t use any SUM or AVG aggregations though. I’ll give that a try when I have a chance. But I don’t have any State Description metadata for this Item and it applies the %% automatically based on the units of the members. However, that’s a selection and not a calculation so it probably just inherits the units of that state as is. SUM and AVG is more complicated.
That’s not the case. The whole point of UoM is that if you add an Item with km/h to an Item with cm/h or even inph the whole UoM framework will do that normalization for you so it’s adding apples to apples. The answer will be correct, but the units may not be what you want. The State Description Pattern is supposed to work to convert that to the unit you actually want.
Here is one place where OH is deficient over all. Persistence doesn’t know anything about UoM yet (unless I missed a PR). So if the actual value stored in an Item is km/h, it’s that number that will be saved to the database without the units. And it’s that value that will be charted. The Pattern Item metadata is used when restoring the value from Persistence at restoreOnStartup but it is not used by Persistence and therefore not used by charting.
You can do that in a rule. The State Pattern metadata is supposed to do that everywhere else.
(MyItem.state as QuantityType).toUnit("mm/h")
That’s already supported. See the bottom of the UoM page Markus linked to.
Let’s write up a summary for clarity.
In the table of units shown on the UoM page, all the units with the same value in the first column of the table are compatible with each other (e.g. there are three compatible Speed units, <Imperial Length>p<time>, <SI Length>/<time> and knots). You can do math with any two numbers so long as they have compatible units. So you could add an Item with mph to one with m/s and add that to one with kn and the result will be the correct answer. However, the units of the result is . That part isn’t well documented.
All the SI Lengths support all the standard metric prefixes. So you can use mm for millimeters. The first m is the prefix and the second m is the length meter.
There are 6 units of time. It looks like seconds s is the smallest supported unit.
Given the above it shouldn’t matter what units the members of the Group are so long as they are all in a Speed unit which has 163 different combinations of length, prefix, and time units plus knots. You can do math between numbers using any two of those 163 combinations. They do not need to match. So you can compare km/h to mps and get the correct answer.
The default unit used by an Item is defined by it’s State Description Item Metadata (add metadata from that Item’s settings page in MainUI and set the Pattern field the same as you would do for a label on the sitemap).
Given that, what should happen is after summing all the members of the Group, the units of the result should match the units defined in the State Description Item metadata. That needs verification and if it doesn’t happen an issue should be filed.
To my knowledge there is no way to set the Group subtype through Main UI; you can only assign it by pasting an openHAB2-style Item definition (using the appropriate tags). For Items, it’s a trivial thing to do.
Here’s the “state description” metadata configuration:
I know I can get the ‘formatted’ state through items.itemName.displayState but this again implies prior/implicit knowledge of the units when parsing the state in YAML (e.g., by using Number.parseFloat() or by splitting the state at the first white space character.
Indeed. That’s a powerful feature of openHAB when using QuantityType as it offers convenient mappings.
I indeed noticed this. Fortunately this can relatively easily be implemented by normalising UoM-based state values to a specific convention (either fixed by design, or configurable as is the case today), possibly enriching the state with a scaling factor or unit identifier as a 2nd column. It would be a big improvement in managing persistence in a future major release.
Why this hasn’t been implemented, may be for sake of preserving whatever state information unaltered. Converting floating point values will introduce loss of precision errors which may (or may not) be sufficiently significant.
I use this extremely useful pattern extensively in my own rules. Unfortunately it’s not available (yet) in YAML widgets, but it reflects my exploration of the new possibilities offered by openHAB 3. Hence: what if it were available universally (also in YAML widget definitions)?
For Items, this is indeed how I see it work.
For Groups, I have the impression that the SUM aggregation defaults to one particular unit that represents the “Group subtype” which is inferred from the Member Item’s subtype (e.g. Number:Speed). I can understand the rationale behind this decision: as long as the units are compatible, avoid the hassle of determining the ‘expected’ UoM by defaulting to ‘the’ measurement’s system default (‘km/h’ for Number:Speed on a metric openHAB installation). In the same logic I expect AVERAGE to show the same behaviour. However I expect MIN and MAX aggregation to return the UoM of the matching item’s state as only 1 (existing) state value is returned.
I suppose that exposing more UoM functionality (e.g., in YAML UI components and in persistence/charting) will be something for openHAB 4 or later
I think perhaps that is present but mislabelled as “Members Base Type”. It’s legitimate to have mixed types as members of a Group, so the label is a bit of a nonsense really.
If in doubt, it will be plain in the API Explorer JSON version.
Well, it is serving the state quantity wit the units (and precision) that you requested in your Item setup, it’s not random.
I suppose what’s missing is the ability to choose units at the UI design. You could do that in an old fashioned sitemap with label="blah [state presentation]" and get a quantity conversion to the UI specification, regardless of Item definition.
UoM is wholly implemented by Java. It is not and will never be available in the browser. That’s what displayState is for. It’s all executed on the OH server but all the widget stuff is executed in the browser.
Also, UoM is not new in OH 3. It’s be around since OH 2.2 if I remember correctly. Maybe OH 2.4.
Based on your screen shot above you have explicitly configured the Group to be of type Number:Speed.
It’s an open question as to what would happen if the members of the Group were a mix of incompatible units (e.g. some Number:Speed and Number:Temperature for example). I suspect we’ll see errors in the log because you cannot add a Speed to a Temperature. But that’s not the case here. Both the Group is a Number:Speed and all of its members are Number:Speed.
For all intents and purposes all Number:Speeds are the same base unit. Where there are differences are when we use the value (displayed in a Widget, displayed on the sitemap, saved in the database, used in a rule). So, because both the Group and the members are all Number:Speed, the SUM aggregation function doesn’t explode in errors but calculates a real sum.
By default, when given no other influence, a Number:Speed Item will use meters for those using SI and inches for those using Imperial (based on the choice in Regional Settings). But that’s not the case here.
When doing math with UoM I don’t know how it chooses the units of the result. Most of the time it doesn’t matter really because everywhere you would use the state you can specify the units you want to see it in. Even in widgets.
Where there is an inconsistency is the behavior between regular Items and Group Items. Regular Items appear to use the state description pattern as the default units to store the state (maybe, that needs to be verified, maybe it’s only showing you the state as mm/p because of something from the binding or from the state description but it’s really storing the value as km/h).
If this is indeed inconsistent, I’ll say it again, an issue needs to be filed.
The formatted state through displayState is exactly how you are supposed to specify the units you want to display that Item’s state in MainUI. I fail to see the problem here I guess. You know the Item is a Number:Speed. You know the members of the Group are also Number:Speed. You know that the speeds are small. So you know everything you need to know to specify that you want to show the speed as mm/h which you specify using the state description and using the displayState in the YAML for the widget. That’s what the displayState is there for; to specify how you want that Item’s state to be displayed up to and including which units to display it as.
It’s simply not technically feasible. But what would that do for you that the displayState doesn’t already?
I’m sure Yannick will consider an alternative if a better one is presented. I can’t come up with anything that is any better. It’s a hard thing to distill down to a simple label.
That’s exactly what the “state description” metadata pattern does and to access that choice use displayState instead of state. That ability is already there and it’s available in the widget anywhere you can access the Item’s state in the widget definition.
But it’s tied to the Item, once and forever. In a sitemap, you can display e.g. a single temperature quantity in three different units by use of label= overriding what the Item says. It’s under the control of the UI designer, separating Item property from display presentation.