Units of Measure - UoM - OH4 - Standard Display

I read OH4 annoucements regarding breaking changes in UoM in OH4.
No complain about the new handling which is from technical point needed.
As a Car binding developer I still have a question regarding the region of hte user and the corresponding display of units of that region.

Situation in OH3
Carr binding is recognizig the Number:Length is Miles or Kilometres from the backend. Configuring channel-types with %unti% is always displaying the delivered Unit.

	<channel-type id="mileage-channel">
		<item-type>Number:Length</item-type>
		<label>Mileage</label>
		<state pattern="%d %unit%" readOnly="true"/>
	</channel-type>

Situation in OH4
The bindig is still delivering Miles or Kilometres from backend and the channel has the correct value in metres.
But the user wants too see his values based on the configured region.

My Problem
What shall I deliver in my binding project as channel-types.xml to reflect the correct UoM based on the cofigured region?
I can enter km as shown below to satisfy European customers - this works!

	<channel-type id="mileage-channel">
		<item-type>Number:Length</item-type>
		<label>Mileage</label>
		<state pattern="%d km" readOnly="true"/>
	</channel-type>

Shall I ask every user in North America user to add a state pattern in UI to change the pattern of the items

  • mileage
  • range-electric
  • range-fuel
  • range-radius
  • trip-distance

Unfortunately there was a deliberate decision to not allow bindings to supply unit metadata. You can supply actual units to the State Description Pattern but that’s just going to change the how the Item is shown.

The end users will have to supply unit metadata manually where their desired unit does not match what the system default is (which I think is feet for Number:Length when Imperial is chosen and meter for Metric.

I didn’t test this out yet, but there might be a solution if you redefine the default state description in code. You would need to make these channels dynamic channels and overwrite the default state description when you create the channel.
There is a (advanced) parameter in regional settings, measurement systems. You should be able to query that and make your default state description depend on it. See here: https://github.com/openhab/openhab-core/blob/af4fce1e4f7faf9e5d89ded3ca31a20aac57ecf7/bundles/org.openhab.core/src/main/java/org/openhab/core/i18n/UnitProvider.java

@MartinOpenhabFan This could also be an option for the BMW binding.

1 Like

@rlkoshak

Agree, I’m only talking about display.

Exactly this manually is bugging me. I’ve to tell each user of my Mercedes binding to change mileage, ranges, pressure (common is bar)…and so on.

There should be something possible like this (keep in mind, only display!)

  1. system default - fine, used as standard
  2. binding default - binding default - You and I know that mileage isn’t shown in metres / feet
  3. user setting - user shall be able to define it’s own pattern and overwrite everything

@Mherwege
To be honest from the mentioned Interface I not able to derive what you mentioned. I’m also not looking for a hack which is overwriting system defaults. If the problem is accepted as valid there should be proper solution for all - you mentioned already MyBMW but VW, Reanult, Tesla, have definitely the same issue.

No, it is not a hack. Using that interface you can check within the binding code, what measurement system is configured and build the quantity type according to the correct system.

So my rough algorithm would be:

  1. In your HandlerFactory, use a reference to UnitProvider (similar to the one you have to TimeZoneProvider). You can then use a call to getMeasurementSystem() to decide on SI or Imperial.
  2. In your channel-type xml, have 2 different channel types, on with a default state pattern of %d km and another one with a default state pattern of %d mi.
  3. In your handler, create the channel using one or the other type dynamically.

Updating the thing structure is documented here: https://www.openhab.org/docs/developer/bindings/#updating-the-thing-structure

There are multiple bindings doing this kind of thing, e.g. https://github.com/openhab/openhab-addons/blob/d0b161aca189a9cbec317af6454f5f772f4ce3f0/bundles/org.openhab.binding.evcc/src/main/java/org/openhab/binding/evcc/internal/EvccHandler.java#L274

1 Like

Ok, this is what I call a hack :wink:

There’s no need to idendtify the system settings. Mercedes is delivering the unit. So I can change also my car to imperial system in Germany and it should work

Phew - 9 more channels, switching them dynamically, “just” to switch from metre / feet to kilometre / miles?
I think this will work but that’s far away from “straight forward” solution, right?

Agreed it is a bit of a hack.

What is needed is a method to more easily define the default state description in code. As it is on channeI type level, it is more convoluted then needed. It is missing from channel level. I would still vote against messing with the default unit in a binding, as that impacts much more than visualisation. It also messes with persistence, REST API, rules etc. And don’t forget that one item can be linked to 2 channels from different bindings, creating potential conflict. If it is only default visualisation, it is easy to override. All of this led to the changes in OH4.

I actually think you need less channel types doing this. You need one by unit. All the rest can be defined dynamically on the channel (including label and description) and will take precedence from there. So you will have less channel types, and your 9 channels will be created dynamically instead of defined statically.

That‘s not the point. You want to set the units in the binding „globally“, not per item. So you have to identify the users perference (regional settings) and transform what the api delivers to that unit.

@Mherwege
I found ia soluttion

  1. Provide a DynamicStateDescriptionProvider in your binding
    https://github.com/weymann/openhab-addons/blob/mercedes-sdk/bundles/org.openhab.binding.mercedesme/src/main/java/org/openhab/binding/mercedesme/internal/MercedesMeDynamicStateDescriptionProvider.java

  2. No implementation needed. Extended class provides public interface setStatePattern to override state pattern of your channel-types.xml https://github.com/openhab/openhab-core/blob/af4fce1e4f7faf9e5d89ded3ca31a20aac57ecf7/bundles/org.openhab.core.thing/src/main/java/org/openhab/core/thing/binding/BaseDynamicStateDescriptionProvider.java#L60

  3. HandlerFactory will receive this Reference and you can it pass to your handlers. So setStatePattern can be used wherever you want https://github.com/weymann/openhab-addons/blob/mercedes-sdk/bundles/org.openhab.binding.mercedesme/src/main/java/org/openhab/binding/mercedesme/internal/MercedesMeHandlerFactory.java#L69

@hmerk
Just to be sure: don’t take my statements as offensive:

No, fully disagree! The Car is Master => not openHAB!
Again no offence - I don’t care about about the regional settings of openHAB. See below pictures what I can configure for my german car. If Fahrenheit is configured please display Fahrenheit"!

But I understand your proposition

  • 99,999 whatever percent of the users will use complete Imperial or Metric system based on region
  • 0,001 whatever percent of users will have a fancy combination of measurements

Main Point is with the above solution we’re covering all possibilities!


I don‘t, of course😉
But i think, the only master is the user, not the car nor openHAB. Therefore, no matter what is configured in the car, openHAB should display what the user wants to see, and that is, from my perspective what he/she configured in the regional settings.

1 Like

Yes, fully agree!

After testing I can confirm the above three steps are working with the usage of DynamicStateDescriptionProvider.

  • System default isn’t affected
  • Binding can set the pattern as delivered by vehicle
  • User can override metadata if he wants something different

So: User is the master!

1 Like