[SOLVED] Error in rule "cannot invoke method public abstract boolean"

hello community,

i have a rule with this if function:

if((timer === null && flagItemsunset.state == ON) || (timer === null && Light_Sensor_Outdoor.state <= 10))

now i will add an virtual switch for manuall stop the rule.
in words, if flagItemsunset is on ore Light_Sensore_Outdoore is less then 10 and the dummyswitch is ON, than do …

i have tried this code:

if(((timer === null && flagItemsunset.state == ON) || (timer === null && Light_Sensor_Outdoor.state <= 10))&& (timer === null && AllMotionDevices.state == ON))

when the dummy switch is on, it works, is the dummy switch off, it works also but i get the following error:

[ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Licht Gaestezimmer bei Bewegung Einschalten': cannot invoke method public abstract boolean org.eclipse.smarthome.model.script.actions.Timer.reschedule(org.joda.time.base.AbstractInstant) on null

this is my rule at the moment:

var Timer timer = null
rule "Licht Gaestezimmer bei Bewegung Einschalten"
when
    Item Motion_FF_Child received update ON
then
       if((timer === null && flagItemsunset.state == ON) || (timer === null && Light_Sensor_Outdoor.state <= 10)) {
        var time=Integer::parseInt(GaestezimmerLichtDauer.state.toString)
        logInfo("FILE", "Setting to ON and creating timer "+time.toString)
        Light_FF_Child_Ceiling.sendCommand(ON)
        Spot_Gaestezimmer.sendCommand(ON)
        timer = createTimer(now.plusMinutes(time), [|
            logInfo("FILE", "Timer expired and setting to OFF")
            Spot_Gaestezimmer.sendCommand(OFF)
            Motion_FF_Child.postUpdate(OFF)
            Light_FF_Child_Ceiling.sendCommand(OFF)
            timer = null
        ])
    } else {
        logInfo("FILE", "Timer rescheduled")
        timer.reschedule(now.plusMinutes(2))
        
    }
end

The problem is that by your logic the else part of the rule can be accessed if the timer is null, therefore:

    } else if (timer !== null) {
        logInfo("FILE", "Timer rescheduled")
        timer.reschedule(now.plusMinutes(2))
    }

Really?

if((timer === null && flagItemsunset.state == ON) || (timer === null && Light_Sensor_Outdoor.state <= 10)) {

===>

if(
   (timer === null && flagItemsunset.state == ON) || 
   (timer === null && Light_Sensor_Outdoor.state <= 10)
                                                       ) {

===>

if(
   timer === null && (
                      flagItemsunset.state == ON || 
                      Light_Sensor_Outdoor.state <= 10)
                                                       ) {

===>

if(timer === null && (flagItemsunset.state == ON || Light_Sensor_Outdoor.state <= 10)) {

Another thing is: As you check if it’s sunset or darker than some threshold, how should the lights react if the sun raises? shall the lights keep being on or should they be shutdown? The rule would be slightly different:

if(flagItemsunset.state == ON || Light_Sensor_Outdoor.state <= 10) {
    if(timer === null) {
//switch light on, create timer
    } else {
//reschedule timer
    }
}

i have tried this, but than the rule doesnt work anymore.

i have the light sensor only if it is a rainy day or thunderstorms.
it is ok if the light comes on just because a cloud passes by.
I just want to have an additional switch that disables the rule, maybe i need it sometimes

Hello, Martin,

I had the same mistake in a similar rule. After some testing, I was able to solve it by following Vincent’s train of thought. Here’s my code, I hope it helps.

var Timer Motion_Flur_timer = null
val int timeoutSeconds = 60 // choose an appropriate value	

rule "FlurLicht an"
when 
  Item HueSensor_2_Motion changed to ON
	then
	if (Motion_Flur_timer === null && (vEsWirdNacht.state == ON && gFlur.state == OFF )) { 
	logInfo("FlurBewegung","--> Bewegung nach Sonnenuntergang im Flur. Schalte Licht ein")
	gFlur.sendCommand (1)
	Motion_Flur_timer = createTimer(now.plusSeconds(timeoutSeconds ), [|
				gFlur.sendCommand(OFF)
	      logInfo("FlurLicht","--> Schalte Licht im Flur wieder aus")
      Motion_Flur_timer = null
  ])
  } 
  else if (vEsWirdNacht.state == ON) {
		Motion_Flur_timer.reschedule(now.plusSeconds(timeoutSeconds ))
    logInfo("FlurLicht","--> Weitere Bewegung im Flur, Timer erneut auf 60 Sekunden gesetzt")
  }
	else {
	  logInfo("FlurLicht","--> Bewegung erkannt, aber noch Tag: Nichts zu tun")
	}
 end

VG
Dave

1 Like

Had the same error here. Was also related to rescheduling a timer that was set to ‘null’. My code here for a motion detector. Make sure to take a good look at the ‘else’ clause.

rule "Verlichting berging (MOTION ON)"
when
    Channel "mqtt:topic:MyMQTTBroker:GPIO06:GPIO06_IN9" triggered ON
then 
    logInfo("Verlichting berging", "Motion detected in berging (MOTION)")

    var Timeout = 60    // Timeout for motion sensor in seconds

    // Only turn on the light using motion if:
    //  - The previous timer has expired
    //  - The previous timer is null
    //  - The light was not already turned on manually

    // Do not confuse NULL with null (NULL = unitialized, null = does not exist)
    // When comparing with null, use === or !==. For all the rest use == or !=
    if(TimerVerlichtingBerging === null && VerlichtingBerging == 1) 
    {
        logInfo("Verlichting berging", "Verlichting berging ON (MOTION)")
        Led17_4.sendCommand(ON)
        Led18_4.sendCommand(ON)
        Led10_4.sendCommand(ON)
        GPIO05_OUT02.sendCommand(ON)
        VerlichtingBerging = 0

        TimerVerlichtingBerging = createTimer(now.plusSeconds(Timeout), 
        [
            logInfo("Verlichting berging", "Verlichting berging OFF (MOTION TIMER)")
            Led17_4.sendCommand(OFF)
            Led18_4.sendCommand(OFF)
            Led10_4.sendCommand(OFF)
            GPIO05_OUT02.sendCommand(OFF)
            VerlichtingBerging = 1
            TimerVerlichtingBerging = null
        ])
    }
    else if (TimerVerlichtingBerging !== null && VerlichtingBerging == 0)
    {
        logInfo("Verlichting berging", "Verlichting berging (Reschedule MOTION TIMER)")
        TimerVerlichtingBerging.reschedule(now.plusSeconds(Timeout))
    }
end
1 Like

thanks to all for the infos :slight_smile:

this is now my working rule:

var Timer timer = null
rule "Licht Gaestezimmer bei Bewegung Einschalten"
when
    Item Motion_FF_Child received update ON
then
       if((timer === null && flagItemsunset.state == ON && Bewegungsmelder.state == ON) || 
       //(timer === null && Light_Sensor_Outdoor.state <= 60 && Bewegungsmelder.state == ON) || 
       (timer === null && Motion_FF_Child_illuminance.state <= 40 && Bewegungsmelder.state == ON)) {
        var time=Integer::parseInt(GaestezimmerLichtDauer.state.toString)
        logInfo("FILE", "Setting to ON and creating timer "+time.toString)
        Light_FF_Child_Ceiling.sendCommand(ON)
        Spot_Gaestezimmer.sendCommand(ON)
        timer = createTimer(now.plusMinutes(time), [|
            logInfo("FILE", "Timer expired and setting to OFF")
            Spot_Gaestezimmer.sendCommand(OFF)
            Motion_FF_Child.postUpdate(OFF)
            Light_FF_Child_Ceiling.sendCommand(OFF)
            timer = null
        ])
    } 
      else if (timer !== null) {
        logInfo("FILE", "Timer rescheduled")
        timer.reschedule(now.plusMinutes(10))  
    }
      else {
	    logInfo("File","Bewegung erkannt, aber noch Tag oder zu hell: Nichts zu tun")
	}
end