[SOLVED] Timer rule drives me crazy :/ Help welcome

Hi Community,

after long hours of troubleshooting I cannot find the error but as it is a simple rule I would hope you spot it more easily than me.

Rule: Execute a bunch of commands in a given timeframe between 6 AM and 10 AM BUT only fire the rule once and afterwards restrict the execution in this timeframe.

I had a similar rule running successfully but this one I cannot get my head around. Any ideas or spotting of my errors is greatly appreciated, thank you :slight_smile:

My assumption is that my logic of the timer tRun is wrong or the timer does not get updated.
The behaviour is that the timeframe parameters are met but the rule gets executed over and over instead of just once in this timeframe.

var Timer tRun = null
rule "test rule"
	when 
		Item Sensor received update OPEN
	then
		if(tRun === null && (now.getMinuteOfDay > 360 && now.getMinuteOfDay < 600)){
			logWarn("Executing commands")
			tRun = createTimer(now.plusHours(4), [|logWarn("ruleName","Timer Off")])
            Alexa_TTS.sendCommand('Executing commands') 
            Thread::sleep(5000) 
            DenonInput.sendCommand('MPLAY') 
            AlexaTraffic.sendCommand("Traffic") 
            gLobbyLights.sendCommand(ON) 
            gLivingroomLights.sendCommand(ON) 
            gOfficeLights.sendCommand(ON) 
            gKitchenLights.sendCommand(ON) 
            Sonos_Master_Bedroom_Add.sendCommand("RINCON_000E582AC07601400")
            Sonos_Master_Bedroom_Add.sendCommand("RINCON_000E582AC07E01400")
            Sonos_Master_Bedroom_Add.sendCommand("RINCON_B8E93783325201400")
            Sonos_Master_Bedroom_Add.sendCommand("RINCON_B8E9375835EC01400")

            tRun = null

		}
		else {
			logWarn("ruleName", "Job already done")
		}
end

By setting tRun to null your timer will get garbage collected and will not run. Also, between 04:00 and 10:00 it causes the if(tRun ===null ... to be true hence running the commands again and again within that timeframe.
You probably want to avoid the Thread::sleep(5000) and replace it by a timer because that blocks the rule thread for 5 seconds. There’s only a limited amount of rule threads that can be running at the same time (I think 5) so you want your rules to complete as soon as possible to not block any other rules from running.

Set tRun to null when the timer runs:

tRun = createTimer(now.plusHours(4), [|
    logWarn("ruleName","Timer Off")
    tRun = null
])

And have a look at the Time of Day design pattern.

You set tRun to null in one of the last lines, so then all conditions are met a next time the item triggers.

Next to that, you shouldn’t use such long sleeps in your code, you would be better of using a createTimer there as well.

Hey,

thanks for the quick response. I will delete the sleeps and have changed the code to this, removing tRun = null at the end and putting it to the timer above. Is this what you meant?

var Timer tRun = null
rule "test rule"
	when 
		Item Passlobby received update OPEN
	then
		if((now.getMinuteOfDay > 360 && now.getMinuteOfDay < 600)){
			logWarn("testRoutine", "test")
			tRun = createTimer(now.plusHours(4), [|logWarn("ruleName","Timer Off")
            tRun = null
            ])
            Alexa_TTS.sendCommand('test') 
            Thread::sleep(5000) 
            DenonInput.sendCommand('MPLAY') 
            AlexaTraffic.sendCommand("Traffic") 
            gLobbyLights.sendCommand(ON) 
            gLivingroomLights.sendCommand(ON) 
            gOfficeLights.sendCommand(ON) 
            gKitchenLights.sendCommand(ON) 
            Sonos_Master_Bedroom_Add.sendCommand("RINCON_000E582AC07601400")
            Sonos_Master_Bedroom_Add.sendCommand("RINCON_000E582AC07E01400")
            Sonos_Master_Bedroom_Add.sendCommand("RINCON_B8E93783325201400")
            Sonos_Master_Bedroom_Add.sendCommand("RINCON_B8E9375835EC01400")
		}
		else {
			logWarn("ruleName", "Job already done")
		}
end

Yes that should do it (although my Rules DSL is a bit rusty).

Damn, the above code still lets it fire again and again :confused:

Any other ideas why it still fires and does not adhere to the restriction set by the timer?

This line was correct before, so please change it back again to:

if(tRun === null && (now.getMinuteOfDay > 360 && now.getMinuteOfDay < 600)){

Oh wow, I thought this would also let it fire again and again. It worked now, THANK YOU so much :wink:
It now fires only once and afterwards says the job is done :ok_hand:

Again thanks for the help!

1 Like