The full code for the NodeJS API can be found on Github https://github.com/alexpeta/spotify-aws-iot-button
The code snippets below can quickly become out of date so I recommend checking the repo to get the latest version.
I recently was cleaning out the old boxes and I stumbled upon a brand new AWS IoT programmable dash button. I remember ordering two of them at some point but never got a chance to use them. I also wanted to go hands-on more with Amazon cloud services so I figured now would be a good time to try to build something and I thought the best candidate would be a Spotify control.
- Have an AWS IoT programmable button
- You can buy one here: https://aws.amazon.com/iotbutton/
- Have a premium Spotify account because the Spotify Web API only works with a premium account especially for playback control options
- Create a Spotify App via the developer portal: https://developer.spotify.com/dashboard/applications. Because this is an app without a display where the user can authenticate using the OAuth2.0 flow, I manually authenticated in the browser and saved the details in a DynamoDB instance.
The data flow
This is with what I ended up in the end. A picture is worth 1000 words, so here is the data diagram.
Setting up the AWS IoT button
There are a lot of references out there with how to set up the AWS IoT Button so I will spare you the duplicate information here. Feel free to check out these links:
Coding the AWS Lambda function
Once the button is up and running and connected to WiFi, it’s time to code the AWS Lambda function. The function is going to act as a proxy to our AWS Beanstalk NodeJs API. Based on the click type :
- Single press – will trigger eventType= ‘SINGLE’
- Double press – will trigger eventType= ‘DOUBLE’
- Long press – will trigger eventType= ‘LONG’
Lambda folder structure:
The Lambda function will need to make HTTP requests to our Node.js API.
We can extract this into a generic HTTP utility file utils.js:
Next, we need to code Spotify specific requests into
The main index.js function tying everything together:
Coding the NodeJS API
The basic folder structure contains a few layers: Controllers, Factories, Managers, and Utils.
│ ├── HealthControllers.js
│ └── SpotifyController.js
│ └── LoggerFactory.js
│ ├── AwsManager.js
│ ├── SpotifyManager.js
│ └── SpotifyTokenManager.js
Controllers/HealthControllers.js – contains just a health-check ping endpoint. This is optional but will help to debug.
Controllers/SpotifyControllers.js – this is our API service endpoint. This is an express router that exposes the “/next”, “/previous” and “/pause” endpoints. The heavy lifting of the logic is being done in the managers’ layers.
The logical flow is similar for all three methods
- We get an OAuth2.0 token from the SpotifyTokenManager
- We pass the token to the SpotifyManager to actually call the Spotify API
- Return the results or the error
Managers/AwsManager.js – this is the data layer that has the storage mechanism and based on AWS Dynamo DB. It exposes upsert and
The only need we have for persistence is for the Spotify Web API token and refresh token.
Managers/SpotifyManager.js – this class has Spotify Web API specific code to build the HTTP requests for each type of action.
Managers/SpotifyTokenManager.js – this is where we have all the logic for working with tokens: retrieving, checking for expiration, generating a new one etc. If a token is expired, we will retrieve the refresh token that will help us generate a new token to be used for requests.
app.js – this is our main ExpressJS app
- As mentioned in the TLDR; section at the beginning of the post, you can check out the full code for the NodeJS API on Github: https://github.com/alexpeta/spotify-aws-iot-button
- The Lambda function was coded in the editor directly. If I would have been done via the AWS-CLI tools then it could have been part of the same repo.
- Working with AWS and AWS Lambda was very fun and very easy. This made me sign up for an Azure account so that I can compare the two cloud offerings.
- AWS IoT Buttons are nice but I don’t really see the point for them, but I do believe in IoT in general