Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UoM] Change Dimensionless default unit to percent #4078

Closed
wants to merge 1 commit into from

Conversation

mherwege
Copy link
Contributor

@mherwege mherwege commented Feb 2, 2024

Closes #4077

There has been a lot of debate and confusion about the default unit for QuantityType. There is some consensus that the most used case for Dimensionless is percent, and therefore it would make more sense to have this as the default unit.

This PR is breaking as anyone that is using the current default Unit.ONE in persistence will see there persisted data scale. It will require manually changing the unit for this item to Unit.ONE. The expectation is there are very few cases where Unit.ONE is the right unit.

@mherwege mherwege requested a review from a team as a code owner February 2, 2024 16:07
@J-N-K
Copy link
Member

J-N-K commented Feb 2, 2024

You may be able to convince me that my position is wrong, until then I put a veto on this one.

Changing the default unit of a dimension is a breaking change which may result in big issues in a lot of systems, especially when it comes to such a fundamental one like Dimensionless. Please see the discussion in #3552 for a change that only affected users of the imperial system and a far less used dimension (Length).

I fail to the the big benefit to change the default unit which has been ONE since the introduction of UoM in eclipse-archived/smarthome#4818 back in 2018.

@rkoshak
Copy link

rkoshak commented Feb 2, 2024

I could go on but you get the point. This is the #1 most common problem I deal with on the forum since OH 4 was released.

And while it's a breaking change, ONE is the least useful and used unit in Number:Dimensionless. It's a really bad default. I don't know how to properly structure a search but as far as I can tell, there are no bindings that publish anything in ONE. The vast majority are publishing % with a few ppm and db here and there based on what I could find with my limited search skills.

And the problem is particularly confusing to end users because of the way bindings can pass state description with a unit for display. These users end up having a Number:Dimensionless that appears to be a % everywhere they look until they try to use it in a Chart or use the battery level icon or something. Then all of a sudden the value is two orders of magnitude off and they have no idea why. (Number:Dimensionless isn't the only unit that has this problem BTW).

It may have been the default since UoM was first introduced, but with the changes to UoM in OH 4 we introduced a new interaction between the state description and the Item state which is causing no end of problems and confusion to users. Previously, because the State Description was used as the unit.

In #3854 binding developers are advocating for introducing a whole new mechanism to bindings to provide hints for what unit to use by default. But the main thing driving them to this is %.

For the sake of end users I think we have three choices:

  1. make Number:Dimensionless default to %, by far the most used unit
  2. allow bindings to provide a unit hint so when the Item is linked a reasonable unit is chosen
  3. no longer allow bindings to push state description patterns to the Item

If you veto 1, then I suggest 3 is the only reasonable option, even though it will result in a lot of disruption to binding developers and end users. 2 has already been vetoed and I'm not actually sure it's a viable option anyway, but it's the only way to address this problem in a non-breaking way.

The big thing that makes this distinct from #3552 is I would be surprised if there are more than a dozen users among all OH users who are using ONE on purpose.

@J-N-K
Copy link
Member

J-N-K commented Feb 2, 2024

I like 2, as long as it is a suggestion. Users can decide to follow that (for new items) or not. It doesn't break anything, already existing installations are not affected.

I think "automatically set the unit metadata when a link is created" as a core-feature is wrong, it breaks the separation of things and items.

@spacemanspiff2007
Copy link
Contributor

It would be very unexpected if Number:Dimensionless would default to percent so I'm against this, too.
I'll throw in a 4th option which would be a new type Number:Percent. Even if it's no unit per se its so commonly used that it would justify an own type. This new type would default to Number:Dimensionless with metadata unit=% forced.

@rkoshak
Copy link

rkoshak commented Feb 2, 2024

I like 2, as long as it is a suggestion. Users can decide to follow that (for new items) or not. It doesn't break anything, already existing installations are not affected.

What's important is this has to be what gets applied to the Item if the user takes no action. It becomes the default, which was expressly rejected previously.

If it's just a suggestion that, if ignored, causes ONE to be the default, we haven't actually addressed the problem. We've just added more stuff that the user ends up right back where they are now with an Item they expected to be and has always been a % but is now a ONE.

However, it could be implemented at the MainUI level. MainUI already shows the default unit when creating the Item and offers a chance to change that unit prior to creating the Item. If that default becomes whatever the binding is pushing and that default results in unit metadata being created whether it was changed or not, from the end user's perspective that would work I think. All new Items would end up with unit metadata based on their choices or failure to make choices when creating the Item.

This didn't used to be a problem because the binding essentially got to set the unit. It's a problem now because we expressly forbid the binding from setting the unit, but still let them change how the Item's state appears.

I think "automatically set the unit metadata when a link is created" as a core-feature is wrong, it breaks the separation of things and items.

I agree. I've disliked this for a long time. But that's how State Description works now. Seems like that would be an even bigger breaking change than changing the default unit of Number:Dimensionless. It definitely would be more disruptive.

It would be very unexpected if Number:Dimensionless would default to percent so I'm against this, too.

And it's equally unexpected for these users who have always had Number:Dimensionless Items which were "defaulting" to % because of the State Description Pattern pushed by the binding but now their Item's state is ONE. Only it's even more than unexpected, it's inexplicable, since by all appearances the Item still is a % because of that State Description Pattern, it's just not behaving like one.

@mherwege
Copy link
Contributor Author

mherwege commented Feb 2, 2024

I very much understand the concern with this PR. But I don’t see a perfect solution. Implementing 2 provides a solution for new items defined from thing channels through mainUI. It does not help for users migrating from a previous version, or users using textual configuration.

@jlaur
Copy link
Contributor

jlaur commented Feb 2, 2024

However, it could be implemented at the MainUI level. MainUI already shows the default unit when creating the Item and offers a chance to change that unit prior to creating the Item. If that default becomes whatever the binding is pushing and that default results in unit metadata being created whether it was changed or not, from the end user's perspective that would work I think. All new Items would end up with unit metadata based on their choices or failure to make choices when creating the Item.

This is exactly what I proposed in #3854.

@spacemanspiff2007
Copy link
Contributor

And it's equally unexpected for these users who have always had Number:Dimensionless Items which were "defaulting" to % because of the State Description Pattern pushed by the binding but now their Item's state is ONE. Only it's even more than unexpected, it's inexplicable, since by all appearances the Item still is a % because of that State Description Pattern, it's just not behaving like one.

But that's a migration issue, if we set the default to % it'll be a logical flaw because the default of dimensionless is not %.
I don't want to downplay the confusion and the issues users are facing but the solution can't be to introduce something that is logically flawed.

Imho the root cause is that the users don't have a unit set for a UoM item so that's what we should address.
Why not log a warning/info on startup/when *.items file is loaded that there is a UoM item without metadata unit?
There's a good chance that it might not behave like the user intended so it always makes sense to explicitly pin the unit.
HABApp already does this and I've got no complains from the user.
If you pick a UoM item, you have to pick a unit. That's a simple rule that everyone can understand.

The other issue is a usability issue.
Users have pick Number:Dimensionless and additionally set unit=%.
Percentage values are prevalent, so it makes sense to provide a shortcut.
I've suggested Number:Percent which will pin unit=% without further user interaction.

These are very small changes which should sufficiently address the issue.

Currently the UI already suggests a unit so I don't think we gain much if we introduce a way for the binding to suggest the unit.
The user already has to select the correct unit for the item type when creating the item so he can make a click more to select the appropriate unit (if he wants a different one).
I don't think it's worth the added complexity at all to make the bindings suggest something (which will probably work only in < 80% of the cases anyway and/or just for simple things).

@andrewfg
Copy link
Contributor

andrewfg commented Feb 3, 2024

FWIW I was wondering what could be the scale of this issue, so I did some grepping on the add-ons source code..

  • there are ca. 20 bindings containing the string Units.ONE in .java files
  • there are ca. 111 bindings containing the string Units.PERCENT in .java files
  • there are ca. 115 bindings containing the string Number:Dimensionless in thing .xml files

There are probably a few more add-ons (like tado) which don't (yet) return any kind of QuantityType .. but which should probably do so..

EDIT: obviously the Venn diagram intersection of the number of entries in above bullet points is clearly far less than their simple sum..

@andrewfg
Copy link
Contributor

andrewfg commented Feb 3, 2024

Why not log a warning/info on startup/when *.items file is loaded that there is a UoM item without metadata unit?

+1

If you pick a UoM item, you have to pick a unit. That's a simple rule that everyone can understand.

+1

Percentage values are prevalent, so it makes sense to provide a shortcut.
I've suggested Number:Percent which will pin unit=% without further user interaction.

+1

@mherwege
Copy link
Contributor Author

mherwege commented Feb 3, 2024

But that's a migration issue, if we set the default to % it'll be a logical flaw because the default of dimensionless is not %.

That is arbitrary (just like in OH km/h is the default for speed, while the base unit in physics would be m/s).

I agree with the principal of always having to set a unit when creating a QuantityType item. I also agree with logging if it is not defined in textual configurations (+ documenting it should always be defined).

I don’t think creating artificial dimensions (percent) is the way to go though. I understand why you would want it. However, it makes conversion to Units.ONE impossible (express percent as ratio), and it means all bindings using Dimensionless to express percent should be changed (over 100). You could in theory leave it, but it creates another way to express the same thing. I see a major issue with backward compatibility also.

If not changing the default unit (and I understand why one would not want to do it), I do think the unit-hint concept could play a role in the UI to present the most meaningful unit, and bindings could provide that. I don’t see a way to do that without extending the channel or channel type configurations though.

@spacemanspiff2007
Copy link
Contributor

I don’t think creating artificial dimensions (percent) is the way to go though. I understand why you would want it. However, it makes conversion to Units.ONE impossible (express percent as ratio), and it means all bindings using Dimensionless to express percent should be changed (over 100). You could in theory leave it, but it creates another way to express the same thing. I see a major issue with backward compatibility also.

Just in case you misunderstand my intention I'd like to clarify:
The idea is that Number:Percent will create Number:Dimensionlesswith unit forced to %.
This would be a fully backwards compatible change, think of it as a shortcut for the user.

@mherwege
Copy link
Contributor Author

mherwege commented Feb 3, 2024

The idea is that Number:Percent will create Number:Dimensionlesswith unit forced to %.

So, it would only live in mainUI? Textual configuration would always have to be Number:Dimensionless? And once created it will show as Number:Dimensionless. I could see that working, but expect questions like it doesn’t save the Number:Percent setting. And how do we make the UI propose Number:Percent in the first place when creating an item from a channel? I fear we are back to the unit-hint concept, or introducing dimension synonyms.

@jlaur
Copy link
Contributor

jlaur commented Feb 3, 2024

Why not log a warning/info on startup/when *.items file is loaded that there is a UoM item without metadata unit?

What is the difference between missing unit metadata on a managed item and an item defined in an .items file, i.e. why would you only log this for file-based configuration?

I primarily use file-based configuration and have some UoM items without explicitly provided unit metadata. Since unit metadata is optional, I would find it quite annoying to have anything logged because of this. For example, I have items of type Number:Time which I don't persist, and where default unit is fine since I don't care about the internal representation. I already have state descriptions etc. in place where I want to control the appearance (e.g. time remaining for a media player in a sitemap).

I also have Number:EnergyPrice items without a unit provided. In 4.2 with a currency provider, providing a unit could cause conversions between currencies using an online service. In some cases this is desired, but I could also imagine a few scenarios where this might not be, and the lack of unit metadata could be some safe-guard to not silently ignore a currency mismatch in the configuration (i.e. between a Thing configuration and linked item).

Also, wouldn't the somehow degrade the regional settings/measurement system? Currently you can have unpersisted items without unit provided, and I believe the configured measurement system will then be taken into consideration when determining default unit? So you can change the unit at once for all these items by simply changing the measurement system. I know this is dangerous for persisted items without unit metadata, in which case it's of course preferable to explicitly define the unit. But at least the user has the freedom to choose.

I guess what I'm saying is: If we add such logging, isn't that the first step towards making unit metadata mandatory? I see this as an early warning/reminder before that happens. If we want to keep it optional, it shouldn't cause any warnings to be logged, as this would raise some concerns for perfectly valid configurations, and worse, it would be logged on each system startup, when the user really don't want to provide these units?

@mherwege
Copy link
Contributor Author

mherwege commented Feb 3, 2024

Would we then say we only need to force a unit when persisting? It is a totally different change of course, but we might look at forcing to set a unit in the persistence configuration for QuantityTypes. That would require extending textual and UI persistence configuration. The persistence unit would then be by item and persistence service.

@J-N-K
Copy link
Member

J-N-K commented Feb 3, 2024

Just some thoughts:

  • There is no difference between managed and un-managed items, they behave the same.
  • I agree with @jlaur that a valid configuration should not log warnings.
  • There was a suggestion similar to mandatory unit-metadata (Number:m/s, Number:%, Number:s) when we discussed the UoM changes, but it didn't find much support. I have some doubts that mandatory metadata would be much more popular, especially when it its not important for most users.
  • I don't think "artificial dimensions" should be introduced and adding Number:Percent as an alias to Number:Dimensionless ... [ unit="%" ] is also not the way to go. We would end up with a tons of such aliases and much confusion. E.g. what happens if I configure Number:Percent ... [ unit="ONE" ]?

@lolodomo
Copy link
Contributor

lolodomo commented Feb 4, 2024

The idea of the log message is not bad at all but of course we should log something only for Number:Dimensionless as it is the only case where we all know that the default unit ONE will be inappropriate in 99.99% of cases.
But I would prefer an INFO message as it is not 100% invalid to not set it.

@andrewfg
Copy link
Contributor

andrewfg commented Feb 4, 2024

Would we then say we only need to force a unit when persisting? It is a totally different change of course, but we might look at forcing to set a unit in the persistence configuration for QuantityTypes. That would require extending textual and UI persistence configuration. The persistence unit would then be by item and persistence service.

Actually, the real, (and perhaps only), problem is that persistence is wrongly designed. Currently each slot in a persistence database is storing only the float part of the data. Whereas it should be storing the full QuantityType i.e. a float and a unit. If that were the case, a time series of persisted data would always be consistent, even across a change in units. @mherwege suggestion to bolt on a unit to the data series, via the persistence configuration, outside the actual data series, is also a hack. The proper solution is to rework persistence to store and retrieve QuantityTypes in addition to floats.

A further nice to have would be a migration tool to convert legacy persistence data streams to QuantityType data streams by manually providing a unit to the conversion tool.

@jlaur
Copy link
Contributor

jlaur commented Feb 4, 2024

Actually, the real, (and perhaps only), problem is that persistence is wrongly designed.

This is an implementation issue in the concrete persistence services rather than a general design issue. At least I don't think anything prohibits the persistence services from storing unit information as well?

Personally I prefer a fixed unit in my MySQL tables so I can utilize the data outside openHAB without having to deal with conversions. But having e.g. a unit column shouldn't cause any problems except storage space (because it would usually be very redundant).

@jlaur
Copy link
Contributor

jlaur commented Feb 4, 2024

Would we then say we only need to force a unit when persisting?

Just a short note here for completeness: The impact of unit issues is probably most severe for persistence. But it is not the only place.

For rules, a user could either:

  • Define unit on item and use raw value knowing that unit.
  • Leave default unit on item and convert quantity value to desired unit in the rule.
  • Do both.
  • Do neither and face issues.

@spacemanspiff2007
Copy link
Contributor

What is the difference between missing unit metadata on a managed item and an item defined in an .items file, i.e. why would you only log this for file-based configuration?

My suggestions was to log it for all items on startup and when loading an *.items file it's only logged for the items defined in the file. Both items defined through gui and file should behave the same.

So you can change the unit at once for all these items by simply changing the measurement system.

This is a non-feature because how often do you switch your system from e.g. metric to imperial. And even if you want to do it's still possible by editing all the items, it's just not that convenient.
Also afaik when creating an item the GUI already suggests a unit so for these items a measurement system switch would already not work.

  • We would end up with a tons of such aliases and much confusion.

Do you already think of other aliases? If it's only one or two it'll be fine if there are many this should be rejected.

  • E.g. what happens if I configure Number:Percent ... [ unit="ONE" ]?

That would obviously not allowed, that's why I wrote "force to %". Changing the unit for Number:Percent should result in an error and the change should be rejected.

Currently each slot in a persistence database is storing only the float part of the data. Whereas it should be storing the full QuantityType i.e. a float and a unit.

Some persistence services don't support persisting a unit or strings so that would not work there.
Also the normalized value is not only used in persistence and rules but also when interacting with external systems e.g. for the HABApp rules. So that would effectively break the integration.

@mherwege
Copy link
Contributor Author

mherwege commented Feb 4, 2024

Some persistence services don't support persisting a unit or strings so that would not work there.

Totally agree, and I am not saying to store the unit, but to set a unit parameter in the persistence strategy for the item, so it gets converted to the unit before persisting. If the parameter is not set, use the default. The challenge is obviously that persistence is often defined or group (or all) level, so not the item level.
This is just a wild idea and is definitely more complex to pull off.

Also the normalized value is not only used in persistence and rules but also when interacting with external systems e.g. for the HABApp rules. So that would effectively break the integration.

Why is that? An item state for a QuantityType item contains the unit, also in the REST response. Does HABApp drop it by default and assume the default? That negates the whole value of units in my view. All the info is available in the REST responses.

@spacemanspiff2007
Copy link
Contributor

Why is that? An item state for a QuantityType item contains the unit, also in the REST response. Does HABApp drop it by default and assume the default? That negates the whole value of units in my view. All the info is available in the REST responses.

Almost - HABApp just drops the unit and treats the value as if it would be a value without unit.
That's why it's important to to set the unit metadata so the values don't change the scale unexpectedly and that's why HABApp logs a warning.
It's really a non issue because at some time you have decide on a unit and scale to do the calculations.
On the item level the benefit of UoM is questionable at best so this is not an issue.
Obviously if you want to bring UoM to HABApp PR welcome ;-)

@andrewfg
Copy link
Contributor

andrewfg commented Feb 5, 2024

My suggestions was to log it for all items on startup and when loading an *.items file it's only logged for the items defined in the file.

Perhaps use a console command instead of logging?

@spacemanspiff2007
Copy link
Contributor

Perhaps use a console command instead of logging?

But if I have to run a console command I already know that there might be an issue.
Isn't the goal to reach the users who simply forget to supply the unit or don't know they should supply one at all?

The intersection of users who know how to run the console command and users who face this issue is probably very small, too.

@andrewfg
Copy link
Contributor

andrewfg commented Feb 5, 2024

if I have to run a console command I already know that there might be an issue

Ok. You are right.

@rkoshak
Copy link

rkoshak commented Feb 5, 2024

I've suggested Number:Percent which will pin unit=% without further user interaction.

One concern I have is adding another source of confusion similar to what we have for Location. It's an Item and it's a semantic model category. I've had to help more than one user who created Location Items instead of Groups, with the semantic model Location tag and they can't figure out why they can't add Equipment to it.

I fully expect users to become confused between a Number:Percent and PercentType.

providing a unit could cause conversions between currencies using an online service. In some cases this is desired, but I could also imagine a few scenarios where this might not be, and the lack of unit metadata could be some safe-guard to not silently ignore a currency mismatch in the configuration (i.e. between a Thing configuration and linked item).

To truly protect yourself from this scenario, don't use a Number:EnergyPrice Item in the first place and just use a Number Item.

Currently you can have unpersisted items without unit provided, and I believe the configured measurement system will then be taken into consideration when determining default unit?

The default unit is chosen based on what the default for that type of unit is for the selected measurement system selected in regional settings. A user who has a Number:Length without unit metadata with SI selected I think will get a default of m whereas one with Imperial selected will get ft. The user has the option to change this default by setting the unit metadata.

Whether or not the Item is persisted is irrelevant.

That would require extending textual and UI persistence configuration.

What would need to change for the UI?

especially when it its not important for most users.

I think it is important for more users than you might think.

Also afaik when creating an item the GUI already suggests a unit so for these items a measurement system switch would already not work.

I believe the suggestion only results in unit metadata actually being added to the Item if the user changes it from the suggested default. So only where the user didn't change this will still work.

Do you already think of other aliases?

I can see developers of the car bindings wanting Number:LongDistance (or something like that) to measure length as km or miles instead of meters and feet by default. I'm not sure what the default units for volume are but could see something similar wanted there.

Essentially, any time a binding developer hits a situation where they have a lot of Channels not using the default unit, they're going to want an alias to reduce the need of their users setting the unit metadata.

Totally agree, and I am not saying to store the unit, but to set a unit parameter in the persistence strategy for the item, so it gets converted to the unit before persisting. If the parameter is not set, use the default.

By default I assume you mean whatever unit the Item is configured to carry (i.e. unit metadata or system default if the metadata is not defined).

Perhaps use a console command instead of logging?

@J-N-K posted a rule some time ago that will tell you all your Items lacking unit metadata. With permission I can convert that to a rule template and post it to the marketplace in a couple of hours.

@boehan
Copy link
Contributor

boehan commented Feb 6, 2024

Also afaik when creating an item the GUI already suggests a unit so for these items a measurement system switch would already not work.

I believe the suggestion only results in unit metadata actually being added to the Item if the user changes it from the suggested default. So only where the user didn't change this will still work.

I may be wrong, but looking at openhab/openhab-webui#2302, this only seems to be true for state description.

@mherwege
Copy link
Contributor Author

mherwege commented Feb 6, 2024

I may be wrong, but looking at openhab/openhab-webui#2302, this only seems to be true for state description.

That's also my interpretation. Unit metadata is always set when creating an item through the UI.

@mherwege
Copy link
Contributor Author

mherwege commented Feb 9, 2024

Closing this for openhab/openhab-webui#2312

While not entirely equivalent (does not solve the issue of users upgrading and having a mismatch between unit and state description), it will give a more meaningful default when creating a Dimensionless Number item through the UI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[UoM] Change default for Number:Dimensionless tio %
8 participants