Migration from 3.4.5 to 4.0.3: problem with battery level of mi home devices

I’ve upgrade OH to version 4.0.3 (I know about 4.1.0, but trying to do it step by step), and it cause problems. On of them is the percent conversion of battery level of mihome devices. They started display a something like “8300 %” instead of “83 %”. I have the similar devices connected via Z2M+MQTT, they show proper values.

The OH logs shows interesting thing:

Item '<problematic device 1>_BatteryLevel' changed from NULL to 83
...
Item '<common device 2>_BatteryLevel' changed from 0.97 to 0.9

But I sure that the battery level for “common device 2” exposes in percent (0-100) via MQTT. The record from the log of OH 3.4.5 confirms this:

Item '<common device 2>_BatteryLevel' changed from 100 % to 97 %

It seems OH 4 tries to converts values defined in percentage to use it internally and convert it back when displaying them, but something is going wrong. Or may be I do something wrong?

Could you please help me with the problem?

There were changes to how units are processed in OH 4. Instead of guessing at the unit for a given Item a set of hard and fast rules have been developed.

  1. The unit carried by the Item is defined by the unit metadata.
  2. If no unit metadata is defined, the system default unit is used.
  3. If an update arrives with a unit different from the unit carried by the Item, that value is converted to that unit.
  4. If an update arrives without a unit, the unit carried by the Item is assumed.

The default unit for Number:Dimensionless is ONE which represents a simple ratio.

I’d guess that what’s happening is you didn’t update your Number:Dimensionless Items with unit metadata and therefore the percentages are being converted from % to ONE; 97 % == .97 ONE.

So, as was discussed in the release notes, you need to define the unit metadata on your Items where the default unit is not what you want.

The problem is I have no idea where I can set up the units of measurement. Every things and items were added in Main UI. According to the release notes of OH 4 all should be converted by the upgrade scripts.

I added information about units in the places I could. For example, it was very easy for mqtt. I set up it in the channel configuration:

  - id: batteryLevel
    channelTypeUID: mqtt:number
    label: Battery Level
    description: Remaining battery in %.
    configuration:
      unit: "%"
      min: 0
      stateTopic: zigbee2mqtt/XiaomiAqaraMotionSensor009
      transformationPattern: JSONPATH:$.battery
      max: 100

I have an item linked to the channel with default conversion:

label: Battery Level
type: Number:Dimensionless
category: batterylevel
groupNames:
  - XxxxxxMotionSensor
groupType: None
function: null
tags:
  - Status
  - Level

It displays the same value as before upgrade (the difference only in logs I wrote before): “97 %”

The situation with things bound to Mi Home is different.
I have the thing:

UID: mihome:sensor_motion_aq2:158dxxxxxxxxxx
label: Xiaomi Aqara Motion Sensor 002
thingTypeUID: mihome:sensor_motion_aq2
configuration:
  itemId: 158dxxxxxxxxxx
bridgeUID: mihome:bridge:xxxxxxxxxxxx

The thing has several channels:

<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="mihome"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
	xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">

	<thing-type id="sensor_motion_aq2">
		<supported-bridge-type-refs>
			<bridge-type-ref id="bridge"/>
		</supported-bridge-type-refs>
		<label>Xiaomi Aqara Motion Sensor</label>
		<description>Sensor that detects movement. Also called Occupancy Sensor or Human Body Sensor. After it detects motion,
			it goes to sleep for 1 minute.</description>
		<channels>
			<channel id="motion" typeId="motion"/>
			<channel id="illumination" typeId="illumination"/>
			<channel id="motionOffTimer" typeId="motionOffTimer"/>
			<channel id="lastMotion" typeId="lastMotion"/>
			<channel id="batteryLevel" typeId="system.battery-level"/>
			<channel id="lowBattery" typeId="system.low-battery"/>
		</channels>
		<config-description-ref uri="thing-type:mihome:device"/>
	</thing-type>
</thing:thing-descriptions>

I have an item linked to “batteryLevel” channel with default conversion:

label: Battery Level
type: Number:Dimensionless
category: Battery
groupNames:
  - YyyyyyyXiaomiAqaraMotionSensor
groupType: None
function: null
tags:
  - Status
  - Level

It displays the wrong value after upgrade : “8300 %”

I thought that “system.battery-level” is a system-channel type which should provide right units of measure. And it provides something, otherwise the UI display “one”, but it displayes “%”.

I tried to define unit of metadata for the item as you adviced, but UI does not allow it (I have done it for group aggregation items and it helped there, thanks for the advice). I think it is becase the unit of measure was provided by channel.

It look like a bug, but I hard to belive nobody found it since 4.0 was released. Maybe I do something wrong?

Settings → Items → MyItem → Add Metadata → Unit

There is no such thing as a “system-channel type”.

It probably does provide the right units. But the units provided by the Thing/Channel may not be the unit desired to be used by the end user. Therefore, it’s the unit on the Item that counts. If the unit on the Item doesn’t match the unit of the value delivered by the Channel, OH converts the value to the unit of the Item.

So far you’ve not shown what you’ve tried to do on the Item. If you’ve not added the metadata from the menu above then you’ve not yet set the unit metadata on the Item and therefore have not solved the problem. Unless and until the unit metadata is defined as %, the value is going to continue to be converted to the default unit for Items, ONE.

Yes, with the information presented thus far you have a miss configuration.

Note, in 4.1 going forward, everywhere you can create an Item in MainUI, you will be presented with the default unit that will be assigned to that Item and you will have the option to change that unit before the Item is created.

Thanks a lot for your answer. I’ve upgraded to OH 4.1 and now UI allows assign unit using the menu you mentioned for battery level (It did not display “unit” option before for battery level, only for group items).
I dig into documentation and made several tests, and near to understand what was wrong: your are completely right that the problem was in “Dimensionless” dimension. OH tries to get dimension from channel (that’s why it displays “%” but not default unit “one”), but something goes wrong with it. It converts the values right from several channels and wrong from others. I have no problems with for example temperature values because I use items with “Temperature” dimension with default unit - Celsius (in my case) and channels report and send it in Celsius. But it might cause the same problem if I whould have a channel reporting that it sends temperature in Fahrenheit (and sending it in Fahrenheit). I’ll try to check it when I have a spare time.

Anyway, I made a script (javascript) which set right unit for all the items displaying battery levels and humidity:

items.getItems().filter(item=>(item.name.endsWith("_BatteryLevel") || item.name.endsWith("_Humidity")) && !item.getMetadata("unit")).forEach(item=>{
  item.replaceMetadata("unit", "%");
  console.log("The unit metadata was set to %s", item.name);
});