Using UoM item states in DSL Rules

Hi all,

@rossko57 gave some great examples of working with QuantityTypes that hold Units of Measurement in DSL rules, i.e. here.

One crucial item is missing however, and I have not been able to figure out how to get it to work. How do I use the state of a QuantityType Item in a DSL variable and work with it?

I have an item that is set up as a “Number:Volume” number type item using m³ as the unit.

I am simply trying to copy it into a variable at the start of my rule and perform some manipulations:

var BWZ = BWZ_Zaehlerstand.state

I would assume that BWZ now hold the state of my item with the unit attached.
I.e. If I do (as in Rossko’s examples)

val BWZ = 33|"m³

My call above should do the same, right (assuming the item’s state is 33 m³)?

And if I now have a second Number:Volume item, that I cast into the variable “Offset”, this should work too:

var Jahr = BWZ - Offset

However, the actual code gives me error messages and the rule won’t work:

[internal.handler.ScriptActionHandler] - Script execution of rule with UID 'bewaesserung-2' failed: Unknown variable or command '-'; line 92, column 20, length 46 in bewaesserung

What still works is to get rid of the units in variables by casting them like so:

var Double BWZ = (BWZ_Zaehlerstand.state as QuantityType<Number>).doubleValue

and simply work without the units in the rest of the code.

However at the end of my rule i then do sendCommands to any updated items without the units attached which is probably not going to be supported in future versions, which got me started on wanting to work properly with the units.

Any idea what I am doing wrong?

Best,

Thomas

Rules DSL is sometimes stupid when it comes to figuring out the types of Objects. This is unfortunate because it tries really hard to be a typeless language.

MyItem.state returns the Item’s state as a State. You know that it’s more than just a State but Rules DSL can’t figure that out on it’s own. And a State Object doesn’t support mathematical operations. So you have to tell it it’s something else by casting it using as.

var BWZ = BWZ_Zaehlerstand.state as QuantityType<?>

I recommend going one step further and specifying the units you want to work with in the rule too. This makes your rules more self documenting and more robust to changes outside the rule.

var BWZ = (BWZ_Zaehlerstand.state as QuantityType<?>).toUnit('m³')

Now you have BWZ as a QuantityType and you know what units the value is.

This is a somewhat overwrought line of code. This line of code:

  1. gets the state of the Item
  2. casts the state of the Item to a QuantityType
  3. pulls a primitive double from the QuantityType
  4. converts that primitive double to a Double Object.

Steps 2-4 are unnecessary and redundant. Just use

var BWZ = BWZ_Zaehlerstand.state as Number

Simple as that.

Note, it’s bad to force the types of variables in Rules DSL. Even though it’s bad at detecting types sometimes, it causes even more problems to define the types of Items unless necessary. It’s really bad to use primitives in Rules DSL. It can add minutes to the amount of time required to load and parse a single rule, even on a fast machine.

Note2: If you were able to swap the arguments to your subtraction, Rules DSL probably would have been able to figure out that BWZ was a QuantityType without your explicitly casting it.

val Jahr = Offset - BWZ

This is because Rules DSL takes it’s type hints from the first operand of any operation and tries to force the rest of the operands to become compatible.

Maybe don’t show some parts of code but the complete code (at least the essential part).
Let’s say there are two Items

val BWZ = BWZ_Zaehlerstand.state as QuantityType<Volume>
val Offset = Offset.state as QuantityType<Volume>
val myVol = BWZ - Offset
logInfo("quanType","BWZ ({}) - Offset ({}) = {}",BWZ, Offset, myVol)

should work, also

val BWZ = BWZ_Zaehlerstand.state as QuantityType<Volume>
val Offset = 33|m³ as QuantityType<Volume>
val myVol = BWZ - Offset
logInfo("quanType","BWZ ({}) - Offset ({}) = {}",BWZ, Offset, myVol)

should work (be aware that there is no quote around the QuantityType.
There are other Quantities which have to be set in quotes, so sometimes it might be a little bit tricky.

The cast here is not necessary. It’s already clear that it’s a QuantityType to Rules DSL through the | operator.

It never hurts to put the unit in quotes I think. But indeed there are some units that require the quotes because the unit includes math operations so it can hurt not to.

33|m³ and "33|m³" will both work. But 5|Bq/m³ will not and the quotes are required because of the / operator being a part of the unit: "5|Bq/m³".

1 Like

Excellent, very helpful, gents! This pointed me into the right direction and I will hopefully be able to change my rules accordingly.