[SOLVED] Simple group forEach fails with NULL exception, why?

I have a rather simple rule that should forward a global temperature setpoint for my radiators to each Z-Wave thermostat. Each Z-Wave thermostat has a setpoint item (type Number) that is a member of the group “group_setpoint”. The rule is called whenever I change my global setpoint item via Basic UI or other means.

rule "Temperature setpoint changed"
when
    Item setpoint_global received command
then
    // Forward new temperature setpoint to each radiator
    if (setpoint_global.state != NULL && setpoint_global.state > 0) {
        logInfo("heating.rules", "Setpoint changed to " +  setpoint_global.state.toString + "°C")
        group_setpoint.members.forEach[ setpoint_item | {
            setpoint_item.sendCommand(setpoint_global.state)
        }]
    }
end

The “logInfo” line shows up correctly in my log, so up until then the rule is working fine.
However, then I get the following exception, and I can’t figure out why:

Rule 'Temperature setpoint changed': Could not invoke method: org.eclipse.smarthome.model.script.actions.BusEvent.sendCommand(org.eclipse.smarthome.core.items.Item,java.lang.String) on instance: null

Using “sendCommand(setpoint_item, setpoint_global.state)” instead does not work and checking setpoint_item for NULL also does not work. And I don’t understand at all why setpoint_item could be null in the first place.

Can anyone shed some light on this? Thank you very much!

I think one of your group items is NULL.

This leads me to a question.

How can I catch these NULL and continue with all the other items in the group.

Try that:

            setpoint_item.sendCommand(setpoint_global.state as Number)

or

            setpoint_item.sendCommand(setpoint_global.state.toString)

Thank you very much, this seems to have solved the problem :grinning:

But I still don’t understand why this would be required and why it would result in a NULL exception.
The exception messages in the log always seem to be rather misleading… :roll_eyes:

Yes they can be cryptic.

In your case, the setpoint_item is a genericItem type and the language interpreter has to try and guess what command you are sending it. The best way to avoid that it to send a String as ALL items accept string as commands.

Vincent has you set but I wanted to provide some answers to the questions and explanations not yet addressed.

null != NULL. They are two different things and are two different concepts within OH. So please do not use NULL when the error is actually about null because it can mislead those who are trying to help you.

NULL is a state that Items get initialized to when they are first loaded into OH.

null and NullPointerExceptions in OH Rules almost always are caused by a type problem. In this case, as Vincent provided, the Rules engine just needed a little bit of help to figure out what type the states are that you are working with.

You are most likely correct. This is the error that one sees often when trying to cast the state of an Item that is NULL to Number or the like.

One of the really big problems with the Rules DSL is you cannot catch this exception. When type exceptions occur like this your Rule gets killed immediately.

So what you need to do is filter out the Items that are NULL before the forEach.

group_setpoint.members.filter[ setpoint_item | setpoint_item.state != NULL ] forEach[ setpoint_item | ...

@knitrupf, note that the { } is redundant and not needed inside the .

1 Like

Thank you Rich for your very detailed explanation! This is very much appreciated!

I was always wondering why sometimes NULL and other times null was used.
Now I know and will not fall into that particular trap again.
Unfortunately, the openHAB rule engine still offers a nearly unlimited number of other traps to fall into :laughing:

Okay, I get this (now). But I still think the error message here is plain wrong. It should have complained that it couldn’t decide which overloaded version of “sendCommand” it should call or something like that.
Telling me it could not call sendCommand on a null instance send me on a wild goose chase instead, since “setpoint_item” couldn’t really be null.

real good to know thanks!