My enhanced Sonos alarm with lights and slow ramp up

Tags: #<Tag:0x00007fc3eb5e0928> #<Tag:0x00007fc3eb5e0248> #<Tag:0x00007fc3eb5e0180>

My goal here was to get a morning alarm with an as smooth as possible wake up experience. I first ramp up the dimmable lights in the room slowly over the course of a minute. After that I slowly start to ramp up the sound level for a random track from a Sonos playlist. Currently, I use a playlist of nature sounds, this can be configured at will.

For time configuration, I use the Sonos controller with a special playlist. It is essential that the playlist starts with one minute of silence. This can be found online here:


I would recommend to run the wake-up music from a local share. The alarm mode must not be set to shuffle. The rule will take care of this after the alarm has started. The rule will wait for a bit until Sonos has ramped up the volume to the programmed level and then store it. This way, it will always use the volume you programmed for the alarm in the Sonos controller.

The rule will not mess about when the Sonos buzzer is played, as this is often on purpose or otherwise the fall-back mode in case of connectivity problems. Thus I hope for maximum reliability.

First , a few dummy items need to be configured for the player to be used:

Dimmer   SonosSchlafzimmerL_Alarm_Volume    "Alarm end volume dummy"
Dimmer   SonosSchlafZimmerL_Alarm_Dimmer    "Alarm light dimmer dummy"

They have no channels, I just use them for a persistent variable storage.

For the light items involved in the wake-up sequence, I added them to a group that contains all dimmable lights in the room.

Group:Dimmer gDimmableSZ    "Dimmable lights in Schlafzimmer"

This is the code for my rule. It makes extensive use of timers to sequence things. I have included a value from a light sensor to not switch on the lights in case the room is already brightly lit, by removing the if clause and its brackets this can be modified to always work if you don’t have a brightness sensor.

var Timer alarmTimerSZ = null
var Timer lightTimerSZ = null
var Timer musicTimerSZ = null

rule "Sonos Alarm SZ"
    // Enhance Sonos alarm with light ramp up and slow volume ramp up
when 
    Item SonosSchlafzimmerL_Alarmrunning changed
then
    //stop in case it's the buzzer. don't mess with backstop case
    if (SonosSchlafzimmerL_Currenttrackuri.state == "x-rincon-buzzer:0") {return;}

    if (SonosSchlafzimmerL_Alarmrunning.state == ON){
        //wait 45 seconds for volume ramp up to programmed volume; we need silent track to start playlist, shuffle must be off
        alarmTimerSZ = createTimer(now.plusSeconds(45)) [|
            SonosSchlafzimmerL_Alarm_Volume.postUpdate(SonosSchlafzimmerL_Volume.state)
            SonosSchlafZimmerL_Alarm_Dimmer.postUpdate(0)
            SonosSchlafzimmerL_Volume.sendCommand(0)

            //orchestrate lights if dark
            if (Bewegungsmelder_SZ_MeasurementIlluminance.state < 17) {   //remove line when no brightness sensor present
                lightTimerSZ= createTimer(now) [|
                    if (SonosSchlafZimmerL_Alarm_Dimmer.state < 96) {
                        gDimmableSZ.sendCommand((SonosSchlafZimmerL_Alarm_Dimmer.state as Number) + 5)
                        SonosSchlafZimmerL_Alarm_Dimmer.postUpdate((SonosSchlafZimmerL_Alarm_Dimmer.state as Number) + 5)
                        lightTimerSZ.reschedule(now.plusSeconds(5))
                    }
                    else {
                        lightTimerSZ.cancel() 
                    }
                ]
            }                                                            //remove line when no brightness sensor present

            //random next track, after one minute (and 45 seconds) ramp up volume
            SonosSchlafzimmerL_Shuffle.sendCommand(ON)
            SonosSchlafzimmerL_Control.sendCommand(NEXT)

            musicTimerSZ = createTimer(now.plusMinutes(1)) [|
                if (SonosSchlafzimmerL_Volume.state < SonosSchlafzimmerL_Alarm_Volume.state) {
                    SonosSchlafzimmerL_Volume.sendCommand((SonosSchlafzimmerL_Volume.state as Number) + 1)
                    musicTimerSZ.reschedule(now.plusSeconds(2))
                }
                else {
                    musicTimerSZ.cancel()
                }
            ]
        ]
    }
    else {
        //alarm was turned off, cancel all automation still running
        if (alarmTimerSZ !== null) {alarmTimerSZ.cancel()}
        if (lightTimerSZ !== null) {lightTimerSZ.cancel()}
        if (musicTimerSZ !== null) {musicTimerSZ.cancel()}
    }
end
6 Likes

Hi Arno,

Great post, thank you. I’m new to OH and learning everyday.
One thing I don’t get from your code, where is the connection with the sonos radom track?

First, it starts playing the playlist from the first track, which is silence. It needs to be silence, so that the system has some time to notice that an alarm is running and to turn down the volume to 0. Then it starts the random play by activating shuffle and changing the track. Then it will slowly increase volume.

            //random next track, after one minute (and 45 seconds) ramp up volume
            SonosSchlafzimmerL_Shuffle.sendCommand(ON)
            SonosSchlafzimmerL_Control.sendCommand(NEXT)

By doing it this way, I make sure that when automation fails, Sonos will at some point start playing a track at the preset volume. And Sonos has its own backup that when the network is down, it will play a default ring tone. So the alarm should be pretty fail safe.