(Why) is linking two items complex?

Hello,

CC: @ThomDietrich @sjka @rlkoshak

Quite regularly I try to link two items to each other and every time I fail to do this properly at once, why is it so complex and can we improve the error message.

So I have a virtual expring switch and a normal switch:

Switch vExpiringKitchenLight { expire="2m,OFF" }
Switch CoCoKitchenLights "Keukenkastjes" { channel="rfxcom:lighting2:17634398_1:command" }

Intuitively I would expect to link them in one of the following two ways:

rule "synchronize_vExpiringKitchenLight"
when
        Item vExpiringKitchenLight changed
then
    CoCoKitchenLights.sendCommand(vExpiringKitchenLight.state)
end
rule "synchronize_vExpiringKitchenLight"
when
        Item vExpiringKitchenLight changed
then
    sendCommand(CoCoKitchenLights, vExpiringKitchenLight.state)
end

But this did not work with the error:

2017-12-15 21:35:06.038 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'synchronize_vExpiringKitchenLight': An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.actions.BusEvent.sendCommand(org.eclipse.smarthome.core.items.Item,java.lang.String) on instance: null

I do not really understand why and remembered that one of the cases used to work, finally I ended up with:

rule "synchronize_vExpiringKitchenLight"
when
        Item vExpiringKitchenLight changed
then
    var state = vExpiringKitchenLight.state.toString
    CoCoKitchenLights.sendCommand(state)
end

Why does this work and is this the only way it work or is there a more ‘sensible’ way to do this.

And more important and the reason to mention @sjka and @ThomDietrich can we improve error, because I do not even understand what the actual problem with the option above is.

I believe the reason the 2nd rule works for you is because you have correctly converted the state of the switch into String.

This may work, but not sure

rule "synchronize_vExpiringKitchenLight"
when
        Item vExpiringKitchenLight changed
then
    //var state = vExpiringKitchenLight.state.toString
    CoCoKitchenLights.sendCommand(vExpiringKitchenLight.state.toString)
end

I have similar rule that I use as follows:

rule "Match Kitchen Sink light"
  when
    Item FF_Light_KitchenCooking received update
  then
    var String state = FF_Light_KitchenCooking.state.toString()
    sendCommand(FF_Light_KitchenSink, state.upperCase)
    //sendCommand(FF_Light_KitchenSink, ON)
end

Yes but could we maybe kill that intermediate step somehow and or make the error less vague :slight_smile:

Here I found what I remembered:

http://docs.openhab.org/configuration/rules-dsl.html#sendcommand-method-vs-action

So I would expect that the first example should work:

This works

CoCoKitchenLights.sendCommand(vExpiringKitchenLight.state.toString)

I also get it to work like this:

rule "synchronize_vExpiringKitchenLight"
when 
	Item vExpiringKitchenLight changed 
then
    val OnOffType newState = vExpiringKitchenLight.state
    CoCoKitchenLights.sendCommand(newState)
end

And here comes the surprise for me…

rule "synchronize_vExpiringKitchenLight_test"
when 
	Item vExpiringKitchenLight changed 
then
    val OnOffType newState = vExpiringKitchenLight.state
    //CoCoKitchenLights.sendCommand(newState)
	
	logInfo("Synchronize", "About to postUpdate state: " + vExpiringKitchenLight.state)
    postUpdate(CoCoKitchenLights, vExpiringKitchenLight.state)
	logInfo("Synchronize", "postUpdate success, new state: " + CoCoKitchenLights.state)

	logInfo("Synchronize", "About to sendCommand state: " + vExpiringKitchenLight.state)
	sendCommand(CoCoKitchenLights, vExpiringKitchenLight.state)
	logInfo("Synchronize", "sendCommand success, new state: " + CoCoKitchenLights.state)
end
2017-12-15 22:45:13.844 [INFO ] [e.smarthome.model.script.Synchronize] - About to postUpdate state: ON
2017-12-15 22:45:13.844 [INFO ] [e.smarthome.model.script.Synchronize] - postUpdate success, new state: OFF
2017-12-15 22:45:13.844 [INFO ] [e.smarthome.model.script.Synchronize] - About to sendCommand state: ON
2017-12-15 22:45:13.845 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'synchronize_vExpiringKitchenLight_test': An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.actions.BusEvent.sendCommand(org.eclipse.smarthome.core.items.Item,java.lang.String) on instance: null

@ptmuldoon / @hr3 do you happen to run 2.1? Can you test whether this a regression?

CoCoKitchenLights.sendCommand(vExpiringKitchenLight.state.toString)

works in 2.1.0 and 2.2.0 #1139 without messages

Yes, but does the one without the toString work in previous versions? Because in the latest nightly it works for postUpdate but does not work for sendCommand.

Hmmmm.

Both rules gave the same error? I would not have expected that.

I’ve done your first example to work as written, unless perhaps you are seeing the error when the Rule is triggering when vExpiringKitchenLight changes from NULL to ON or OFF. Add a logging statement to print the state of vExpiringKitchenLight.state to that version of the rule to see if that is the case.

If it is you can deal with it by changing your trigger to

Item vExpiringKitchenLight changed from ON to OFF or
Item vExpiringKitchenLight changed from OFF to ON

The second version of the Rule I’m not surprised might fail. The sendCommand action takes two Strings as arguments and I’ve found that the Rules DSL does not always do a good job of figuring out that it can call toString on States, though I’ve never had problems with Enum Types so it is kind of a mystery why that one failed as well.

So my question is have you simplified this code for posting or is this complete? If it is complete, why not:

Switch CoCoKitchenLights "Keukenastjes: { channel="rfxcom:lighting2:17634398_1:command", expire="2m,OFF" }

and skip the Rule?

I would expect all of the following to work, but only if vExpiringKitchenLight.state != NULL:

CoCoKitchenLights.sendCommand(vExpiringKitchenLight.state)
sendCommand(CoCoKitchenLights, vExpiringKitchenLight.state.toString)

There was an issue to improve error reporting. But realize it is not an easy thing to implement.

I agree, which is why I’m wondering if the state is NULL.

Hmm, that points to it not being an issue with NULL. This does look very much like a regression.

You should file an issue. It should work the same for both Actions.

1 Like

@rlkoshak thanks for copy-pasting my (partially) monologue to a dialog with you :wink:

And of course @hr3 @ptmuldoon thanks for your suggestions!

BTW: my use case is that I want to switch my light normally (directly through openHAB / rules) but if motion is detected I want to enable it for a certain time, with the rule:

rule "Motion in kitchen"
when
    Item ZWaveNode19MotionSensorPIRMotionSensor_SensorBinary changed to ON
then
    if (vTimeOfDay.state.toString  != "DAY") {
        if (Light_Group_Kitchen.state == OFF || vExpiringKitchenLight == ON) {
            vExpiringKitchenLight.sendCommand(ON)
        }
    }
end

Is the short summary: CoCoKitchenLights.sendCommand works, while sendCommand(CoCoKitchenLights,..) doesn’t?

If so, I would consider this a regression, imho both should equally work.

No, that has been known for some time but it seems CoCoKitchenLights.sendCommand also stopped working, if you pass a state to it. I’m having an hard time to get the part of smarthome running locally in debug. And a lot of private things to do today, I’ll have time to look at this tonight :cry:

The following does work on my master of smarthome.

rule "Initialize demo items"
when
  Time cron "*/10 * * * * ? *"
then  
  DemoSwitch.sendCommand(ON)
  DemoContact.sendCommand(OPEN)
  
  logInfo("Test", "Item DemoContact:   " + DemoContact.state)
  DemoContact.postUpdate(DemoContact.state)
  logInfo("Test", "postUpdate DemoContact success")
    
  logInfo("Test", "Item DemoSwitch:   " + DemoSwitch.state)
  DemoSwitch.postUpdate(DemoSwitch.state)
  logInfo("Test", "postUpdate DemoSwitch success")
  
  logInfo("Test", "Item DemoContact:   " + DemoContact.state)
  DemoContact.sendCommand(DemoContact.state)
  logInfo("Test", "sendCommand DemoContact success")
    
  logInfo("Test", "Item DemoSwitch:   " + DemoSwitch.state)
  DemoSwitch.sendCommand(DemoSwitch.state) 
  logInfo("Test", "sendCommand DemoSwitch success")
end

But this does not work in latest snapshot:

rule "synchronize_vExpiringKitchenLight_test"
when 
	Item vExpiringKitchenLight changed 
then
    val OnOffType newState = vExpiringKitchenLight.state
    //CoCoKitchenLights.sendCommand(newState)
	
	// resend own state -> FAILS here
	CoCoKitchenLights.sendCommand(CoCoKitchenLights.state)

	logInfo("Synchronize", "About to postUpdate state: " + vExpiringKitchenLight.state)
    CoCoKitchenLights.postUpdate(vExpiringKitchenLight.state)
	logInfo("Synchronize", "postUpdate success, new state: " + CoCoKitchenLights.state)

	logInfo("Synchronize", "About to sendCommand state: " + vExpiringKitchenLight.state)
	CoCoKitchenLights.sendCommand(vExpiringKitchenLight.state)
        //  --> FAILS here
	logInfo("Synchronize", "sendCommand success, new state: " + CoCoKitchenLights.state)
end

And my wife and kids and other people are waiting for me…

And now (after a restart?) it works… :face_with_raised_eyebrow: