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

[blockly] UOM handling, provide block to strip unit and convert Quantity to Decimal #1945

Closed
mherwege opened this issue Jun 28, 2023 · 10 comments
Labels
enhancement New feature or request main ui Main UI

Comments

@mherwege
Copy link
Contributor

The problem

I am trying to replace the following Jython code by a blockly script:

certifikaten = math.floor((items["PVEmeter"].toUnit(Units.KILOWATT_HOUR).floatValue() - CERTIFIKATEN_OFFSET)/1000)
events.postUpdate("Certifikaten", str(certifikaten))

Certifikaten is a Number item without Dimension.
CERTIFIKATEN_OFFSET is a numeric constant in the script.

There is no easy way to strip the unit from a Quantity and get the pure numeric value in Blockly. It can probably be done with a text replace block or by dividing the Quantity by a Quantity 1 with the same unit, but that does not feel natural and is not easy to understand for a novice.

Your suggestion

Provide a block in the Units of Measurement section to strip the unit from a Quantity.

@mherwege mherwege added enhancement New feature or request main ui Main UI labels Jun 28, 2023
@rkoshak
Copy link

rkoshak commented Jun 28, 2023

There is. The "get X of Item" block has a "numeric state" option.

image

That returns the state of the Item without units.

I can't think of any other case where you would have a Quantity that didn't come from an Item. If you did, then the solution is to not create that variable as a Quantity in the first place.

However, there is a wrinkle above in that you are converting it to a specific unit. In that case it probably makes sense to keep everything in units. Since "Certifikaten" is just a Number, OH will strip the units if you postUpdate to it. Though one wonders why have this miss match. I'd think you'd either want both PVEmeter and Certifikaten to have units or neither of them to have units. Note, in OH 4 even if the Channel uses units you don't have to. Just link it to a Number Item. the opposite is also true, if you want to use units and the Channel doesn't, you have the option to append units.

Were it me, I'd create CERTIFIOKATEN_OFFSET as a Quantity in the first place.

image

Eliminate the divide by 1000 and instead use the to unit block to convert it from kWH to MWH and sent that as the value to postUpdate. It makes sense to make Certifikaten a Number:Energy but if there is some odd reason you don't want to, OH will strip the MWH unit and you'll just have the number.

@mherwege
Copy link
Contributor Author

The other place where this is an issue is with event.itemState. I simplified the code above, leaving this out. It is covered for items, however, it is not always clear what unit one is getting back if you use the numeric value.

In this case Certifikaten has no logical unit. I am getting money every time I produce 1000 kWh with my solar panels. I need to submit my solar panel meter readings for that. 1000 kWh represent a discrete certificate, no unit. Keeping track nd having OH generate a message triggers me to submit readings. So Certifikaten is effectively dimensionless.

@mherwege
Copy link
Contributor Author

Another use case for this: getting the quantity state, converting to another unit and then rounding. To do the rounding, one again has to strip the unit and add it back again afterwards. You cannot force to get the numeric value of an item in a specific unit.

@mherwege
Copy link
Contributor Author

mherwege commented Jun 29, 2023

Eliminate the divide by 1000 and instead use the to unit block to convert it from kWH to MWH and sent that as the value to postUpdate. It makes sense to make Certifikaten a Number:Energy but if there is some odd reason you don't want to, OH will strip the MWH unit and you'll just have the number.

The number has to be an integer, rounded down. If I keep units, I can't round down.

@mherwege
Copy link
Contributor Author

mherwege commented Jun 29, 2023

The javascript library supports it, there is just no way to do it in Blockly, see documentation:

var qty = Quantity('10.2 °C');

qty = qty.toUnit('°F');
var intValue = qty.int;
var floatValue = qty.float;

@rkoshak
Copy link

rkoshak commented Jun 29, 2023

The other place where this is an issue is with event.itemState.
I'm not entirely certain the Quantity blocks would help here as event.itemState is the Java State Object, not a JavaScript Quantity. I think you can use an Item State to create a Quantity so theoretically the first Qty block ought to take event.itemState and be able to convert it to a JS Quantity. But if it has to be converted anyway, one wonders if instead we should have a block that exposes parseInt() and parseFloat() which will parse up to the first non-number character and stop. That effectively trims off the units but would also have uses outside of just Quantity types.

The other place where this is an issue is with event.itemState. I simplified the code above, leaving this out. It is covered for items, however, it is not always clear what unit one is getting back if you use the numeric value.

In OH 4 it will always be the unit defined by the unit metadata. But if you want something different, you can use the qty block to convert the event.itemState to a Quantity and then use the to unit block to change it to something else. Then if you need to remove the units, I'd propose either exposing the int/float properties in a block or adding the parseInt() parseFloat() blocks mentioned above. I'm a little more in favor of exposing the parse functions as they have additional uses outside of Quantity.

So Certifikaten is effectively dimensionless.

OK, but like I said, when you post a value with units to a Number Item, OH will strip the units for you. You don't have to do this in your rule.

Another use case for this: getting the quantity state, converting to another unit and then rounding.

I'm thinking for this it might be more appropriate to add support for all the Math functions, not just one of them. But I'm not sure how feasible that is. I think it could work though but support would have to be added to openhab-js first.

@stefan-hoehn
Copy link
Contributor

Is there still an open issue that needs to be fixed, if yes, please update the description, otherwise it would be nice if you closed this one here? thx.

@mherwege
Copy link
Contributor Author

Another use case for this: getting the quantity state, converting to another unit and then rounding.

I'm thinking for this it might be more appropriate to add support for all the Math functions, not just one of them. But I'm not sure how feasible that is. I think it could work though but support would have to be added to openhab-js first.

There is still something open, but it probably would be more appropriate to create a new issue for it. I see regular questions in the forum about wanting to strip units to do math operations. As long as we don't have broader support for math functions, it will keep coming back. I will create a new issue for it.

@stefan-hoehn
Copy link
Contributor

@mherwege Are you referring to this in terms of "broader support of Math operations"?
#2001

@mherwege
Copy link
Contributor Author

@mherwege Are you referring to this in terms of "broader support of Math operations"?
#2001

@stefan-hoehn Yes, so no need to open a new one. That should take care of a major reason to strip units.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request main ui Main UI
Projects
None yet
Development

No branches or pull requests

3 participants