Strange if/null behaviour

  • openHAB version: 2.5M5

I am scratching my head for this. Here’s an excerpt of the rule:

    val baseName = "Hallway" // Simplified for this excerpt
    var itemColor = null
    try {
        itemColor = ScriptServiceUtil.getItemRegistry.getItem(baseName + "_Light_Color")
    } catch (Throwable t) {} // is there a better way?

    if (itemColor !== null) {
        itemColor.sendCommand("03030303") // <<=== This is where the error occurred
    }

The above code when executed, will trigger this error message:

16:02:13.876 [ERROR] [untime.internal.engine.RuleEngineImpl] - Rule 'Night Light PIR': An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.actions.BusEvent.sendCommand(java.lang.String,java.lang.String) on instance: null

Why is the instance null when it passed the if (itemColor !== null) ?

A separate question: Is there a way to check for the existence of an item without resorting to try / except to catch the exception?

Could it be that it’s “weird” because the compiler does not know what the type is until its too late?

It knows it’s going to be a string.

I have laptop “hunting” group with said items and do a findFirst on that group. Simply returns null if not found.

As Crispin indicated, if you initialize a variable to null, you have to provide the type because they’re has nothing to tell the rules engine what type it is.

You need to provide more context but I suspect the answer in Rules DSL is no. But I don’t know what ScriptServiceUtil.getItemRegistry.getItem(itemName) returns when the item by that name doesn’t exist. Maybe it just returns null. See Design Pattern: Associated Items for details.

There is a alternative to “find Item by name string”. Before ScriptServiceUtil, we used to put Items in Groups and search Group by name. If there is no such member, you get a tidy null result and no error, and can deal with that in code
I still use this method where some Item may or may not have a “helper” or “associated” companion Item

EDIT - knew there was a previous, found it

I do not think that is a sensible thing to send to a Color Item, shouldn’t there be commas? It will fail with null components when it tries to parse the string?

It would throw an exception. That’s why I enclosed it in a try/catch

What would be the type for a String Item?

The “Color” item is actually just a String type item. It expects a tring in the form of 8 hexadecimal digits, e.g. FFFFFFFF for RGBW values. This is the Thing definition for it:

Thing mqtt:topic:mosquitto:hallway1_light "Hallway Light 1" (mqtt:broker:mosquitto) {
    Channels:
        ...
        Type string : color "Color"		[ stateTopic="stat/hallway1-light/RESULT", transformationPattern="JSONPATH:$.Color", commandTopic="cmnd/hallway1-light/Color" ]
        ...
}

Is there a better way to represent this particular color item?

Thanks to @rossko57 and @CDriver, I think the solution, for now, is using the group find method, although to me it feels a bit dodgy. It would be nicer to have another function, maybe ScriptServiceUtil.getItemRegistry.findItem() ?

Okeydoke.

It’s perfectly reliable. It does depend on you assigning things to the correct Group(s) as part of your design.

EDIT - I’ve never compared performance, it might be interesting;
getItemRegistry must rummage through all Items, though there may be speed-up hashing in bowels of system
Group findFirst in theory need only look through a smaller set of Items, but likely less optimized.

A String Item is a StringItem. The state of a String Item is a StringType .

I think for now, I’m happy with just using try/catch and if the variable needed to be outside the try/catch block, I’d give it an explicit type. If it is only needed inside the try/catch then just create/assign it inside the block.

Knowing getItems() and the group findFirst would come in handy though, thanks!