Error when resetting timer

I am trying to create a rule that switches on the lights in the kitchen once it detects motion only at night. After 5 minutes of no motion the light gets turned back off. New motion resets that timer. I am using openhab 2.

My rule already switches on the lights successfully but I get an error when the timer code runs that should switch off the light.

Rule:

    var Timer offTimer = null
    var Integer offDelay = 5

    rule "Switch on kitchen lights when detecting motion at night"
    when
        Item molganKueche received update OPEN
    then 
    	if(nightTime.state == ON) { // is night
        	logDebug("Motion", "Turning on lights in kitchen")
        	sendCommand(LichtKuecheUntenOn, ON)

        	if (offTimer == null) {
        		logDebug("Motion", "Creating new timer")
    	    	offTimer = createTimer(now.plusMinutes(offDelay)) [|
    	            logDebug("Motion", "Turning lights in kitchen back off")
    	            offTimer.cancel()
    	            offTimer = null
    	            sendCommand(molganKueche, OFF)
    	            sendCommand(LichtKuecheUntenOn, OFF)
    	        ]
    	    } else {
    	    	offTimer.reschedule(now.plusMinutes(offDelay))	
    	    }
    	}
    end

Where molganKueche is the motion sensor, LichtKuecheUntenOn is the light to turn on/off and nightTime is a switch that get turned on at night.

I get this error:

    19:02:56.380 [ERROR] [org.quartz.core.JobRunShell         ] - Job DEFAULT.2017-08-14T19:02:17.501+02:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
      logDebug(<XStringLiteralImpl>,<XStringLiteralImpl>)
      <null>.offTimer = <XNullLiteralImplCustom>
      sendCommand(<XFeatureCallImplCustom>,<XFeatureCallImplCustom>)
      sendCommand(<XFeatureCallImplCustom>,<XFeatureCallImplCustom>)
    } ] threw an unhandled Exception:
    java.lang.NullPointerException: Cannot assign value to field: KitchenRules.offTimer on null instance
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._assignValueTo(XbaseInterpreter.java:1249)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter._assignValueTo(ScriptInterpreter.java:188)[130:org.eclipse.smarthome.model.script:0.9.0.b5]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.assignValueTo(XbaseInterpreter.java:1220)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:1212)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:215)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:203)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:446)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:227)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:203)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:189)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at com.sun.proxy.$Proxy118.apply(Unknown Source)[:]
            at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:44)[130:org.eclipse.smarthome.model.script:0.9.0.b5]
            at org.quartz.core.JobRunShell.run(JobRunShell.java:202)[105:org.eclipse.smarthome.core.scheduler:0.9.0.b5]
            at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)[105:org.eclipse.smarthome.core.scheduler:0.9.0.b5]
    19:02:56.407 [ERROR] [org.quartz.core.ErrorLogger         ] - Job (DEFAULT.2017-08-14T19:02:17.501+02:00: Proxy for org.eclipse.xtext.xbase.lib.Procedures$Procedure0: [ | {
      logDebug(<XStringLiteralImpl>,<XStringLiteralImpl>)
      <null>.offTimer = <XNullLiteralImplCustom>
      sendCommand(<XFeatureCallImplCustom>,<XFeatureCallImplCustom>)
      sendCommand(<XFeatureCallImplCustom>,<XFeatureCallImplCustom>)
    } ] threw an exception.
    org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.NullPointerException: Cannot assign value to field: KitchenRules.offTimer on null instance]
            at org.quartz.core.JobRunShell.run(JobRunShell.java:213)[105:org.eclipse.smarthome.core.scheduler:0.9.0.b5]
            at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)[105:org.eclipse.smarthome.core.scheduler:0.9.0.b5]
    Caused by: java.lang.NullPointerException: Cannot assign value to field: KitchenRules.offTimer on null instance
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._assignValueTo(XbaseInterpreter.java:1249)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter._assignValueTo(ScriptInterpreter.java:188)[130:org.eclipse.smarthome.model.script:0.9.0.b5]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.assignValueTo(XbaseInterpreter.java:1220)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:1212)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:215)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:203)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:446)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.doEvaluate(XbaseInterpreter.java:227)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.internalEvaluate(XbaseInterpreter.java:203)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.evaluate(XbaseInterpreter.java:189)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.ClosureInvocationHandler.doInvoke(ClosureInvocationHandler.java:46)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at org.eclipse.xtext.xbase.interpreter.impl.AbstractClosureInvocationHandler.invoke(AbstractClosureInvocationHandler.java:29)[146:org.eclipse.xtext.xbase:2.9.2.v20160428-1452]
            at com.sun.proxy.$Proxy118.apply(Unknown Source)[:]
            at org.eclipse.smarthome.model.script.internal.actions.TimerExecutionJob.execute(TimerExecutionJob.java:44)[130:org.eclipse.smarthome.model.script:0.9.0.b5]
            at org.quartz.core.JobRunShell.run(JobRunShell.java:202)[105:org.eclipse.smarthome.core.scheduler:0.9.0.b5]
            ... 1 more

Why is that? I also do not see any of my debug statements in the openhab log? What do I have to change to see them?
Thanks for any help!

I believe canceling the timer and setting it null inside the timer is causing your problem…

Thanks, looks like you are right!

I changed my code to this and it seems to be mostly working.

var Timer offTimer = null
var Integer offDelay = 5

rule "Switch on kitchen lights when detecting motion at night"
when
    Item molganKueche received update OPEN
then 
	if(nightTime.state == ON) { // is night
    	logDebug("Motion", "Turning on lights in kitchen")
    	sendCommand(LichtKuecheObenOn, ON)

    	if (offTimer == null || offTimer.hasTerminated) {
    		logDebug("Motion", "Creating new timer")
	    	offTimer = createTimer(now.plusMinutes(offDelay)) [|
	            logDebug("Motion", "Turning lights in kitchen back off")
	            offTimer.cancel()
	            sendCommand(molganKueche, CLOSED)
	            sendCommand(LichtKuecheObenOn, OFF)
	        ]
	    } else {
	    	offTimer.reschedule(now.plusMinutes(offDelay))	
	    }
	}
end

The state of the motion sensor changes to CLOSED but I still get this error:

22:28:17.981 [ERROR] [ome.core.thing.internal.ThingManager] - Exception occurred while calling handler: java.lang.IllegalArgumentException: Passed command: CLOSED is not an OpenClose command
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: Passed command: CLOSED is not an OpenClose command
at org.eclipse.smarthome.core.common.SafeMethodCaller.executeDirectly(SafeMethodCaller.java:220)[99:org.eclipse.smarthome.core:0.9.0.b5]
at org.eclipse.smarthome.core.common.SafeMethodCaller.callAsynchronous(SafeMethodCaller.java:189)[99:org.eclipse.smarthome.core:0.9.0.b5]
at org.eclipse.smarthome.core.common.SafeMethodCaller.call(SafeMethodCaller.java:83)[99:org.eclipse.smarthome.core:0.9.0.b5]
at org.eclipse.smarthome.core.common.SafeMethodCaller.call(SafeMethodCaller.java:67)[99:org.eclipse.smarthome.core:0.9.0.b5]
at org.eclipse.smarthome.core.thing.internal.ThingManager.receiveCommand(ThingManager.java:374)[106:org.eclipse.smarthome.core.thing:0.9.0.b5]
at org.eclipse.smarthome.core.items.events.AbstractItemEventSubscriber.receive(AbstractItemEventSubscriber.java:47)[99:org.eclipse.smarthome.core:0.9.0.b5]
at org.eclipse.smarthome.core.internal.events.OSGiEventManager$1.call(OSGiEventManager.java:192)[99:org.eclipse.smarthome.core:0.9.0.b5]
at org.eclipse.smarthome.core.internal.events.OSGiEventManager$1.call(OSGiEventManager.java:1)[99:org.eclipse.smarthome.core:0.9.0.b5]
at org.eclipse.smarthome.core.common.SafeMethodCaller$CallableWrapper.call(SafeMethodCaller.java:181)[99:org.eclipse.smarthome.core:0.9.0.b5]
at java.util.concurrent.FutureTask.run(FutureTask.java:266)[:1.8.0_131]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)[:1.8.0_131]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)[:1.8.0_131]
at java.lang.Thread.run(Thread.java:748)[:1.8.0_131]
Caused by: java.lang.IllegalArgumentException: Passed command: CLOSED is not an OpenClose command
at org.openhab.binding.mysensors.converter.MySensorsOpenCloseTypeConverter.fromCommand(MySensorsOpenCloseTypeConverter.java:44)[190:org.openhab.binding.mysensors:2.2.0.201707241115]
at org.openhab.binding.mysensors.handler.MySensorsThingHandler.handleCommand(MySensorsThingHandler.java:165)[190:org.openhab.binding.mysensors:2.2.0.201707241115]
at org.eclipse.smarthome.core.thing.internal.ThingManager$4.call(ThingManager.java:377)[106:org.eclipse.smarthome.core.thing:0.9.0.b5]
at org.eclipse.smarthome.core.thing.internal.ThingManager$4.call(ThingManager.java:1)[106:org.eclipse.smarthome.core.thing:0.9.0.b5]
at org.eclipse.smarthome.core.common.SafeMethodCaller.executeDirectly(SafeMethodCaller.java:218)[99:org.eclipse.smarthome.core:0.9.0.b5]

Any idea why?

You probably shouldn’t send a “command” (CLOSED) to the motion sensor, these normally reset themself back to CLOSED after X amount of time (depends on the motion sensor). However, if you really want to change the status of the sensor use postupdate, like this: postUpdate(molganKueche, CLOSED)

It’s probably too late now that the rule is mostly working for you, but for future readers, this entire behavior can be reduced to:

Items:

Switch Light_Timer {expire="5m,command=OFF"}

Rules:

rule "Switch on kitchen lights when detecting motion at night"
when
    Item molganKueche received update OPEN
then
    if(nightTime.state == ON) {
        logDebug("Motion", "Turning on lights in kitchen")
        LichtKeucheUntenOn.sendCommand(ON)
        Light_Timer.sendCommand(ON)
    }
end

rule "Kitchen light timed out"
when
    Item Light_Timer received command OFF
then
    logDebug("Motion", "Turning lights in kitchen back off")
    LichtKeucheUntenOn.sendCommand(OFF)
    molganKueche.postUpdate(CLOSED)
end

See

3 Likes

Thank you @rlkoshak. It is working just fine now with my version (although I split the motion part and the reset of the light into 2 rules) but I will keep your method in mind. Although I must say its not that much cleaner imho.

Well, if having fewer lines of code, fewer nested clauses and the nesting is shallower (one nesting verses 3), and the removal of bookkeeping code where you have to check the timer, turn it off, set it to null, etc doesn’t fit your definition of cleaner then we have a very different definition for clean code.

2 Likes