Help with simple alarm clock rule

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.