I have several items that represent a percentage value. I have played around and realized that the values are randomly off by a factor of 100. The special thing is: If I do not change the code but just reboot, it might be correct value or just off by factor 100. It stays than stable for at least several hours / days.
Hausstrom_Autarkiegrad.postUpdate(((Balkonkraftwerk_ACPower.state as QuantityType<Power>) / ((Balkonkraftwerk_ACPower.state as QuantityType<Power>) + (Stromzaehler_Wirkleistung.state as QuantityType<Power>))) * 100.0)
The unsatisfying thing is not to check by factor 100 once - it is a non reliable bevaiour!
Hausstrom_Autarkiegrad.postUpdate(((Balkonkraftwerk_ACPower.state as QuantityType<Power>) / ((Balkonkraftwerk_ACPower.state as QuantityType<Power>) + (Stromzaehler_Wirkleistung.state as QuantityType<Power>))) as PercentType)
Script execution of rule with UID 'balkonkraftwerk-1' failed: Could not cast 1.5598103574033552151714077315827865956 to org.openhab.core.library.types.PercentType; line 25, column 39, length 192 in balkonkraftwerk
Ok, maybe it’s better to split it (for readability)…
val bkw = Balkonkraftwerk_ACPower.state as QuantityType<Power>
val zwl = Stromzaehler_Wirkleistung.state as QuantityType<Power>
val result = (bkw / (bkw + zwl)).floatValue
Hausstrom_Autarkiegrad.postUpdate(result * 100)
// or
Hausstrom_Autarkiegrad.postUpdate(result as PercentType)
Does the result of the calculation match the state of the Item? You’ll need to log out the result of the calculation first.
Is the Item’s actual state off by a factor of 100 (i.e. the value you see on the Settings → Items page or in events.log) or is it just the display state?
Does the calculation result in a QuantityType<Dimensionless> or does it carry some other unit or no unit at all? Again, logging out the result of the calculation can reveal that.
Sorry to jump in. I’m also struggling with this at times.
Would you know how to output the data type of a non-strictly defined variable or calculation result (other than if there’s an error message like here) ?
I think if you just toString the result it will log out with the unit. But it occurs to me that ONE is the most likely unit that would result from this calculation and that one doesn’t have a displayed unit.
Hmmm.
QuantityType does have a getDimension() method. That should tell us something.
val bkw = Balkonkraftwerk_ACPower.state as QuantityType<Power>
val zwl = Stromzaehler_Wirkleistung.state as QuantityType<Power>
val result = (bkw / (bkw + zwl)) // I want to preserve the QuantityType for logging
logInfo('Test', 'Result of calculation is: ' + result)
loginfo('Test', 'Unit is: ' + result.getUnit()) // I would actually expect this to show `ONE`
logInfo('Test', 'Dimension is: ' + result.getDimension())
Hausstrom_Autarkiegrad.postUpdate(result.toUint('%'))
Note: Hausstrom_Autarkiegrad.postUpdate(result as PercentType) is unlikely to work. Neither a primitive float nor a QuantityType is a PercentType. You cannot change them to become a PercentType through casting like this. PercentType is a distinct Class that float and QuantityType do not inherit from.
But if we stay inside QuantityTypes we can ask for the unit we want.
Do you still have the *100 in your rule? You shouldn’t have that as the unit conversion should take care of it.
Did you try the full rule @rlkoshak provided? That would be logging out the details (result, unit, dimension) and tell you exactly where it goes wrong.
Removing the *100 might solve it temporarly - I added it as openhab just went wrong after reboot by factor 100 => not deterministic, not reliable.
The rule does not work fully:
2024-04-02 10:58:14.083 [INFO ] [org.openhab.core.model.script.Test ] - Result of calculation is: 0.9999999999999999999999999999999999990
2024-04-02 10:58:14.085 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'test-1' failed: The name 'loginfo' cannot be resolved to an item or type; line 16, column 5, length 47 in test
Line 16 is:
loginfo('Test', 'Unit is: ' + result.getUnit()) // I would actually expect this to show `ONE`
If I skip this, than I get:
2024-04-02 10:59:48.731 [INFO ] [org.openhab.core.model.script.Test ] - Result of calculation is: 0.42498450092994420334779913205207686104
2024-04-02 10:59:48.732 [INFO ] [org.openhab.core.model.script.Test ] - Dimension is: one
2024-04-02 10:59:48.733 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'test-1' failed: 'toUint' is not a member of 'org.openhab.core.library.types.QuantityType<? extends java.lang.Object>'; line 19, column 39, length 18 in test
Most likely reason it may go wrong after reboot: restoring from persistence with the wrong unit. That happens if you change the unit, because all stored values will be assumed to be in the current configured unit.
2024-04-02 12:11:25.330 [INFO ] [org.openhab.core.model.script.Test ] - Result of calculation is: 0.71510572743004262862448824547334660965
2024-04-02 12:11:25.332 [INFO ] [org.openhab.core.model.script.Test ] - Unit is: one
2024-04-02 12:11:25.334 [INFO ] [org.openhab.core.model.script.Test ] - Dimension is: one
2024-04-02 12:11:25.336 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'test-1' failed: 'toUint' is not a member of 'org.openhab.core.library.types.QuantityType<? extends java.lang.Object>'; line 19, column 39, length 18 in test
And in the last line, it needs to be result.toUnit... instead of result.toUint....
You actually don’t need the conversion in that last line, because you can just postUpdate the quantity value from the calculation as is. Because you set the unit to be % in your item definition, it will persist as %. Because of the stateDescription string it should show as % as well. You can save in any compatible unit.
2024-04-02 14:07:37.927 [INFO ] [org.openhab.core.model.script.Test ] - Result of calculation is: 0.21371544896466172588186647157988482453
2024-04-02 14:07:37.929 [INFO ] [org.openhab.core.model.script.Test ] - Unit is: one
2024-04-02 14:07:37.930 [INFO ] [org.openhab.core.model.script.Test ] - Dimension is: one
Also this line works:
Hausstrom_Autarkiegrad.postUpdate(((Balkonkraftwerk_ACPower.state as QuantityType<Power>) / ((Balkonkraftwerk_ACPower.state as QuantityType<Power>) + (Stromzaehler_Wirkleistung.state as QuantityType<Power>))).toUnit('%'))
This should always work. The issue often stems from persisting in the wrong unit, or mixing pure Number and QuantityType.
And back to my suggestion:
Hausstrom_Autarkiegrad.postUpdate((Balkonkraftwerk_ACPower.state as QuantityType<Power>) / ((Balkonkraftwerk_ACPower.state as QuantityType<Power>) + (Stromzaehler_Wirkleistung.state as QuantityType<Power>)))
should give exactly the same result. You do not need to explicitly convert to the % unit as long as you have the state description pattern set to show % in your item definition.