I have a rule that I wrote with OH 4.2 that basically does this:
const quantityState = historicItem.quantityState;
const numericState = historicItem.numericState;
if (quantityState)
// work with it
else if (numericState)
// fallback
Where historicItem is an element in an array of PersistedState elements, retrieved like this:
This worked well because the documentation says this:
Item state as Quantity or null if state is not Quantity-compatible or Quantity would be unit-less (without unit)
When null is returned, the if condition is false and I’m happy with that.
But since I have updated to OH5.2, the above code no longer works, the rule fails when accessing the QuantityState property with the following error message:
Script execution of rule with UID '734823b712' failed: Error: Error: Failed to create "quantityState": TypeError: Argument of wrong type provided, required Item, string or Quantity.
The workaround is obviously to use a try...catch statement, but it’s really cumbersome and goes against the documentation and it caught me by surprise because I did not see any mention of this in the changelog.
The only way an error can be thrown here is if the rawState is of a type not supported by getQuantity(). If we trace the code further we see that a PersistedItem is passed a Java HistoricItem which calls the constructor for PersistedState with the Java State of the HistoricItem. This means _quantityStateOrNull() gets called with the Java State and therefore getQuantity() is called with the Java State Object.
getQuantity() just calls new on the Quantity class with the Java State Object.
In the constructor, if the passed in state is a Java QuantityType, which is what it should be here, it’s supposed to just take that as the rawQuantity. Somehow that’s failing and it’s trying to convert what’s passed into a Java QuantityType.
function _toQtyType (value, errorMsg = 'Argument of wrong type provided, required Item, string or Quantity.') {
if (_isItem(value)) {
if (value.rawState.getClass().getSimpleName() === 'QuantityType') {
value = value.rawState;
} else {
try {
value = QuantityType.valueOf(value.state);
} catch (e) {
throw new QuantityError(`Failed to create QuantityType from Item state ${value.state}: ${e}`);
}
}
} else if (typeof value === 'string') {
try {
value = QuantityType.valueOf(value);
} catch (e) {
throw new QuantityError(`Failed to create QuantityType from ${value}: ${e}`);
}
} else if (_isQuantity(value)) {
value = QuantityType.valueOf(value.rawQtyType.toString()); // Avoid referencing the same underlying QuantityType, so "clone" it
} else {
throw new TypeError(errorMsg);
}
return value;
}
Here we find the source of the error message. It’s falling through all of these if statements and throwing that TypeError at the end. So we can conclude the state returned by persistence is not:
null
undefined
QuantityType
Item
string
However, one of the bigger changes between OH 4 and OH 5 was a major overhaul on how UoM works in Items. How is this Item defined? Does iot have unit metadata? If so what is it?
It’s a WMO code, so a simple number without any unit.
Note that I would love to be able to write if (myItem is Quantity) but I don’t think there are any properties for this on the javascript object.
if(items.MyItem.type.includes(":")) // Number Items with dimensions are the only ones with a : in the type
or
if(items.MyItem.type.startsWith("Number:"))
But that’s not going to help you with a PersistedItem which is a different type of Object and doesn’t have type. But presumably you know which Item the persisted data came from so you could possibly to that.
But the as far as I know and in my experience the code as written should work too. Knowing that it’s not a QuantityType and it is a DecimalType narrows the search somewhat.
Yes, but it’s inside a “helper” method that gets called for quite many items, so I’d rather avoid adding another parameter to that method just for this.
If you want to have a look at it, it’s in the getHistoricItemNumericValue method inside this monster of script: ohab-weather-display/doc/OpenHABRule.md at master · obones/ohab-weather-display · GitHub