Music Cards: RFID cards + Spotify + Raspberry Pi

I first saw the Spotify Box project a couple of years a go, even before the Raspberry Pi was released to the market. Since then, I have been trying to replicate this idea of using physical objects to select the music that you want to listen.

After a couple of attempts, by the end of 2014, I was able to have a working version and it turned out to be very simple. Just a few lines of python code and usb connected hardware (not even soldering!). The idea is to use RFID cards that are associated to a Spotify URI to start playing a song, album, playlist, etc… in a Raspberry Pi.

So, here’s what you will need if you want to create your own version:

Hardware (~80 USD)

  • Raspberry Pi (any version, as long as you are able to connect it to the internet). Don’t forget the power supply!
  • An 125 kHz RFID card reader. This one is incredibly cheap and it works perfectly.
  • 125 kHz RFID cards. This is the best deal I have found.
  • (Optional) A sound card. The Raspberry Pi has audio output, but the quality is not very good. For less than 10 USD you can get a decent result, like this one. There are better options as well, like the hifiberry.
  • A speaker, receiver, headphones or whatever you want to use to listen to the music.

The connections are pretty obvious. Just connect the RFID reader to the USB port and the sound card too.

Software

To handle the connection to Spotify, I use the image from Pi Musicbox. You can follow the instructions in their website to install the image to the Raspberry Pi. Remember to enable the SSH connection in the settings. Now, if you want to use another board (Beagle Board Black, for example), you can just install Mopidy, which is the base of Pi Musicbox. It creates a music player daemon (MPD) and a web server, so it also provides a web interface to control your music.

To read the cards and control the MPD, I wrote a script that can be found here. The dependencies are listed there. First run ‘python config.py’ to configure the card reader. Then run the script called add_cards.py, where you can assign an Spotify URI to a card number using the reader. You can get the Spotify URI in the Spotify desktop app by right-clicking any song, album, playlist or radio station that you want. After adding some cards and playlists, run ‘python box.py’ and you are all set. All the code is open source and you are more than welcome to contribute!

Last thing is that you may want to include the script box.py to the startup. You can do so by following this tutorial for example.

If you have any questions, comments or improvements I am more than happy to hear them!

Advertisements

65 thoughts on “Music Cards: RFID cards + Spotify + Raspberry Pi

  1. Hi Francisco, is there a simple documentation about your scripts? I have problems to connect the RFID cards with Spotify URLs. Thx for your help

    • Hi Steph,

      I don’t have a documentation yet. But if you have any questions, I am happy to help. Also, a good source of documentation is the python-mpd2 library (http://pythonhosted.org/python-mpd2/index.html).

      You said you were having trouble with the Spotify URLs. The system works with URI (i.e. spotify:track:7iN1s7xHE4ifF5povM6A48) that are different from the URLs. Are you sure that is not the problem?

      Francisco

      • Hi Francisco,
        thx for your fast reply. My problem is to add the URI with your script. After I put the card to the reader the raspi shows me the ID of the card but then nothing happens. If I try to enter the URI afterwards it is not possible (I start to enter the first letter than the letter appears several time). What is the next step after putting the card to the reader? I’m really sorry to ask you that trivial stuff but I’m not a raspi or LINUX specialist.
        Thx again for your help.
        Steph

      • Hi Steph,

        That is probably because your card has less than 10 characters per ID. You can count the number of character of the ID and then change line 14 of readtest.py accordingly.

        Hopes this helps. If it doesn’t let me know!

        Francisco

  2. Hi Fransisco, thanks a whole lot for sharing!

    I’m currently working on a music player for a person with autism and poor motoric skills, and this is exactly what I have been looking for. This will make it possible to enjoy music without getting frustrated over scratched CDs, flimsy player lids, tiny buttons etc. Hopefully I’ll be able to implement physical buttons for next/prev/play/stop as well.

    Regards
    Thomas

    • Hi Thomas,

      That is a very cool application! Let me know how it goes. You can also assign different cards for next/play/pause instead of buttons. In the code the play/pause is already implemented and you can add the others very easily.

      Francisco

  3. I’ve run into the same problem as Steph, and have edited readtest.py using nano on the RPi. It now says “Put the card in the reader” and reads the card but then does nothing. If I press enter, it outputs X or blank. When trying to enter the Spotify URI it looks like this:
    s
    spp
    oo
    ttt
    ii
    ff
    yz

    If I keep pressing enter, eventually it outputs “Specify Spotify UIPut the card in the reader”

    • Hi Thomas, I still have the same problem you describe above and I couldn’t fix it yet. I also tried to change line 14 of readtest.py because Francisco mentioned that the length of the RFID ID’s could be the problem. But it doesn’t fix the problem. If you find a solution and you fixed the problem please give me note. Thx.

      • Hi Thomas and Steph,

        I am sorry to hear that is not working. Can you give more details? A screenshot of program running and a picture of card code would be great.
        Also, are you using an external keyboard connected to the Raspberry Pi? Because it sounds like the python is script is capturing both the card reader and the keyboard as the same. I use ssh to connect to the Raspberry and that might be the cause.

        Francisco

    • Got SSH to work, RFID reader connected direcly to Pi but when running add_card or readtest I now get
      OSError: [Errno 2] No such file or directory: ‘/dev/input/event1’

      • That should be easy to solve. Probably the reader is in ‘/dev/input/event0’. If event0, doesn’t work try another number. You can see all the options typing ‘ls /dev/input/event*’ in the terminal.

        Hope this helps!

  4. I had the same problem like Thomas. After I changed ‘/dev/input/event1’ to ‘/dev/input/event0’ it worked. Now the script reads the card ID and displays the ID (and the request) like this:

    0
    0
    0
    0
    5
    5
    1
    3
    6
    7
    2
    Specify Spotify URI

    If I copy the Spotify URI the ID and the URI is written correctly to the CSV-file. What are the next steps afterwards? What do I need to do if I want to start the Spotify URI’s with the cards?

    Thx so much, Steph

    • Great!

      I am assuming that you’re logged in as root, if not add sudo before every command. Now you can start a screen (just type ‘screen’ in the terminal, if it’s not installed, type ‘apt-get install screen’) and then type ‘python box.py’. The screen keeps running even if you close your ssh session. It should work now.

      Also, Musicbox comes with a web interface. You might want to make sure that you can play music from there before you try running box.py. You can access the web interface by typing the IP address of the Pi in a web browser.

      Finally, you may want to add the command ‘python box.py’ to the startup, so you don’t have to log in an start it again every time you reboot. There is a link to a tutorial to do this in the blog post.

      Let me know if it works!

      • Hi Francisco, thx again for your fast reply. Screen was installed and I can start the python script box.py. If I type the command ‘sudo python box.py’ the cursor jumps into the next line and nothing happens. Than I put the card to the reader and the card ID is displayed as one number per line. But the linked Spotify playlist doesn’t start. The ID and the spotify link is written correctly in the cardlist.csv and I can start the playlist with the web interface. But the card doesn’t start the playlist. Do you have any idea what the problem could be? Cheers, Steph

    • Same problem here (I’ve installed csvtool to check card id and spotify URI, but have not been able to find the correct file path to check the contents of cardlist.csv.) After typing ‘python box.py’ (included below) and swiping the card I get this:

      root@MusicBox:~/music-cards# python box.py
      0
      0
      0
      6
      8
      1
      3
      4
      3
      7
      X

      ..then nothing. Web interface works as it should. Very grateful for all your help so far! it has been essential as I could hardly spell Linux before deciding to try this.

      Thomas

      • Hi Thomas and Steph,

        Thanks for all your input. After all these problems that you have mentioned, I decided to improve the code. I uploaded a new version to the GitHub repository. It should be much more robust. Now it should work for all card code lengths.

        Try updating the code and let me know how it goes. You need to first run ‘python config.py’ to select where is the reader. Then you can run ‘python box.py’ and hopefully this time will work!

        Best,

        Francisco

        PS: To see a .csv file, just type ‘more cardList.csv’

  5. Thanks again Francisco, great job! It now worked beautifully on the first try 😀 I’ll update when all the components have been mounted in the enclosure.

    Thomas

  6. Hi Francisco,
    sorry but I still have a little problem with your script box.py (listed in the rc.local file). After I start the Raspi the script starts automatically and works fine with a network cable. If I use a wireless USB adapter (EDIMAX EW-7811UN Wireless USB Adapter) the script works one time after I started the Raspi. Afterwards the reader reacts to a new RFID card (sound is audible) but nothing happens. If I start the script manually again it works perfectly. Do you have any idea what the problem could be?
    Furthermore I would like to use your awesome scripts to play local music files saved on the SD card. Is that possible? Or do you have any idea how it could work?
    Thank you so much again.
    Cheers, Steph

    • Hi Steph,

      I haven’t tried the script with a wi-fi adapter, so I can’t help you that much. Did you the boot log for any errors? Maybe you can try placing your script in init.d instead of rc.local?

      I know it is possible to also include local files, because they also have an URI, but I don’t know what it is. For a single file I am pretty sure it is the path to the file, but for a playlist I don’t know. Once you have the URI, you can use the same script add_card.py to associate cards with playlists.

      • Hi, if I restart / start the Raspi your script is running but I figured out that if I put a RFID card on the reader the internet connection gets lost. The connection comes back after 3-5 seconds but than the script doesn’t work any longer. I assume that the mpd client reference gets lost with the internet interruption and never comes back. If I start your script manually afterwards everything works perfectly from this point on. Is there any possibility to reconnect to the mpd client reference after loosing the internet connection for a while? Cheers

      • Hi Steph,

        It sounds like you may have a power problem. Are you using a 2A power supply? Wi-fi adapters use a lot of power. The script connects to the MPD server every time an instruction is sent, so I don’t think is the script. Check if mopidy crashes, which is the MPD server. You can check if it is running by tipping ‘ps aux | grep mopidy’.

        Francisco

  7. Hello together,
    i have a Problem with me RFID Reader. He works on Event0. I changed the Setting in the readtest.py File to /dev/input/event0 but it did not work. Please help me, I want to build a Player for my childrens.
    thanks
    yves

  8. i installed new.. now he write this
    oot@MusicBox:~/music-cards# python add_card.py
    Traceback (most recent call last):
    File “add_card.py”, line 1, in
    from readtest import *
    File “/root/music-cards/readtest.py”, line 8, in
    dev = InputDevice(‘/dev/input/event1’)
    File “/usr/lib/python2.7/dist-packages/evdev/device.py”, line 93, in __init__
    self.fd = os.open(dev, os.O_RDWR | os.O_NONBLOCK)
    OSError: [Errno 2] No such file or directory: ‘/dev/input/event1’

    my reader is in event 0 and i do the config before

  9. root@MusicBox:~/music-cards# python config.py
    Choose the reader from list
    0 Barcode Reader
    Device Number: 0
    root@MusicBox:~/music-cards# python add_card.py
    Traceback (most recent call last):
    File “add_card.py”, line 1, in
    from readtest import *
    File “/root/music-cards/readtest.py”, line 8, in
    dev = InputDevice(‘/dev/input/event1’)
    File “/usr/lib/python2.7/dist-packages/evdev/device.py”, line 93, in __init__
    self.fd = os.open(dev, os.O_RDWR | os.O_NONBLOCK)
    OSError: [Errno 2] No such file or directory: ‘/dev/input/event1’
    root@MusicBox:~/music-cards# python CardList.py
    root@MusicBox:~/music-cards# python box.py
    Traceback (most recent call last):
    File “box.py”, line 3, in
    from readtest import *
    File “/root/music-cards/readtest.py”, line 8, in
    dev = InputDevice(‘/dev/input/event1’)
    File “/usr/lib/python2.7/dist-packages/evdev/device.py”, line 93, in __init__
    self.fd = os.open(dev, os.O_RDWR | os.O_NONBLOCK)
    OSError: [Errno 2] No such file or directory: ‘/dev/input/event1’

  10. thank you for the new files. I dont have any errors now. But my Reader gives no reaction?? Today I order a new one, may be is this better.
    Or you have any Idea?

    Greets yves

  11. okay.. now it works. i used the wrong dc adapter for my raspberry. I used a handy charger, the Reader hasn´t enough power. Now it workes perfect. Thank you for this perfect tool

  12. Hi Fransicso,
    I love this project (looks like the Jooki Product on Kickstarter does something similar right now).
    I have no experience with Raspberry so far, but I think about getting one for this project.
    My question: To add a new Playlist, do I need to attach a keyboard and screen to the Raspberry? Or is there some kind of web server running on the Pi that I can log in to and add playlists remotely?

    Also, it is possible to output music to a different device via Spotify Connect, like a Chromecast?

  13. I want to use this to play a few local audio files. However, how can I get their URI’s? Or is it not going to work for anything other than spotify?

  14. Hola Francisco.

    Gracias por el tutorial, pero no consigo que me funcione, yo tengo un modulo que no va por USB (NFC RC522) y al lanzar el config.py no me reconoce el dispositivo.

    Muchas gracias
    Luis

  15. Hello Francisco! I’m using the newest version of volumio and a raspberry pi 3. I have had pimusicbox on my pi before, but it runs really bad, and volumio works better than a dream atm.

    Here is the first error I get when I run add_cards.py

    Traceback (most recent call last):
    root@volumio:~/rwid2# sudo python add_card.py
    Traceback (most recent call last):
    File “add_card.py”, line 5, in
    cardList = CardList()
    File “/root/rwid2/CardList.py”, line 8, in __init__
    self.cardList = self.readList()
    File “/root/rwid2/CardList.py”, line 11, in readList
    with open(self.path + ‘/cardList.csv’, mode=’r’) as infile:
    IOError: [Errno 2] No such file or directory: ‘/root/rwid2/cardList.csv’

  16. I changed the name of CardList.pyc to cardList.csv to get past the nameerror, and now I’m getting:

    root@volumio:~/rwid2# sudo python add_card.py
    Traceback (most recent call last):
    File “add_card.py”, line 5, in
    cardList = CardList()
    File “/root/rwid2/CardList.py”, line 8, in __init__
    self.cardList = self.readList()
    File “/root/rwid2/CardList.py”, line 11, in readList
    with open(self.path + ‘/cardList.csv’, mode=’r’) as infile:
    IOError: [Errno 2] No such file or directory: ‘/root/rwid2/cardList.csv’
    root@volumio:~/rwid2# sudo python add_card.py
    Traceback (most recent call last):
    File “add_card.py”, line 5, in
    cardList = CardList()
    File “/root/rwid2/CardList.py”, line 8, in __init__
    self.cardList = self.readList()
    File “/root/rwid2/CardList.py”, line 13, in readList
    cardList = {rows[0]:rows[1] for rows in reader}
    File “/root/rwid2/CardList.py”, line 13, in
    cardList = {rows[0]:rows[1] for rows in reader}
    IndexError: list index out of range

  17. Hi Alexander,

    There is a bug in the code that is causing your problem. I never noticed it because I had my cardList.csv for a long while. I will fix the code soon, but I think you can get around it by running “touch cardList.csv”. This command will create an empty to store the playlists and the code should run fine.

    Let me know how it goes.

    Francisco

    • Hello 🙂 The touch command works great, but now I get “Could not play playlist spotify:user:taylorsawyerr:playlist:5P2CFLqEk9CMelH6vICd” on all the playlists I add.

      Also it says “type q to quit” but whenever you try to exit the python thingie it just starts going on new lines forever, not responding.

      Thanks for looking into the project! 🙂

  18. Hello,
    thank you for that great project.

    I am building my own Musicbox. I just want to start local mp3-playlists for files stored on the sd card. So far everything is working. I can start playlists and songs via website.
    When I start box.py, it says, that “Could not play playlist”. I am assuming, that I have to enter the playlist in the file cardlist.csv a specisal way (not just “playlist_name.m3u”).. But I don’t know how. Has anybody an idea, how I can fix that problem?

    Greetings from Marburg, Germany
    Micha

  19. Pingback: DIY: RFID music box with Raspberry Pi | Tech Envy

  20. I think I maybe found why the problem is occuring, but I havnt found out how to fix it yet. When scanning the car it connects fine, but i think it is happening when using mpdclient.play() or mpdclient.add(). Here is the error in the volumio.log:

    2016-12-30T23:34:12.902Z – info: [1483140852901] Received update from a service different from the one supposed to be playing music. Skipping notification.Current spop Received mpd
    Here is the whole log:

    2016-12-30T23:34:12.884Z – info: [1483140852884] —————————— 57ms
    2016-12-30T23:34:12.885Z – info: [1483140852885] parsing response…
    2016-12-30T23:34:12.887Z – info: [1483140852886] ControllerMpd::parseState
    2016-12-30T23:34:12.897Z – info: [1483140852887] ControllerMpd::pushState
    2016-12-30T23:34:12.898Z – info: CoreCommandRouter::servicePushState
    2016-12-30T23:34:12.899Z – info: [1483140852898] CoreStateMachine::syncState
    2016-12-30T23:34:12.900Z – info: [1483140852900] CorePlayQueue::getTrack 0
    2016-12-30T23:34:12.902Z – info: [1483140852901] Received update from a service different from the one supposed to be playing music. Skipping notification.Current spop Received mpd

      • Hello Francesco, thanks for your reply 🙂
        I tried and I can play with an mp3, i changing cardlist.csv with “0008875262000,file:/music/MusicBox/born.mp3”
        I can not play the playlist, instead of “file:” what command should I use for the playlist?

      • Hi Maox, Francisco,

        Have you got the local playlists to work by using the full path of the playlist? I have not…

        But I got it to work when I do the following
        1. Modify box.py line 26, “client.add(plist)” instead of “client.add(plist)”
        2. When assigning cards (with add_card.py), I use the playlist name as I see it in the MusicBox GUI (i.e. no path / .m3u extension)

        I guess this breaks the support of Spotify playlists though, but it does the job for me.

        Thanks a lot for this great script Francisco.

        Cheers,
        Jon

      • Hi Maox, Francisco,

        Have you got the local playlists to work by using the full path of the playlist? I have not…

        But I got it to work when I do the following
        1. Modify box.py line 26, “client.load(plist)” instead of “client.add(plist)”
        2. When assigning cards (with add_card.py), I use the playlist name as I see it in the MusicBox GUI (i.e. no path / .m3u extension)

        I guess this breaks the support of Spotify playlists though, but it does the job for me.

        Thanks a lot for this great script Francisco.

        Cheers,
        Jon

  21. hi,

    looking at following your code, i am following the config.py part. i initially got an error as i had no module name evdev so i downloaded it now i am getting a NameError: name ‘raw_input’ is not defined was wondering if you could help many thanks!

    • managed to change raw_input to input and it seems to work however the only device showing up in my usb is values 0U, 1U and 2 SIGMACHIP USB Mouse. When removing the keyboard just the mouse shows is there something that can be done to pick up the rfid as a device? sorry for all the questions

      • still no rfid recognition- i am using a id20la and a sparkfun rfid usb if that makes a difference?

  22. Can I just say !!! amazing work !!!

    If you dont mind giving me some help ? i’m having no problem getting one song to play “spotify:track:2jTidefcsTu6VQhpIImJrt” but no joy with a full playlist ? and i can find no other links, is there some syntax i’m missing ?

      • thanks so much, i was using the web player, just installed the app and found the share button.

        sorry for wasting your time

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s