[SOLVED] Error: Rule '<rulename>': null

I receive a strange error from time to time i am struggling to find a reason within my rule.

I have three groups for a bunch of thermostats. gActTemp contains all current temperature readings, gSetTemp contains all target temperatures and a group of unbound Numbers contains the diff (gDiffTemp).

The rule triggers on a update of gActTemp, finds the last changed temperature, chooses the corresponding target & diff items and calculates the difference between current and target temperature again.

All my items are named correctly, and the error is not existing regularly. What is even stranger about it, if i uncomment the three logInfo’s, the error is at least from my mind no longer exisiting.

I hope any of the rule experts may help. Thanks.

This is the rule:

rule "calc diff temp"
	Item gActTemp received update
    // logInfo("heizung", "sleep")
	val NumberItem actitem = gActTemp.members.filter[t|t.lastUpdate("mapdb") !== null].sortBy[lastUpdate("mapdb")].last
    if (actitem !== null) 
        val NumberItem setitem = gSetTemp.members.filter[i|i.name==String::format("%s_SETTEMP",actitem.name.split("_").get(0))].last
        // logInfo("heizung", setitem.name)
        val NumberItem diffitem = gDiffTemp.members.filter[i|i.name==String::format("%s_DIFFTEMP",actitem.name.split("_").get(0))].last
        // logInfo("heizung", diffitem.name)

        if (setitem !== null && diffitem !== null) 
            var Number diff = (actitem.state as DecimalType) - (setitem.state as DecimalType)
            logError("heizung", String::format("SET or DIFF undefined: %s", actitem.name))
    } else {
        logError("heizung", "ACT undefined.")

And this is the log:

2017-12-16 21:59:45.117 [GroupItemStateChangedEvent] - gActTemp changed from 22.08 to 22.07 through B1HK_ACTUALTEMP

2017-12-16 21:59:45.123 [vent.ItemStateChangedEvent] - B1HK_ACTUALTEMP changed from 21.00 to 20.90

==> /var/log/openhab2/openhab.log <==

2017-12-16 21:59:45.578 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'calc diff temp': null

2017-12-16 21:59:45.593 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'calc diff temp': null

==> /var/log/openhab2/events.log <==

2017-12-16 21:59:45.779 [vent.ItemStateChangedEvent] - B1HK_DIFFTEMP changed from 4.00 to 3.90

2017-12-16 21:59:45.782 [GroupItemStateChangedEvent] - gDiffTemp changed from 2.96 to 2.95 through B1HK_DIFFTEMP

This is the updated rule, works like a charm:

rule "calc diff temp"
    Item AZHK_ACTUALTEMP changed or
    Item AZWT_ACTUALTEMP changed or 
    Item ArHK_ACTUALTEMP changed or 
    Item ArWT_ACTUALTEMP changed or 
    Item B1HK_ACTUALTEMP changed or 
    Item B1WT_ACTUALTEMP changed or 
    Item F2HK_ACTUALTEMP changed or
    Item FESHK_ACTUALTEMP changed or
    Item FEWHK_ACTUALTEMP changed or
    Item FEWT_ACTUALTEMP changed or
    Item GZHK_ACTUALTEMP changed or
    Item KUHK_ACTUALTEMP changed or
    Item KUWT_ACTUALTEMP changed or
    Item LeHK_ACTUALTEMP changed or
    Item LeWT_ACTUALTEMP changed or
    Item MiHK_ACTUALTEMP changed or
    Item MiWT_ACTUALTEMP changed or
    Item SZHK_ACTUALTEMP changed or
    Item SZWT_ACTUALTEMP changed or
    Item T1HK_ACTUALTEMP changed or
    Item TEHK_ACTUALTEMP changed or
    Item WZNHK_ACTUALTEMP changed or
    Item WZSHK_ACTUALTEMP changed or
    Item WZWT_ACTUALTEMP changed
	val NumberItem actitem = triggeringItem
    if (actitem !== null) 
        val NumberItem setitem = gSetTemp.members.filter[i|i.name==String::format("%s_SETTEMP",actitem.name.split("_").get(0))].last
        val NumberItem diffitem = gDiffTemp.members.filter[i|i.name==String::format("%s_DIFFTEMP",actitem.name.split("_").get(0))].last

        if (setitem !== null && diffitem !== null) 
            var Number diff = (actitem.state as DecimalType) - (setitem.state as DecimalType)
            logError("heizung", String::format("SET or DIFF undefined: %s", actitem.name))
    } else {
        logError("heizung", "ACT undefined.")

Not quite sure but add the Thread::sleep(100) again.

I had a similar problem. The persistence it not fast enough and due to this the t.lastUpdate(“mapdb”) gives the wrong member of the group.

In the next line the persistance has done its job and you query the wrong item.

Not sure, maybe.

Thanks, i did that already. I experimented with a Thread::sleep of 100, 200 & 300.

From my point of view, this sleep could cause a wrong item to be calculated, but not that “null” - error.

I am quite sure the follwing line of code is the problem.

val NumberItem actitem = gActTemp.members.filter[t|t.lastUpdate("mapdb") !== null].sortBy[lastUpdate("mapdb")].last

I have another rule with that effect and the only thing these rules share is the identification of the triggering item.

The temperature groups contain about 25 items each, the group of the other rule about 50. Are the groups too large perhaps? Does anybody know a hint?

O wow… reading your topic reminded me about an exciting and much needed ESH PR, which I completely forgot about while waiting for it to be included in an OH build…

I just did a test and it works! This is an implicit variable that missed the 2.2 release notes and needs to get into the documentation! @rlkoshak, this may make your day, if you’re not already aware of triggeringItem!

My suggestion to correct your rule…
1. Update to a recent OH build, if you’re not already
2. Add rule triggers for each item in gActTemp (triggeringItem is not yet implemented for groups :confused:)
3. Remove the first line in the rule action
4. Replace actitem with triggeringItem


Brilliant! Thanks a lot!

That is one of the most exciting features of openHAB 2.2. This needs to go to the documentation!

( Now this needs to be implemented for groups! :smiley: )

1 Like

I realized after some more testing and reading that triggeringItem is not yet implemented for groups, so the triggers have to be the individual items. I’ve edited my original post.

I agree!

This is a much awaited and much requested feature that I had no ideas was part of the 2.2 release. Thanks for the heads up. Now I need to figure out the full impact of this to all my DP postings. The fact that it doesn’t work with Groups is somewhat of a bummer but its better than nothing by a long shot.

An issue has already been created to add it to the docs.

1 Like

I am glad that the “triggeringItem” addition is already proving useful. I wish I had gotten the group support in before the OH release, but caught up with other things. I have created a new PR in ESH to handle groups, but it will take a little time to (hopefully) get approved and make it into OH.


Wow. Not only did it not go to the release notes, it didn’t even get it’s own thread. This little feature really could make a difference in my rules!

Thank you!

The current implementation without groups already removes ugly and problematic code from some of my rules.

Whenever the groups are done, i just need to switch to a more comfortable configuration.

The first throw is already a giant step to simpler rules.

Does anyone know when the group triggeringItem will be avaiable in the snapshot builds?

When it is finished being implemented, the changes have been merged into ESH, ESH releases a new baseline, and kai merges that release into OH.

I’m already using it in OH2.2, and it’s in the docs. I believe it’s already official:

No, it’s not.

@rockster was asking about the group extension of the “triggeringItem” stuff. The item based triggers are already in the release, but not the group extension (“MemberOf AGroup changed”).

You’re right, I didn’t read well.

thanks, i did not know that it depends on the esh release

Sorry to revive this thread from six months ago but I stumbled on it just now as I am having the exact same problem. Joachim, did you ever get rid of your null errors?

After the release of “Member of Group” and “triggeringItem” I did a whole re-write of my embarrasingly repetitive code, however I am now getting these sporadic null errors in the log even though I don’t think there is anything wrong fundamentally there. I suspected race conditions as the hardware is a 12 core 24 thread xeon server so I sprinkled a few Thread::sleep(100) in there but that has not changed anything…

Here is a sample rule where the error came up recently:

rule "Update IsHome"

    Member of gDistanceFromHome changed
    val distanceFromHomeItem = triggeringItem
    val userCode = triggeringItem.name.split("_").get(0)
    val isHomeName = userCode + "_IsHome"
    val isHomeItem = gIsHome.members.filter[ t|t.name == isHomeName ].head as NumberItem
    val rSSIName = userCode + "_iPhoneUnifiRSSI"
    val rSSIItem = gUnifiRSSI.members.filter[ t|t.name == rSSIName ].head as NumberItem

    if (distanceFromHomeItem.state <= 50) {
        if (isHomeItem.state != 1) {isHomeItem.postUpdate(1)}}
    else if (!(rSSIItem.state >= rSSIThreshold)) {
        if (isHomeItem.state != 0) {isHomeItem.postUpdate(0)}}

Here are the items:

Group       gDistanceFromHome   "Distance From Home"                    (gPresence)
Number      YE_DistanceFromHome "Yetkin's Distance From Home [%.0f]"    (gDistanceFromHome)
Number      PI_DistanceFromHome "Pinar's Distance From Home [%.0f]"     (gDistanceFromHome)
Number      CA_DistanceFromHome "Car's Distance From Home [%.0f]"       (gDistanceFromHome)

Group       gUnifiRSSI          "Unifi RSSI"                <qualityofservice>  (gPresence)  
Number		YE_iPhoneUnifiRSSI  "Yetkin's iPhone RSSI [%s]" <qualityofservice>	(gUnifiRSSI)	{channel="unifi:client:home:YetkinsiPhoneUnifi:rssi"}
Number		PI_iPhoneUnifiRSSI	"Pinar's iPhone RSSI [%s]"	<qualityofservice>	(gUnifiRSSI)	{channel="unifi:client:home:PinarsiPhoneUnifi:rssi"}
Number		CA_iPhoneUnifiRSSI	"Car's iPhone RSSI [%s]"	<qualityofservice>	(gUnifiRSSI)	{channel="unifi:client:home:CarsiPhoneUnifi:rssi"}

If a user’s distance from home is changed, the rule gets the relevant _IsHome and _UnifiRSSI items, and updates the _IsHome state accordingly.

Sporadically (maybe 3-4 times a day) I get the below in the log file:

2018-06-07 17:57:17.700 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Update IsHome': null

I have checked and checked but cannot find any relevant item whose state is null at the point of execution.

Any thoughts or pointers would be appreciated!


If it is a race condition, sprinkling the Thread::sleeps will only delay when the race condition occurs. It probably won’t address the race condition. And you can only have a race condition if you have two pieces of code running at the same time that need to use the same resource.

That error unfortunately does not always mean that something is null. What it means is the Rules Engine was unable to transform one of the Objects in use into the type that is needed. Most often I see this sort of error when you are assuming that an Item’s state is not NULL (note null != NULL) and try to cast it to some other type.

Add logging statements every other line to find the line that is generating the error in that rule. Then it should be clear what is not in the expected state.

No. These errors still occur. From time to time. The rules are error free. The problem’s origin is the surrounding infrastructure.

Some time ago, i read about the rule engine only executing 5 parallel rules.

Is that correct? If it is, i would suspect this could be the reason.