Sonos Spotify Vinyl Emulator
by markhank01 in Circuits > Raspberry Pi
3229 Views, 8 Favorites, 0 Comments
Sonos Spotify Vinyl Emulator
Please note that this is not the latest set of instructions for this project:
Please visit https://www.hackster.io/mark-hank/sonos-spotify-vinyl-emulator-3be63d for the latest set of instructions and support
Listening to music on vinyl is great. It's physical and tactile. You listen to a whole album rather than random tracks. You notice when it's over and consciously choose something else. You can build a collection and browse through it rather than having to search for exactly what you want.
It's also expensive and bulky, especially when you consider that any money you spend on vinyl is very likely a duplicate of music that you already have access to through a streaming service you subscribe to.
This project attempts to replicate the tactility and collection-building aspects of vinyl while relying on Spotify to actually deliver the music. Placing a physical object on an NFC reader hooked up to a Raspberry Pi (both of which can be hidden away) will start playing the album associated with that tag.
I will walk you through all the steps - from setting up the Raspberry Pi to encoding the NFC tags. This is my very first Raspberry Pi project and my first Python code, so I taught myself both while developing this. As such, these instructions assume literally zero previous knowledge and talk you through every step.
The total cost for the essential components to build this is approximately £50-60.
I'd love to see what you build!
Required Supplies 1: Raspberry Pi
The back end that interfaces with your network, Sonos and Spotify will be run by a Raspberry Pi. There's actually very little you need to get this going.
Essential:
Raspberry Pi: I used a Raspberry Pi 3 Model B+ but it will also work with a Raspberry Pi 3 Model A+ (£23)
USB power supply: I had one lying around - there is an official one available if you don't (£9)
Micro SD card: I got a 32gb one, which is plenty for this application, on Amazon (£6)
Some Sonos equipment running on your network (I'm guessing you have this already if you're here...)
A Spotify Premium account
Recommended:
A case for the Pi: there are lots of options, starting at £5
A bottle of decent California Zinfandel: I recommend Ridge, but others are available
Required Supplies 2: NFC Reader
These instructions are built for an ACR122U NFC reader which connects via USB.
ACR122U
I bought this one from Amazon for £38 (mostly because it had prime delivery) but there are cheaper options to buy this same reader.
Confusingly the ACR122U seems to be sold under a bunch of different brand names (mine came under the far-from-reassuring brand name "Yosoo") but from what I can tell they are all the same and constructed by American Card Systems.
The cheapest I've found the ACR122U advertised is £21 including shipping, but that comes direct from China so you might need to wait a bit for that.
Other options
This project relies on a python library called nfcpy which maintains a list of supported devices here: https://nfcpy.readthedocs.io/en/latest/overview.h...
In theory this project should work with any of those on that list with little integration.
One tempting option is the Adafruit PN532 which is a board which should hook up directly to your Raspberry Pi using jumper cables. I tried it and found it a real faff. It requires soldering, for instance.
One advantage of it is, superficially, that it's smaller but in reality the board is about the same size as the guts of the ACR122U. If you're really pushed for space for your application then you can strip the plastic off the ACR122U and just use the board.
Required Supplies 3: NFC Tags
For each album you want to create, you will need an NFC tag which meets the NTAG213 standard.
There are many places to buy these.
I bought my first batch from Amazon, where I got a pack of 10 for £9 (including Prime delivery)
The best supplied I've found here in the UK is Seritag - they have a really wide selection of different styles, great advice on their website, you know exactly what you're getting (not always true on Amazon). They have no minimum order size and a ton of options. Tags start at 27p per tag
Download the Raspberry Pi OS to an SD Card
On your PC or Mac, download and run the Raspberry PI imager application.
Insert the SD card you want to install the Raspberry Pi operating system on.
Click on CHOOSE OS and select the default Rasbian.
Click on CHOOSE SD CARD and select the SD card you have plugged in.
Click on WRITE. This may take a while.
Once it's done it will tell you to remove the SD card, which you should do. But then plug it back in as there's a few points of housekeeping you need to do first.
Enable SSH on Your Raspberry Pi OS Image
Once the OS has been written to the SD card, there are a few additional tasks you need to do.
We want to access the Raspberry Pi without plugging in a keyboard or monitor (aka "headless"), which we can do over our local network using our PC or Mac over a protocol called SSH. However, for security reasons SSH is disabled by default. We need to enable it.
We can do this by creating an empty file called:
ssh
in the SD card we just created. It's important that this doesn't have any sort of extension (eg .txt). The file itself doesn't need to contain any content - just its existence will enable SSH when the Pi boots up.
Optional: Set Up Wifi on Your Raspberry Pi
You can skip this step if you plan to wire your Raspberry Pi to your router by ethernet. (Although you might want to think hard about that decision - having it run over wifi makes life a lot easier in terms of positioning this)
Create a plain text file called wpa_supplicant.conf in the root directory of the SD card.
Insert the below text into the file:
country=gb update_config=1 ctrl_interface=/var/run/wpa_supplicant network={ scan_ssid=1 ssid="MyNetworkSSID" psk="MyPassword" }
Change the country as appropriate (GB is the UK, US is the US, DE is Germany, etc)
Change the wifi credentials in there to be your actual wifi router details.
Save the file.
Safely eject the SD card.
Power Up Your Raspberry Pi
Put the SD card you just created into your Raspberry Pi.
Plug your Raspberry Pi into power via the USB cable. Wait a minute for it to boot up.
Find the IP Address of Your Raspberry Pi
You now need to find the IP address of the Raspberry Pi so you can connect to it. You can do this in two ways:
- via your router setup page - if you have a modern router like eero then this is super easy;
- or via a smartphone app available for iOS and Android called "fing" - download it, connect to your router and scan for devices - one of them should be called "Raspberry" - this will be the IP address you need.
Connect to Your Raspberry Pi Command Line
Open Terminal on your mac (or if you're using Windows then download and use Putty).
Enter the following command:
ssh pi@[your Pi's IP address]
Accept any security warnings you get. You will be prompted for the password for the default pi user which is
raspberry
Set Up the Raspberry Pi OS GUI
You are now connected to your Pi via the command line, which is great but you also want to set it up so you can access the Graphical User Interface which we will access via VNC (Virtual Network Computing). Predictably, we also need to enable this.
First of all check your Pi software is up to date by entering the following two commands (each followed by enter) into the command line:
sudo apt update sudo apt install realvnc-vnc-server realvnc-vnc-viewer
Next, open up the Raspberry Pi settings menu by entering:
sudo raspi-config
Navigate to Interfacing Options > VNC > Yes.
Exit the config application by pressing the escape key and reboot the Pi from the command line by typing:
sudo reboot
Connect to and Setup Your Raspberry Pi GUI
Download and open VNC Viewer.
Type in the IP address for your Raspberry Pi and press connect. It will prompt you for username and password which are:
Username = pi Password = raspberry
This should boot you up to the GUI.
It will prompt you to confirm your geography and keyboard layout.
It will then prompt you to change your password (good idea).
It will ask you to set your wifi details, but you can skip this as they're already working. (Although if you're running on ethernet and having second thoughts then now is your chance... but note your IP address may change)
It will then check for, download and install updates (might take a while).
Once you are through the setup wizard I would recommend changing the screen resolution as the default is pretty small. You can do this by clicking the Raspberry at the top left > Preferences > Raspberry Pi Configuration > Display > Set Resolution
You will need to reboot the Pi yet again to get this to take effect.
Install Node.js and NPM
Next you want to load the Raspberry Pi command line to install the dependencies we need.
You can either do this by connecting via VNC and clicking the button near the top that looks like a command line; or you can connect directly from your Mac/PC using Terminal and Putty as we did previously. If you're less used to working with the Raspberry Pi then it's easier to do the former.
(Tip: You can copy text from your Mac/PC and paste it to the Raspberry Pi via VNC by pressing CONTROL-V, but if you're trying to paste into the Terminal then you need to press CONTROL-SHIFT-V)
First job is to check again your software is up to date by typing the following two commands. They might take a while to download and install.
sudo apt-get update sudo apt-get upgrade
Next you want to download and install node.js and NPM (don't worry too much about what they are, they are helpful and necessary for our next tasks) by typing the following:
sudo apt-get install nodejs npm
It will ask you a couple of times if you're happy to take up disk space with these - you are so press Y
Install the SONOS HTTP API
The basis of the back end for our project is the node-sonos-http-api package created by jishi. You can read all about it here: https://github.com/jishi/node-sonos-http-api
We will download this from github with the following command entered into the command line:
git clone https://github.com/jishi/node-sonos-http-api.git
and we will install it with the following commands
cd node-sonos-http-api npm install --production
We can then run it with the following command:
npm start
Once that's done we should test that it is working.
First of all, open the internet browser on our Raspberry Pi and navigate to http://localhost:5005/. A nice interface should open with the Sonos logo and some documentation on how the API works.
Next, let's check that this is working from the wider network by using a browser on another PC or Mac on the same network and navigating to http://[theIPaddressofyourPi]:5005/ and seeing if we get the same result. We should.
Now we will actually make the system do something. Use a browser and navigate to:
http://192.168.4.102:5005/Dining Room/playpause
You should replace the above IP address with the address of your Raspberry Pi and "Dining Room" with one of the names of your Sonos zones. It should either play or pause (depending on whether music is already playing or not) the music in that room. Obviously something needs to be in the Sonos queue for that to work.
Going forward, I'm going to use the above IP address and Dining Room as the examples throughout this tutorial. Obviously you should replace them with your IP address and your zone name on each occasion.
Make the Sonos HTTP API Run Constantly
It's great that we've got the Sonos HTTP API running, but what if it crashes? Or you lose power or need to reboot your Raspberry Pi?
You can see the effect by closing down the terminal window and retrying what we just tried. It won't work because the HTTP API has stopped along with the terminal window.
We actually want this to run constantly and do so from startup each time. We do this with a cool thing called PM2.
In a fresh terminal window, install and run it as follows:
sudo npm install -g pm2 pm2 status
Now let's get it to run our Sonos HTTP API:
cd node-sonos-http-api pm2 start npm -- start pm2 startup systemd
This last command generate something which looks a bit like:
sudo env PATH=$PATH:/usr/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi
Copy what your Pi generates (not the exact text above - yours may be different) and enter it into the command line. This instructs the system to run PM2 on boot every time.
Finally, enter:
pm2 save
which saves everything down.
Now test whether this has worked by rebooting your Raspberry Pi with the command
sudo reboot
Hopefully once the Pi reboots it will also start PM2 and in turn the Sonos HTTP API. You can check this by navigating using a browser on the same network to the address we used before and see the Sonos logo and instructions:
http://192.168.4.102:5005/
is what is for me, but yours will depend on the IP address.
Play Some Spotify
Let's check that the service can access Spotify.
Open a browser and navigate to the following address (obviously replacing with your IP address and room name):
192.168.4.102:5005/Dining Room/spotify/now/spotify/spotify:album:2dfTV7CktUEBkZCHiB7VQB
You should hear some John Grant. Enjoy.
Find Spotify URIs
Weird, I know, but not everybody likes John Grant. Maybe you want to listen to something else?
You can get the Spotify links from the desktop, web or mobile apps but the Desktop is by far the easiest as it delivers the URI in exactly the format you want so start with that.
In the Spotify desktop app navigate to the album you want to listen to (maybe Lemonade by Beyonce?)
Click on the three little dots next to the heart button.
Go down the menu to Share and choose Copy Spotify URI
This will copy something like
spotify:album:7dK54iZuOxXFarGhXwEXfF
to your clipboard, which is the Spotify URI for Beyonce's Lemondade album.
Fire up your browser again and navigate to the following address (obviously replacing the IP address and room and pasting in the URI you just copied):
192.168.4.102:5005/Dining Room/spotify/now/[Spotify URI you want to play]
You should hear your choice play.
If you prefer to use the web app then it will give you a web link (something like the below):
https://open.spotify.com/album/7dK54iZuOxXFarGhXwEXfF
you need to convert this to the spotify:album:code format above for it to work.
A Note on Spotify URIs
Spotify URIs and they way they interface with the node-sonos-http-api are intuitive, for the most part.
You can link directly to albums, tracks and playlists.
An album URI looks like:
spotify:album:6agCM9GJcebduMddgFmgsO
A track URI looks like:
spotify:track:4fNDKbaeEjk2P4GrRE1UbW
Playlists work a little differently. When you copy the URI from Spotify it will look something like:
spotify:playlist:5huIma0YU4iusLcT2reVEU
However, to actually get it to work on the API you need to add spotify:user: to the beginning of the above. This applies even to public playlists and, yes, it means that you are saying spotify twice.
To be very clear, user doesn't need to be a particular user's name, just the text user. So the correct URI for the above playlist to get it to work would be:
spotify:user:spotify:playlist:5huIma0YU4iusLcT2reVEU
Set Up Raspberry Pi to Send HTTP Requests
Rather than manually typing HTTP requests into a web browser, we want to automate it so that the Raspberry Pi does that itself when presented with certain stimulus (the NFC reader being triggered).
We will be using a library called requests to allow our Raspberry Pi to do this. Let's check it's installed.
Open up the terminal on your Pi and type the following:
sudo pip install requests
It's likely that it comes back and says it's installed already, in which case great. If not, it will install it.
Generate NFCC Tag(s) With Spotify Data
Now we want to write a Spotify album URI to a NFC tag. Each of these tags are what you will use to tell the Raspberry Pi to play a particular album.
You can write to an NFC tag using an Android phone, but I find it easiest to do so via a mac or PC as then you can get the is easiest to get the Spotify URIs from the Spotify desktop app.
Plug your USB NFC reader into your PC or Mac. I am using the ACR122U by American Card Systems.
Download NFC Tools to your PC or Mac. Install and open it up.
It can be a little slow to connect to the reader sometimes and may say that it can't find the reader at all. Go to the Other tab in NFC tools and click every so often on the Connected NFC Reader button. You may have to unplug and replug the reader a few times before it finds it.
Eventually it will give you the option to choose your reader from a list and say that it is connected. Go to the Information tab which will show nothing except "Waiting for an NFC tag".
Take a blank NFC tag. Put it on the reader and leave it there. NFC Tools will display the information about the tag.
Go to the Write tab and click Add a record > Text. (Be careful not to choose URL or URI - I know it's tempting because you're copying a URI, but you want text)
Grab a URI from Spotify using the method we used previously. If you want an easy example then the following is our John Grant album from earlier.
spotify:album:2dfTV7CktUEBkZCHiB7VQB
Click OK and then click Write (don't forget this last step - it doesn't actually write it until you click this). It will tell you it's written the tag successfully.
Take the tag off the reader
Set Up the NFC Reader on the Raspberry Pi
Plug your NFC reader into one of the USB ports on your Raspberry Pi.
We will use the nfcpy Python library to communicate with the NFC reader. Install it by typing the following on your Pi command line:
pip install -U nfcpy
We can then check whether this library is able to see our NFC reader by typing the following:
python -m nfc
If it has worked then you will see the following:
This is the 1.0.3 version of nfcpy run in Python 2.7.16 on Linux-4.19.97-v7+-armv7l-with-debian-10.3 I'm now searching your system for contactless devices ** found ACS ACR122U PN532v1.6 at usb:001:011 I'm not trying serial devices because you haven't told me -- add the option '--search-tty' to have me looking -- but beware that this may break other serial devs
However there's a good chance that you get an error message saying that the reader has been found but your user (pi)does not have permission to access it. If you do get this error message then it will also explain how to fix the problem, which is by typing two commands which looks a bit like the following:
sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"04e6\", ATTRS{idProduct}==\"5591\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules' sudo udevadm control -R
Copy and execute both of the commands it gives you (not exactly what is above, since yours may be different), then unplug and replug your NFC reader from the USB port.
Try the check command again:
python -m nfc
This time it should say that it's found it without error messages.
Install the Vinylemulator Python Scripts
We now have all the building blocks in place:
- Our Raspberry Pi is able to listen for NFC input
- Our Raspberry Pi is able to tell Sonos to play Spotify playlists when given a Spotify URI
- We have an NFC tag with a Spotify URI stored on it
Now we need to pull all these building blocks into something useful. This is done through a short python script I wrote (with a lot of help from previous NFC/Spotify/Sonos projects) which is called vinylemulator.
You can view the source code for the files at github: https://github.com/hankhank10/vinylemulator
To install this onto our Raspberry Pi we need to clone it from github with the following command:
git clone https://github.com/hankhank10/vinylemulator.git
Customise Vinylemulator
Open the Raspberry Pi file manager and navigate to home > pi > vinylemulator
Open the file usersettings.py
One of the lines in this file will read:
sonosroom="Dining Room"
Change "Dining Room" to be whichever Sonos room name you want to control.
There is also a setting in this file which allows you to customise the IP address of the sonos-http-api. You should be able to leave this unchanged as "localhost" which just means it will use the Raspberry Pi it is running on.
Save the file and close it.
Test Vinylemulator
Go to your Raspberry Pi command prompt.
Enter the following command:
python vinylemulator/readnfc.py
If all is well this will load up the script and say that the reader is ready. The light on the reader should go green.
Put the NFC tag on the reader, which will beep.
The terminal will show what it has read from the NFC tag and show the HTTP request address that it has sent. Your album of choice should play from your Sonos speakers.
This script will keep running until you close the terminal window. You can tap different album NFC tags and it will switch to that album.
Get Vinylemulator to Run Constantly and on Startup
Just like the sonos-http-api, we want vinylemulator to run all the time rather than just when we call it. We can use pm2 to do this again.
First close down any instances of vinylemulator you are running by closing their terminal windows.
Then open up a fresh terminal window and type the following two commands:
pm2 start vinylemulator/readnfc.py pm2 save
Let's check if that has worked by rebooting the Raspberry Pi. (You can either type sudo reboot or do so from the Raspberry menu with your mouse.
Wait for the Pi to start up again and see it it works by tapping an NFC tag on the reader. You should get music.
Congratulate Yourself
Everything is now functional. You can move the Raspberry Pi to wherever you plan to site it. It will restart and operate in the way you've set it up any time you plug it in.
Your next tasks are the fun ones: making it all beautiful.
Make It Beautiful - Hide Your Reader
The first part of making it beautiful is hiding the nasty white plastic NFC reader away somewhere.
I have gone with a decidedly low tech option of taping it to the underside of a counter next to my Sonos Play:5. The wood of the counter is thin enough that the NFC can go through, so I play music by tapping a NFC tag on a magical and invisible spot.