AWS IoT button and Sonos
Mon, Nov 23, 2015UPDATE 29/04/2016: I fixed this issue - see here.
I picked up an AWS IoT button at re:Invent this year. I didn’t really know what I would do with it and it sat in a drawer for a few weeks waiting for an idea to appear. Last week, one finally did.
At home we have a Sonos system for multi-room audio. My wife’s main use case is to listen to triplej in the kitchen/diner and bedroom areas in the morning before she goes to work or uni. We have a few ways to control the Sonos system, each with pros and cons:
the Sonos iOS app, which works OK and is our main control method. However it means pulling out a phone or tablet, unlocking it, tapping Rooms, tapping ‘Sonos Favorites’, tapping triplej, setting the volume to the right level.. then doing much the same when leaving the house.
integration with our Amazon Echo. I use the echo-sonos software which generally works OK but my wife is less happy using the Echo to do this, and turning the Sonos off works less well - if there is voice coming from the speakers (e.g. news, links etc) then the Echo struggles to pick up the voice commands. The integration is also slightly awkward because of limitations in the Echo SDK (Alexa Skills Kit) which mean you have to ‘tell Sonos to play triplej’ and ‘tell Sonos to stop’.
pressing the button on the top of the speakers - works for turning off the system but not for turning on, and we’re starting to mount the speakers off the floor so in the long term this option will go away.
So how about using the button? Press once to start triplej. Press again to stop playback. Sounds achievable.
Steps:
Link the AWS IoT button to the IoT service. The wizard does a decent job of registering your ‘Thing’ (button) and creating a default linked certificate (to authenticate your button), a policy (granting AWS access for the button) and a rule (what happens when the button is pressed).
Write Lambda code. In pseudo-code we’re just doing
get current Sonos playing state if not playing start triplej else pause playback
node.js is the language most of the Sonos and Echo integrations use. In particular I use the node-sonos-http-api project to expose an API for Sonos play/pause/group/volume functions. I set this up a while back to support use of the echo-sonos project, including an external endpoint running on a server in my internal network, so Lambda has an endpoint to talk to. My code is here, if you use it you should
- add more error checking
- fill in your own server IP or DNS name and port that is used for external access to your node-sonos API server
- set up your own presets within node-sonos
Set the IoT rule to trigger your Lambda function on button press.
So we end up with something that looks like this:
The revoked certificates are from testing (there appears to be no way to delete a certificate — so the console will get messy) and we will come to the reason for the S3 and SNS actions..
I tried testing from a starting state of silence and… yes, triplej plays. Then stops. Then plays again. Try again. It starts… and stops. Odd. Checking the Lambda logs in CloudWatch Logs shows the function is running multiple times. As I’m not an experienced node.js or Lambda developer this led me down the rabbit hole of ‘why is my code looping?’. After a while I suspected that the IoT button was triggering multiple invocations of my Lambda function but as the IoT service doesn’t directly support logging I needed another way to prove this — which is where the S3 and SNS rule actions come in. I set things up to log to S3 and to an SNS topic and then to email when the button was pressed, pressed the button once and got this:
One click, two notifications. It looks like there is an issue with my IoT button. I’ve contacted AWS to see if this is a known issue and if I can get a replacement, but given these were given away at a convention in the U.S. it’s unlikely they have spares or would be willing to ship one to me in Australia.
Back in the drawer with you, button. Not every project can be a success.