One of the things that makes working at Pusher great is our appetite for building. We’ve created various internal tools, members of the team work on various open source projects — and of course, Pusher itself is designed to help others in this way.

Alongside this, we also have regular HackDays, where we can take a break from our ongoing projects and stretch our legs a bit.

This time, I was part of a team to build a new ‘office DJ’ we could control from Slack.

Below the summary, generally in my own notes from the day, if you choose to replicate our system then we’d love to know how you get on.

The idea

We wanted to build a way for users to manage the songs played through our office speakers by typing commands into a Slack channel. This removes the need for the official Sonos client and let us query information about the song queue.

We also found it’s fun to see who is adding to particular tracks, and that leads to discussions about the songs interwoven with the commands that played them. Also users don’t get distracted by running another app to manage their music.

The architecture

This is the general setup:

The example shows the flow for adding a new song. That is the most complex case. We also built-in support other commands:

\play

\pause

\volume-up

\volume-down

\remove

These work in much the same way, but without the additional step of querying the Spotify API for metadata.

And we also support queries:



ow-playing

\queue

Which allow us to get information about the currently playing song and the entire queue respectively.

Getting the command to the Sonos system works in much the same way, but the information is then propagated back to the Slack chatroom in the opposite direction.

The Tech we used

Written in Ruby: Because there is a Sonos client library and, as we use Ruby in a lot of the Pusher code, we are familiar with the language

Sinatra on the server

The Github library we used to control Sonos speakers (a big thank you to Sam Soffes, the author of the library)

Overview of the two components

Server was a standard Sinatra web app that has HTTP endpoints to handle the commands from Slack and also results of queries from the client app. This also triggered Pusher events in a private channel to communicate with the client app and authenticated access to the Pusher private channel

Client listened for commands (as pusher events) from the server and forwarded these to the songs system (using the client library). It also sent results of queries to the server via HTTP requests.

The two separate components suited our team size of two!

What went well

It was very easy to setup Slack web hooks to be fired when certain commands are typed (no code, just some configuration in the web dashboard)

Actual code we had to write was minimal, it mainly involved just forwarding commands along

Using Pusher made it very easy to get data from the outside internet into our local area network

Challenges

Incompatibilities between the ruby client library and our particular Sonos system meant we had to patch the client library (this actually took most of the time.)

Undocumented Sonos API – the Sonos API is not documented, so when the client library was not working correctly, we had to manually inspect the HTTP requests sent by official Sonos client in order to try and deduce where the problem was

Future work

Vote to remove songs

Better support for reordering tracks in the queue, and deleting specific tracks (currently you can only delete the last track that was added)

Cleaning up our code so we can open source and share it with the world

Have you attempted any interesting integrations like this using Pusher? We’d love to hear from you.