Projects Meta Quick Hacks About

Sonos Alarm - Cron powered custom alarms for Sonos

Dec 11, 2015

TL;DR: Installation and usage

We love music in the Songkick office (I mean, we’re a music company, duh), and pretty much always have something playing in the background round the office. We used to run this off a Mac Mini with Spotify, it was a bit crazy, everyone would VNC in and add songs to the playlist and stuff, but it worked pretty well. One of the other advantages of this setup is we could use iCal for custom alerts, we’d have sounds and alarms for Standups, meetings, and - my personal favorite - Rebecca Black’s ‘Friday’ at 5PM on a Friday when it’s time for cocktails and Show & Tell.

Earlier this year, we upgraded our office to Sonos. There’s a lot of things I love about Sonos, the sound quality is fantastic, and being able to play the music synchronized all round the office is amazing, but I found it’s alarms feature fairly limited. While it supports alarms, they’re more like proper alarms, that interupt the playlist, then there’s that annoying “Sonos Chime” at the end which you can’t disable, so I decided to play around with trying to create my own alarm trigger script, so we could run whatever alarms we wanted in a flexible way.

The basic features I wanted were;

  • Trigger alarms in a simple way, say with a cron job
  • Play the alarm track once, then continue with the playlist as normal
  • Specify a volume for the alarm, but then reset the volume when returning to the playlist
  • Support for grouping

After a bit of research, I stumbled upon the wonderful SoCo library for Python. It has a few oddities but overall is pretty cool. It handles discovery over the broadcast when on the local network, as well as being able to specify an IP address to connect to.

So in a couple of hours, I threw together a fairly simple Python module to do this. It’s relatively simple, it talks using SoCo to the Sonos system to control what’s going on.

First it looks at the current state of the player, or group, to get information about play state, volume and playlist. After fading out the currently playing track it adds an item to the end of the playlist, plays it, then when that playlist item finishes playing resumes the playlist at the next song.

Usage & Installation

Installation is via PIP, I developed and tested against Python 3.5, but I seen no obvious reason for it not to work on other Python 3’s, or Python 2.7 - though I haven’t tried it and there are no tests so YMMV.

First, ideally in a VirtualEnv, install sonosalarm

Sams-MacBook-Air:sonosalarm sr$ pip install sonosalarm
Collecting sonosalarm
  Downloading sonosalarm-0.2.0.tar.gz
Successfully built sonosalarm texttable PyYAML
Installing collected packages: requests, soco, texttable, PyYAML, sonosalarm
Successfully installed PyYAML-3.11 requests-2.8.1 soco-0.11.1 sonosalarm-0.2.0 texttable-0.8.4

Now, you need to discover information about your Sonos system, you can use the discover command on sonosalarm to find out the names and IP addresses of your sonos systems.

Sams-MacBook-Air:sonosalarm sam$ sonosalarm discovery
| Zone Name    | UID          | Group        | IP           | Current      |
|              |              |              |              | Volume       |
| Sonos01      | RINCON_0000X | Sonos01      |  | 18           |
|              | XXXXXXXX1400 |              |              |              |
| Sonos02      | RINCON_0000X | Sonos02      |  | 25           |
|              | XXXXXXXX1400 |              |              |              |
| Sonos03      | RINCON_0000X | Sonos02      |  | 5            |
|              | XXXXXXXX1400 |              |              |              |

The things you most likely care about are are Zone Name, Group and IP.

Next you need to create a configuration file for the alarm. The alarms are pretty simple;

zone: "Sonos02"
zone_ip: ""
file: ""
volume: 65
fadeout: 5
  • zone is the full name of the zone, or speaker. It’s best to use the master of a group, but not required. If you use the child of a group the controller will automatically be discovered
  • zone_ip is not required, but useful if you’re running the script on a system that doesn’t have the same broadcast as the Sonos speakers, as regular discovery will not work under these circumstances
  • file is a network address to a file to play. Can be anything supported by Sonos, but http is easiest IMO
  • volume is the volume to play the alert at
  • fadeout is the duration, in seconds, to fade out the current song - if there’s one playing

Once you’ve got your config file set up, you can just run

sonosalarm play --config=/path/to/alarm.yml

It’ll print out a bit of logging information, but that’s all there is to it. You probably want to run that under a cron or some other time based scheduler. Sonosalarm itself doesn’t take care of scheduling (because there are like a million other systems that can do time based execution of scripts).