NULL
null != NULL
NULL is a special state indicating the Item has an uninitialized state. And you would get the null error above if you tried to actitem.state as Number if actitem.state == NULL.
Scanning throught the Rule… (not everything below is relevant to the error).
Why the Thread::sleep?
val NumberItem actitem = triggeringItem as NumberItem
Are all the members of gActTemp of type NumerItem?
if (actitem !== null)
This will never happen. triggeringItem will always be set to the Item that triggered the Rule. Since this Rule can only be triggered by a change to an Item, triggeringItem will never be null.
val NumberItem setitem = gSetTemp.members.filter[ i | i.name==String::format("%s_SETTEMP",actitem.name.split("_").get(0)) ].last
This is more a matter of style, but it would be shorter to use findFirst and string concatination:
val NumberItem setitem = gSetTemp.members.findFirst[ i | i.name = actitem.name.split("_").get(0) + "_SETTEMP" ]
if(actitem.state !== null && setitem.state !== null) {
This also can never be the case. If you have a not null Item, the Item will always have a State. But that State may be NULL which cannot be cast to a DecimalType.
Again, NULL != null. They are not the same thing.
Over all, this Rule could be simplified using Design Pattern: How to Structure a Rule.
rule "calc diff temp"
when
Member of gActTemp changed
then
val actitem = triggeringItem // we don't really need to cast this to a NumberItem
val setitem = gSetTemp.members.findFirst[ i | i.name == actitem.name.split("_").get(0) + "_SETTEMP" ]
val diffitem = gDiffTemp.members.findFirst[ i | i.name == actitem.name.split("_").get(0) + "_DIFFTEMP"]
// skip the rule if the actitem changed to NULL
if(actitem.state == NULL){
logInfo(logger, "%s's state is NULL!", actitem.name)
return;
}
// skip the rule if setitem or diffitem were not found in their respective Groups
if(setitem === null || diffitem == null){
logInfo(logger, "Could not find setitem and/or diffitem")
return;
}
// skip the rule if either the associated setitem and diffitem's states are NULL
if(setitem.state == NULL || diffitem.state == NULL){
logInfo(logger, "One of setitem or diffitem's state is NULL:\n setitem = %s\n diffitem = %s", setitem.state, diffitem.state)
return;
}
// at this point we have all three relevant Items and know their states are not NULL
var Number diff = actitem.state - setitem.state // it should be able to do this without casting
diffitem.postUpdate(diff)
end