Help with simple alarm clock rule

Hi Everyone

i’m trying too create a rule but its not behaving as i expected hoping for some tips

What i expected

A sound is played on google home at certain time of day dependent on the mode the system is in (handled by Morning mode ready) i want the sound too play for 2 mins then stop and wait for 5 mins before playing the sound again

the alarm clock will stop doing this when there has been motion at the bottom of the stairs (also handled by morning mode ready) i also want too link an amazon dash button too the alarm too act as a snooze button snooze is a 5 min period where if this button has been pressed no sound will play (this is handled by expire binding set too 5mins)

Morning_Mode_Ready works reliably the first problem is that the sound is played when morning mode has been turned on but when it changes too off

rule "Wakeup Alarm"
when
	Item Morning_Mode_Ready changed to ON or //This is a switch item that turns on at the time the alarm should sound this is for other rules but fits the need for this rule (its defined  in a bigger rule)
	Item Snooze changed to OFF // this is the item linked to amazon  dash button with expire bindng set too 5m
then
Mbed_GH_Volume.sendCommand ("50")
	while ( Morning_Mode_Ready.state == ON ) { //turns off when motion at bottom stairs
		if ( Snooze.state == OFF ) {
			playSound("chromecast:chromecast:c245712d07d19a769446974721aa5e95", "tsb.mp3") 
			createTimer(now.plusMinutes(2), [| 
			])
		}
	}
end
Switch   Snooze "Alarm Clock Snooze" { expire="300s,command=OFF" }

I think you have a misunderstanding of what createTimer does. createTimer schedules a function to execute at some point in the future and immediately returns. It doesn’t block the execution of the Rule for two minutes like you appear to be trying to do. For that you would use Thread::sleep. But, Thread::sleep for more than a few hundred milliseconds is a really bad idea. A minimum two minute sleep with no set maximum is a really bad idea. See Why have my Rules stopped running? Why Thread::sleep is a bad idea for details.

What you should use is a Design Pattern: Looping Timers. And also realize that the addition of the Snooze is a pretty significant complication. Also, I know of no way to stop a sound from playing once it has started so the snooze button will only be able to extend how long it takes for the sound to play again once it finishes.

var Timer wakeupTimer = null

rule "Wakeup Alarm"
when
    Item Morning_Mode_Ready changed to ON or
then
    Mbed_GH_Volume.sendCommand("50")

    wakeupTimer?.cancel
    wakeupTimer = createTimer(now, [ |
        if(Morning_Mode_Ready.state != ON) return;

        if(Snooze.state == OFF) playSound("chromecast:chromecast:c245712d07d19a769446974721aa5e95", "tsb.mp3")
        if(Morning_Mode_Ready.state == ON)  wakeupTimer.reschedule(now.plusMinutes(if(Snooze.state == ON) 5+<tsb.mp3 runtime> else 2+<tsb.mp3 runtime>))
    ])
end

I’m pretty sure that playSound does not block until the sound is done being played so you must add the runtime to the 5 or 2 when rescheduling the Timer.

The above Rule gets triggered when Morning_Mode_Ready changes to ON.

It creates a timer and schedules it to execute immediately.
If Morning_Mode_Ready is OFF we immediately exit the Timer.

If the Snooze isn’t ON we play the sound.

Once the sound has finished playing we check Morning_Mode_Ready is ON again (it may have changed while the sound was plying.

If it is still ON, we reschedule the timer to run again in 5 minutes if Snooze is ON or 2 minutes if not.

But, this is probably not what you want. Instead you probably want the snooze button to stop the sound that is playing on the chromecast. I don’t have a chromecast so I can’t be certain whether this will work but here goes anyway.

We need multiple Rules to handle this. One that triggers on Morning_Mode_Ready and one that triggers on Snooze.

var Timer wakeupTimer = null

rule "Wakeup Alarm"
when
    Item Morning_Mode_Ready changed
then

    // Start the alarm
    wakeupTimer?.cancel // this should never be needed but it is a good thing just in case
    wakeupTimer = createTimer(now, [ |
       playSound("chromecast:chromecast:c245712d07d19a769446974721aa5e95", "tsb.mp3")
       if(Morning_Mode_Ready.state == ON)  wakeupTimer.reschedule(now.plusMinutes(2+<tsb.mp3 runtime>))
       else wakeupTimer = null
   )]
end

rule "Snooze"
when 
    Channel dash:some:channel:id triggered START or // NOTE: if you plan on using the Dash binding, there will be no Item, just a triggering channel
    Item Morning_Mode_Ready changed to OFF
then
    // Stop playing the mp3
    <sendCommand(PAUSE_ to the Item lined to the Control channel on the Chromecast Thing to stop playing the sound if it is currently playing>

    // Turn off the repeating alarm
    if(Morning_Mode_Ready.state == OFF) {
        // stop the timer
        wakeupTimer?.cancel
        wakeupTimer = null
    }

    // Snooze the repeating alarm
    else if(Morning_Mode_Ready.state == ON previousState === null){ // previousState will be null if the Rule was triggered by the dash button
        wakeupTimer.reschedule(now.plusMinutes(2))
    }    
end

As with the first Rule, replace the stuff in < > with what is appropriate.

Thanks again rich as always :slight_smile:

at the moment i have gone for

rule "Wakeup Alarm"
when
	Time cron "0 0/5 * 1/1 * ? *" // Every 5 mins
then
if( Morning_Mode_Ready.state == ON && Snooze.state == OFF ) {
	Mbed_GH_Volume.sendCommand ("50")
	playSound("chromecast:chromecast:c245712d07d19a769446974721aa5e95", "tsb.mp3") // Play alarm sound
	createTimer(now.plusSeconds(90), [| // Wait 90 seconds and stop alarm
	MbedGH_Control.sendCommand ("PAUSE")
])
}
end

rule "snooze"
when
	Item Morning_Mode_Ready changed to OFF or
	Item Snooze changed to ON // amazon dash button linked too item Snooze using expire 
then
	MbedGH_Control.sendCommand ("PAUSE")
end

i just dont understand why my other rule was not working in the while part when morning_ready changed too on it changed the volume but didnt play a sound until morning_ready turned off

i did look at using your second rule but i was receiving errors i still struggle with var and timers :frowning: