My rule works, but i dont know why

I have a rule that turns a light off 5 minutes after it is turned on. The rule works but I cannot get my head round why it works

var Timer md1Timer = null
val int timeoutMinutes = 5  // choose an appropriate value

rule "Downstairs Toilet"
when
    Item DownstairsToilet changed from OFF to ON
then
        md1Timer = createTimer(now.plusMinutes(timeoutMinutes ), [|
        DownstairsToilet.sendCommand(OFF)
        md1Timer = null
        ])

end

I am no programmer (well not on PHP, JAVA etc) Looking at the rule, it looks like to me that the rule runs when the light changes from OFF to ON, looking at the code I would think that a timer is created, then the light turns off straight away, as there inst any conditional code around the OFF command.

The rule does run when the light changes from OFF to ON, it immediatly starts a timer for “now in timeout (5) minutes”, that runs the code supplied with the creation of the timer - turning the light off again.

EDIT: To clarify, the part within the square brackets in the createTimer() function, supplied as second argument, is a “lambda function”. It’s a quick way of supplying a function without explicitly writing a separate function, just passing it as an argument to the timer just being created. (OK, did that clarify or just obscure what’s happening even more? :blush: )

Maybe some formatting makes it easier to see:

md1Timer = createTimer(
    now.plusMinutes(timeoutMinutes ),
    [| DownstairsToilet.sendCommand(OFF)
       md1Timer = null
    ]
)

The first argument to createTimer is the time when it will be fired, the second argument is the code to be executed.

Cheers,
Alex

One way to look at it is -
createTimer ( when to do , what to do )

The what-to-do part can be several lines of code, which obscures the essential nature of createTimer() and its two parameters

Thanks guys that does explain it a lot better (even though i am finding it difficult to get my head round)

I guess I was thinking the “WHEN TO DO” bit was the item changing state and the WHAT TO DO " was the timer bit

The “WHEN TO DO” is just time be it 5 minutes or 5 seconds so another way to think of it is that everything in the createTimer( arguments and lambda function ) is a cron time based rule within your rule. The system will take care of running it in another thread at your requested time and not before.

Maybe you’ve got this covered in other rules and it depends on what devices you have but based on your question wanting to learn think of this as more homework. :+1:

So I visit at 04:00:00 which turns the light from OFF to ON and creates the timer which will expire at 04:05:00 and at that point it will execute the lambda function to turn the light OFF.

I flush and leave at 04:03:30 and forget the light but the timer will take care of it in 1 minute and 30 seconds. Unfortunately the disturbance awakes my son and he enters at 04:04:45 and after 15 seconds the timer kicks in turns the light OFF and I’ve got to mop the floor again in the morning :expressionless:

Do you have a rule covering DownstairsToilet changed from ON to OFF that is cancelling the timer? That would at least cover the scenario where by I didn’t forget to turn the light OFF when I left.

There is no exact right way to solve this but depending on other devices you might be able to bring in to the mix like motion detectors, time of day you can play with rules and conditions that might help you learn a little bit more.

I don’t have anything to cater for on to off bit I’m guessing I need to
cancel the timer… some how

two ways to cancel the timer:

if (md1Timer != null) {
    md1Timer.cancel
    md1Timer = null
}

or you can code it short hand with the tenary if condition:

md1Timer?.cancel
md1Timer = null