Converting numbers in the model (bytes -> giga bytes)

I have an item that has bytes as state (type is Number without dimension).

I want to display this as GB everywhere.

Changing the type to Number:DataAmount did not help me.

In the State Description, I can format, but seems like I cannot calculate.

My current workaround is to use this expression as label for Default Standalone Widget:

=(Number.parseFloat(items.UDMPro_TotalStorageAvailable.state)/1024/1024/1024).toFixed(0) + " GB"

However, I cannot change the label (=value) for Default List Item Widget.

Any other options? Thanks!

Use Units of Measurement i.e. use Number:DataAmount, that’s right what the feature was built for.
If you have a value of say “1024 MB” and define a metadata pattern of say “%.1f GB” then OH will automatically convert it when displaying in MainUI.
Remember you need to initially set the value with a unit.
Eventually also search the forum for ‘bootstrapping items’, there’s a tutorial how to do that best.

If the source of your number (which is a secret from us) does not have units, and it is a channel, you can use a profile to modify the channel output before it updates the Item.

The source is a Number without Dimension and it has no units but I know it is in fact bytes. This is from a channel from the marketplace binding for UniFi Protect.

I am not the developer of the binding, I am just using it. How can I use a profile in this case?

You have choices.

Using a transform profile that is a little javascript, you can append the text unit for bytes to the the basic number from the channel, and link it a Number:DataAmount type Item. How it gets displayed is controlled by the Item metadata, with auto-scaling just as @mstormi says.

Or of course the little javascript could do the maths as well, and pass Gb if you like.

Or you use a plain Number Item and apply a display transformation that scales it to what you want for the UI while leaving Item state unaltered.

If you are charting this value, your choice might be steered by what value you want to store and chart (which will be the raw Item state).

I think you don’t even need a profile. You should be able to simply link the channel to an item of Number:DataAmount type.
Bootstrapping will define the default unit to apply. If that does not work use the profile as @rossko57 suggests.

But if the number from the channel comes in bytes, that is what you must set the Item’s default unit to to get the correct value imported.
Then you don’t get the display in wanted Gb because the default is used for that as well 


I already changed the item type from Number to Number:DataAmount but where do I set the default unit for an item?
If I set the State Description pattern to “%.1f GB”, I just get the bytes value + “GB”.

As I said: search the forum

As I’ve tried to explain, if you load a “plain number” into a Quantity type Item, it will assume that Items default unit.
So set default “b”, post “22”, get “22 b”.
Set default “Gb”, post the same 22, get “22 Gb”.
Obviously if you post a plain number you must set Item default to the units the number is really coming in.
That’s fine, it works.

But it leaves you unable to show the value in Gb - the default unit is used for for both purposes and can only be one thing at a time.

If you post the full “22 b” (e.g. by using a profile) it doesn’t matter what the Item’s default units are, auto-conversion works.

I understand why it is not working as it is. That’s clear.

What I still don’t know, even with the forum link above, is where to set an item’s default unit.
However, if auto conversion then does not work anyway, I would not be able to convert the b to Gb in the State Description, so this is not the solution for me anyway.

That leaves me with a channel profile conversion via JS and that is what I will try next. Although, I think that the whole thing should be easier to do for the user, setting a default unit that is working with auto conversion.

Yes, the binding should provide correct units in the first place, but it is like it is.

Edit:
OK, got it working. I installed the JS transformation. Then I wrote a small JS named “bytes.js” in the transform folder like this:

(function(i) {
    return i + "B";
})(input)

And then used that in the channel transformation profile setting:

Then I set the pattern “%.1f GB” in the model State Description. Now I have everywhere “X.Y GB”, like I wanted. Still think this is too complicated.

Thanks for all the hints here.

1 Like

It does work, but it needs to know the value is in bytes to begin with.
The binding is not supplying that info - this is what is needed for -

You might make an enhancement request for that binding, that’s all that is needed to make it seamless.

What I think is a real restriction is that an Item’s “default unit” and “display unit” are both derived from the same metadata, two different uses for same info. That’s not likely to change in OH3.

If the binding does not provide the quantity unit, ideally I would like to be able to edit the item, change type from Number to Number:DataAmount and enter the base unit there.
Using channel transformation is very powerful but seems like overkill for this simple thing.

One strange thing with my current solution remains:

I have set pattern “%.1f GB” and when I click on the item, I see this:

But in the list of items, I see this:

Why is it not using only one decimal in the 2nd case?

Because the pattern metadata is about display of Item state. It used to be that was all it was about, and never affected actual state in any way.
Later, they introduced Quantity types, with units. Some way to define a default unit was needed, and in the middle of OH2 development “they” decided to hijack the existing pattern (where everyone was putting text to represent units in their displays anyway) and re-use it for this new purpose as well. Rather than changing the core Item model with a new property.

So as you found, you cannot define a default different display. The units part of the pattern gets (ab)used for a default when the data source is deficient and has no units.
(It gets involved in persistence as well - if you change the default unit it has bad effects on historic data)

Meantime the non-units part of ‘pattern’ remains purely for display purposes, the real Item state is unaffected (e.g. can be many decimals) and in the admin facing parts of the GUI you will see raw states, not the prettified version for end users.

2 Likes

Thanks for the insight!

Is there a plan or proposal on fixing this?

Not that I’m aware of. A logical approach would be to separate the default/display properties in OH4 by redefining core Item object. That’s probably much simpler than it was in OH2, with more flexible metadata already available in OH3.

All this is only of interest when the data source is deficient of units, but you want to force unit assignment anyway.
Some bindings remain that can “know” data units but do not currently supply them, so they can be usefully enhanced.
Other bindings handle generic data and cannot guess what units might be appropriate, so we do need a way to manually designate. But that is just what profiles or channel-based transformations are for.

Yes, I think users should file feature requests on each and every binding that could be enhanced by using UoM. It is always sensible because this causes breaking changes but it goes in the right way to empower OH.