"Alexa, turn on the stereo": Spotify, AWS IoT and a 433 MHz socket
We have an Echo now, and a stereo that’s plugged into one of my Pi-controlled 433 MHz sockets. I could have plugged the Echo’s aux output into the amp, but the Echo’s aux out is all or nothing: once it’s plugged in, Alexa goes quiet whenever the amp is off. So the music comes from the Squeezebox that’s already connected to the amp, and Alexa just tells Spotify to play on it. What Alexa can’t do is switch the stereo on first. What I wanted was one sentence, “Alexa, turn on the stereo”, that powers up the amp and starts the music playing through it. “Alexa, stop” should do the reverse.
There were three pieces to build: getting the sockets onto the internet safely, an Alexa skill that knows about Spotify, and the glue between the two.
The Pi joins the cloud
Amazon’s AWS IoT service has a neat idea called a device shadow. Each device (“thing”) gets a small JSON document in the cloud holding two versions of its state: desired, which is what someone has asked for, and reported, which is what the device says is actually true. Anything with permission can set the desired state. The device gets told about the difference (the “delta”), acts on it, and reports back.
That suits a dumb mains socket perfectly. The Pi has no idea whether a socket is really on, since the sockets can’t talk back, but it does know what it last told them. So each socket became a thing with a one-field shadow, power: true/false.
The Pi runs a small Python service, started at boot by an init script, that:
- connects to AWS IoT over MQTT, authenticating with its own X.509 certificate rather than a password;
- registers a shadow for each socket (a lamp and the stereo) and listens for deltas;
- on a delta, runs my old C++
senderprogram to transmit the RF code, then reports the new state back.
It sends each code ten times, with a comment that says “just in case!”. My sender only sends a single frame per run, so this is the belt-and-braces version.
The same service also has a tiny HTTP API on the local network: /send/<channel>/<state>, where the state is 0 for off, 1 for on and 2 for toggle. That’s handy for scripts, and it goes through the same code, so the shadow stays in step.
A Spotify skill that knows about plugs
The Alexa side is a Smart Home skill, backed by an AWS Lambda function in Python. Smart Home skills don’t get to hear what you said. Instead, Alexa does the understanding and sends the skill structured “directives”: discover your devices, turn this on, play, pause, what state is this in?
The skill is linked to my Spotify account, so each directive arrives with a Spotify access token.
- Discovery asks Spotify’s Web API for my Spotify Connect devices and offers each one to Alexa as a speaker. The list is saved to a small per-user JSON file in S3, and that’s where the trick lives. I can edit the file to give a device a friendlier name for Alexa, and, crucially, a
powerfield naming the IoT thing that powers it. - Play, pause, next and previous go straight to Spotify’s player API. “Play” also transfers playback to the chosen device, so the music moves to wherever you asked.
- Turn on does both jobs. It starts Spotify playing on that device, and sets the socket’s shadow to
power: true. A moment later the Pi hears the delta and the stereo clicks on. Turn off pauses Spotify and switches the socket off again. “Stop” does the same. - Report state reads the socket’s shadow, so the Alexa app shows whether the stereo is on.
Only devices with a power field get the on/off ability. Everything else is just a speaker that Alexa can play, pause and skip on.
The first version, from January 2018, was barely a skeleton: discovery returned a single hard-coded speaker, and the playback handler was one line long, reading pass. Now I’ve come back to it and filled it all in.
Loose ends
The skill tells Alexa that the stereo’s power state is “proactively reported”. That obliges it to answer Alexa’s AcceptGrant authorisation handshake, which it does, politely, and then ignores: nothing is actually reported proactively yet. Alexa only finds out the state when it asks.
Where it stands
“Alexa, turn on the stereo” now does what it says: the socket switches on, the amp wakes up, and Spotify starts playing through it. “Alexa, stop” pauses the music and turns the amp off. The lamp is on the same system, so the Pi, and the sockets it talks to, are finally reachable from something other than my shell prompt.