Issue with showing Battery level in Percentage (Number:dimensionless)

Hi guys,

I have an issue with my battery levels and it seems I cannot figure out how to make it right.
I have some Xiaomi Temperature, Humidity and Pressure Sensors and want to show the level of the Battery in Percentage (%) in my sitemap.
The value always gets shown with 2 Percentage signs %%.

Everything I tried so far resulted in wrong formatting or wrong values shown. I use OpenHab 4.2.0.
Could someone please point out what is wrong?

The battery level gets into OpenHab via the MQTT Binding. In MQTT the values are between 0 and 100; that’s why I divide the number /100 with a transformation.

The Thing Definition which includes the Battery Level is:

Thing topic XHTP01 "Xiaomi Temperature, Humidity and Pressure Sensor 01" {
Channels:
	Type number : battery		[ stateTopic="zigbee2mqtt/0x00158d00025d8b50", transformationPattern="JS:format_BatteryLevelToPercent.js" ]
}

My Item Definition for the Battery Level is:

Number:Dimensionless	XHTP01_Battery	"HTP Sensor #1 Battery [%s %%]"	<battery>		["Measurement", "Energy"]	{ channel="mqtt:topic:MQTTBroker:XHTP01:battery" }

In my Sitemap:

Text item=XHTP01_Battery

The result looks like this:

If I change [%s %%] to [%s] I get:

How can I make it that it just shows “100%” with the correct Battery Icon?

Just for completeness, here is my format_BatteryLevelToPercent.js:

(function(i) {

    var data = JSON.parse(i);
    batterylevel = data.battery;

    return parseFloat(batterylevel) / 100;

}) (input)

I think I just figured it out after posting the question.

Instead of [%s %%] I use [%.0f %%] and it seems to work.

This works until you need to start charting it or using it in a rule.

The best way to handle a percent value from MQTT is:

  • set the unit property of the Channel to % to indicate that the Channel publishes a percent
  • link the Channel to a Number:Dimensionless Item
  • set the unit metadata on the Item to %
  • optionally set the label to [%.0f %%]

The last part is optional because you’ve ensured that the Item always carries a percent.

The default unit for Number:Dimensionless is one which is a simple ratio. 57 % = 0.57 one. So by dividing by 100 a the Channel you’ve converted the % to one and then you convert it back to a % for display. That’s a whole lot of unnecessary conversion.

But if you did want to keep the value as unit one the best approach is to let OH convert the units for you. Set the Channel unit to % and set the Item unit to one and OH will do the conversion for you. But I can’t see any reason to convert it from a % to one but then show a %. Just keep it as a percent.

The unit can be set at different places and each place has a different purpose:

  • Channel: for bindings like MQTT this tell OH what unit the value the Channel publishes is in
  • Item: this is the unit the state of the Item will always be in. If it receives a number that doesn’t have a unit, this unit is assumed. If it receives a number with a different unit, the value is converted to this unit. Each type has a default unit which is used if no unit metadata is defined
  • Label/State Description Pattern: this controls how the state of the Item is shown in most places on the UI. If this is different from the Item’s unit, the value is converted before display

The three work together.

But if you are going to use units at all, you should always set the unit metadata on the Item to indicate what unit you want to work with and store in persistence (note that this unit will be applied to all values returned by persistence now).

Thank you for the detailed explanation!

So now my only change compared to above is that I have also set the Unit in the Thing and Item Definition like this. Still applying my /100 Transformation.

Thing topic XHTP01 "Xiaomi Temperature, Humidity and Pressure Sensor 01" {
Channels:
	Type number : battery	[ stateTopic="zigbee2mqtt/0x00158d00025d8b50", unit="%", transformationPattern="JS:format_BatteryLevelToPercent.js" ]
}
Number:Dimensionless	XHTP01_Battery	"HTP Sensor #1 Battery [%s %%]"	<battery>		["Measurement", "Energy"]	{ channel="mqtt:topic:MQTTBroker:XHTP01:battery", unit="%" }

But why do I need to set it again for the Item?
Isn’t this redundant if it’s already defined in the Thing/Channel? I would expect that the Unit is taken over to the Item from the Channel

Also it seems it now works with and without my transformation (/100).
Can OpenHab handle 0-1 and 0-100 when I set unit=“%” ?
And if my Battery Level is “1” how does OpenHab know that 1=1% and not 1=100% ?

Thanks!

Why? A % is a value between 0 and 100 (you can go outside that range but you get the idea). Your device is reporting a value between 0 and 100. And you originally configured your Item to show a value between 0 and 100. There is no need to divide by 100 at all.

The entire point of my post was to show that you do not need the divide by 100.

Read my reply again. There are three places you can define the unit and it has a different purpose in all three palces.

You define it at the Channel to tell OH what unit the Channel will publish.

You define it at the Item to tell OH what unit you want the Item to use.

You define it at the State Description Patter to tell OH what unit you want to see in the UIs.

What if the device/Channel publishes °F but I want to use °C? You configure °F on the Channel to tell OH what unit the Channel publishes. You configure °C on the Item to tell OH what unit you want to use. The °F will be converted automatically to °C because that’s what you want to use.

Yes, that’s what it expects. 5% is literallt 5 %, not 0.05.

Because you told OH that the Channel is publishing a % and you told OH that you want the Item to store a %.

Again, if for some reason you didn’t want 1 % but instead wanted 0.01, you would set the unit metadata of the Item to one (or just leave it as one is the default assumed when the unit metadata isn’t defined). Then the unit property on the Channel tells OH that the Channel publishes % but the unit metadata says you want to use one as the unit so the 1 % gets converted to 0.01 one automatically.

Thanks!
Makes perfect sense now.

I have changed all my battery things and items and it’s now working as expected :slight_smile:

Its an older thread, but I have the same issue and are not able to fix it. I am pulling data via modbus from the battery and Number:Dimensionless wont work properly.

#1 number-channel

The value as a percentage is stored in modbus as integer (i.e. 755 = 75,5%). I divide by 10 in modbus readtransform to get the percentage.

Thing data Marstek1_Akku_decimal_soc     "Marstek1 - SoC Dezimal"      [ readStart="34002", readValueType="uint16", readTransform="JS(divide10.js)" ]
Number:Dimensionless   Hausakku_1_Capacity_SoC   "Ladezustand [%.1f %%]"   <batterylevel>    (Hausakku_1_Capacity)    {alexa="RangeValue", channel="modbus:data:marstek1_bridge:Marstek1_bridge_cellVoltages1:Marstek1_Akku_decimal_soc:number"}

Problem is: This setup gives me the weird 7570% - the dynamic image shows correct though.
grafik

I also tried to use %unit% on the item, which then renders correcnt numbers and image - but in this case the unit displayed is one, which is also not correct.
grafik


#2 dimmer-channel

Thing data Marstek1_Akku_decimal_soc     "Marstek1 - SoC Dezimal"      [ readStart="34002", readValueType="uint16", readTransform="JS(divide10.js)" ]
Number:Dimensionless   Hausakku_1_Capacity_SoC   "Ladezustand [%.1f %%]"   <batterylevel>    (Hausakku_1_Capacity)    {alexa="RangeValue", channel="modbus:data:marstek1_bridge:Marstek1_bridge_cellVoltages1:Marstek1_Akku_decimal_soc:dimmer"}

If i use the dimmer channel on the thing in my item, the item in basic UI is rendered correctly it lloks like - but not on the OH Apps (neither Android nor iOS). That its correct on the web I only realized during post creation, because it seemd easier to get a sscreenshot here from web…
grafik

Problem here: Non of the two OH Mobile Apps (Android, iOS) renders the dynamic image correctly, if I use dimmer channel. BUT it does, if I use number channel - in that case the percentage number is wrong (siee #1).


Summary: IF the correct solution is using the dimmer channel (0..1) with unit="%%"then there is a bug in both OH mobile Apps, as they render the dynamic item image wrong!

Or am I wrong?

PS: Sorry to not add the screenshots from mobile app - but you should be able to repo.

You have to set the unit metadata to %.

`unit=%`

Otherwise, the unit assumed will be systemwide default which for Number:Dimensionless is ONE which is a simple ratio.

.75 ONE = 75 %

When a value is passed to an Item in an update that’s a different unit from the Item’s unit, it gets transformed to the Item’s unit. In this case you are passing 75.7 % which gets transformed to 7570 ONE.

For the most part, you should always set the unit metadata for all Number:X Items so it’s always clear what unit you want the Item’s state to be in and if anything is ever sent with different units, it will be converted to your desired units.

Dimmers only support PercentType meaning integers between 0 and 100. And a Dimmer Channel is expected to be linked to a Dimmer Item. I would not be surprised if the fact that you have linked a Dimmer channel to a Number Item is causing problems.

The correct solution is using the Number Channel with unit=% metadata on the Item.

1 Like

Okay, I thought I tried it. But I did it with ,stateDescription=""[unit="%%"] which did not work. Using only unit="%" worked. Thanks!