quick and cheap RFID with RPi and rc522

To my great surprise it turns out you can nowadays get an RFID reader with 2 tags for somewhere between 7$ and 10$. Better yet, interfacing these to Arduino is well documented and several libraries are available for that purpose.

My friend who bought a couple of these asked me to see if I can read the tags directly from a Linux based ARM board (for example Raspberry Pi). It turned out to be rather easy as long as you aren’t interested in anything but the ID of the card. This can be done using rpi-rc522 library (NOT written by me). It sadly currently lacks any documentation or a Makefile so here are my notes on how to get it running.

First you have to connect the rc522 and RPi over the SPI interface. It will look something like this:

Raspberry pi and rc522 RFID reader

Raspberry Pi and rc522 RFID reader

Then you have to install the bcm2835 library. Assuming that you have gcc and other essential development stuff already installed you can achieve it this way:

wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.35.tar.gz
tar -zxf bcm2835-1.35.tar.gz
cd bcm2835-1.35
./configure
sudo make install

After that you can compile and run the rpi-rc522 with the following commands:

sudo apt-get install subversion
svn checkout http://rpi-rc522.googlecode.com/svn/trunk/ rpi-rc522-read-only
cd rpi-rc522-read-only/rc522
gcc config.c rfid.c rc522.c main.c -o rc522_reader -lbcm2835
sudo cp RC522.conf /etc/
./rc522_reader -d

You should see tag IDs in the output of the program as they are read. You can put these into the /etc/RC522.conf file and map each ID to a specific command to run there.

62 thoughts on “quick and cheap RFID with RPi and rc522

  1. Florian

    Hi Kadara,

    good work.
    It was the only fully working TUT and Code that worked for me.
    But i’ve got some problems over here…
    ive written a script which toggles an led.
    normal shell run: all normal.
    executed from the config of the rfid tool -> Nothing happens…

    May you can help me

    Regards
    Florian form Germany πŸ™‚

  2. hadara Post author

    hi Florian,

    couple of hypothesis why you shell script might not run when called from the reader program

    • missing/different environment variables, for example PATH might not have the same value as it was when you tried to execute it from your shell. If your shell script uses external binaries that are referenced with relative paths these might fail. Try to replace all the paths in your shell with absolute paths.
    • different shells: reader programm uses the following code to execute the programm given in the configuration:
      execl(“/bin/sh”,”sh”,”-c”,str,NULL);
      Is your normal shell the same as /bin/sh and does your script work with it?
      To debug it try to run /bin/sh -c ‘the command in your config’
  3. Florian

    Hi hadara,

    its just a very small script. Here: http://pastebin.com/vJ7MkUU5
    iam normally using bash… and with your command given it does nothing except empty lines with “>”. no output….
    just like this
    >

    and is there a way to export the read serial? so that i use this programm just for reading?
    i hope you can help me..

    Florian

  4. hadara Post author

    You probably forgot to terminate the single quotes around the script name.

    Since your script doesn’t take any arguments you can just remove the quotes anyway and just test with something like:
    /bin/sh -c /path/to/your/script.py

    As to reading new serials there’s no good direct support but following hacks should work.

    If you don’t describe any known serials in the configuration file and run the program in the debug mode it will print all the read serials into it’s output which you can read with other programs.

    For example if you just want to extract serials from the output of the reading program and print out just the serial then something like this should work:
    ./rfid_reader -d 2>&1 | awk ‘{ print $5 }’ | cut -d ‘=’ -f 2

    If you actually want to use the read serial in your python program then something like this would make more sense:
    ./rfid_reader -d 2>&1 | python /tmp/rfid_reader.py

    where rfid_reader.py is comething like this:

    import sys

    while 1:
        line = sys.stdin.readline()
        if line == '':
            break
        if not line.startswith("New tag"):
            continue
        serial = line.split()[-1].split("=", 1)[1]
        print(serial)

    Another method would be to execute the reading program from your python script using subprocess.Popen() and read its output that way.

    I don’t have the rc522 reader at hand anymore so none of this was actually tested.

  5. hadara Post author

    I took a another look at the code of the library and I believe the reason why it doesn’t work with your script is that the rc522 reader binary drops root privileges to the UID given in the configuration file after doing the hardware initialization.
    While this is good practice from the security perspective it also means your script isn’t called in the root privileges anymore. Accessing file /root/status.txt in your script and using RPi.GPIO module both probably require root access and will fail because of that.

    The methods with piping that I described in my previous comment should still work though.

  6. Florian

    thx for your fast reply.

    i want to use your last suggestion.
    with subprocess. It now opens the process, and read all output…
    Code: http://pastebin.com/W79M7abn
    but i want to read just the serial. and after reading once: terminate subprocess, do some commands and then jump back to the loop and open the process again and so on

    Iam new to python .. already codes java and php πŸ˜‰
    i hope you can help me again

    Florian

  7. hadara Post author

    killing the reading subprocess after each read tag doesn’t make much sense.

    I suggest you let it run and do your stuff when the new tag is read.

    Here’s a simple wrapper class that you can use for example.

    You have to make a tiny modification to the main.c of the rc522 library and recompile it.
    Look for the fprintf() containing “New tag: and add fflush(stderr); after that so that
    the end result would look something like this:

    if (debug) {
      fprintf(stderr,"New tag: type=%04x SNlen=%d SN=%s\n",CType,SN_len,sn_str);
      fflush(stderr);
    }

    This is just a way to get around the output buffering when using pipes. Otherwise python process wont see the serials until output buffer of the rfid_reader process is filled.

  8. Florian

    Wow.
    You. are. amazing πŸ™‚

    It works! πŸ˜€
    but a small thing doesnt work πŸ™

    i want to read from a .txt file. this works ^^
    but i want to check for every new read serial, if this serial is in the text file.
    with my code it works 1 time. no more.

    I hope you can help me a last time πŸ™‚

    i appreciate that

    Yours Florian πŸ™‚

  9. Florian

    Edit:
    now it works every time.. forgot fobj.close()
    But how can i read multiple serials an then print e.g. the names after the serials from the .txt?
    .txt like that:
    [2f75b800]; Peter Pan

    hope you can help me a very last time πŸ™‚

  10. Florian

    Looks great.
    But doesnt work πŸ˜€

    my whole code: http://pastebin.com/RFeuR59Y

    error:

    Traceback (most recent call last):
    File “./rfid_reader.py”, line 68, in
    a= get_serialmap(sys.argv[1])
    NameError: name ‘get_serialmap’ is not defined

    but it is defined? :O

  11. Florian

    ah… i oversaw it ..

    okay. still another array error:
    Traceback (most recent call last):
    File “./rfid_reader.py”, line 66, in
    print (get_serialmap(sys.argv[1]))
    IndexError: list index out of range

    thx πŸ™‚

  12. hadara Post author

    well sys.argv is a list of command line arguments and sys.argv[1] is argument number 1.

    In your case you probably want to define a variable containing your file name and use that as an argument instead.

  13. Florian

    ok. works again πŸ˜€
    but it does not yet do, what i intend ..

    i want tu print only this name, which belongs to the serial wich is read.

    maybe check everytime if the serial is in the file and then print just this line?

  14. hadara Post author

    well the get_serialmap() function returns mapping from serial to name. you can use something like:

    serialmap = get_serialmap(filename)
    if serial in serialmap:
    print(“known tag with name”, serialmap[serial])

    It’s up to you how often you want to re-read the mapping file…

  15. Florian

    Great! You’re awesome!

    just a tiny thing:
    my output is like this:
    (‘known tag with name:’, ‘Peter Pan’)

    how can this be?
    snippet:

    if __name__ == ‘__main__’:
    datei=”/root/status.txt”
    reader = RFIDReaderWrapper(“./rc522_reader -d”)
    while 1:
    fobj = open(“/root/status.txt”,”r+”)
    serial = reader.read_tag_serial()
    # blink the lights etc.
    #print(serial)
    serialmap = get_serialmap(datei)
    #print serialmap
    if serial in serialmap:
    print(“known tag with name:”, serialmap[serial])

    #print (get_serialmap(datei))
    fobj.close()

  16. hadara Post author

    use this instead:
    print(β€œknown tag with name: %s” % serialmap[serial])

    the point is that in python 2.X print is a keyword so
    print(“a”, b) prints out a tuple that consists of 2 elements: string a and variable b.

    in python 3.X print() is a function, so
    print(“a”, b) wouldn’t print the extra parentheses there because it would be just a call to the function print with 2 arguments.

    the expression print(“a %s” % str(b)) should work in both python2 and python3 because in that case python2 will see it as a keyword print that is followed by string that is surronded by useless parenthesis and python3 will think of it as a function call.

  17. Florian

    Well…
    I did’nt know, that python 2 was installed…
    i’ve installed python 3..

    I thank you very much for your help.
    I want to publish my whole code on the internet.
    Of course with you Name in the Credits πŸ™‚

    Thank You πŸ™‚

  18. david

    hi, i’ve got problem here πŸ™

    when i : #./rc522_reader -d

    Collision
    Collision
    Collision
    ….

    any idea ??

  19. Renzo

    All is working in debug mode. Good
    Bat I have not understand what do rc522_reader not in debug mode…
    Write a log file ?

    Thank you πŸ™‚

  20. hadara Post author

    in general the collision happens when the reader sees multiple tags at once (for example when you wave your wallet at it that contains multiple rfid cards).
    I assume the same can happen if you have noisy electrical connections

  21. hadara Post author

    in the normal mode it’s meant to execute commands defined in the configuration file for the cards that are defined there.

    unknown cards are read and memory dump is written into the directory that is defined under NEW_TAG_PATH variable in the configuration. By default this is /tmp

    As far as I can see there’s no good way to just continuously read serials of all the cards that it sees without the debug mode. Probably the author of the library didn’t need that…

  22. Jeff Curry

    I’m trying to configure this for a school project, and I was wondering if you have an example of what the code would look like in the /etc/RC522.conf file for the IDs of the cards. I have some experience with programming, but not an extensive knowledge. I’ve looked at a few examples on the web, but I am still unclear as to how to proceed.

    Also do the ID cards have to be saved in the RC522.conf file to stop them from going to the /tmp/?

    In my (very simple) mind, it would be something like this:

    if (code) = ID
    run command

    Obviously this is not how it would actually look, just kind of what I think the logic behind it would be.

    Any help is definitely appreciated.

    Thanks,

    Jeff

  23. Bryn

    Hello,
    I was wondering if you could help me. I am new to this so this question may sound simple.
    I have followed your instructions and now have the RFID reader recognizing the cards and fobs (thanks)
    I will be using a dual relay (5V DC Two 2 Channel Relay Module ) to activate a small solenoid. The problem i have is i need the activation of the RFID to set one of the RPi’s GPIO pins to low to activate the relay. I am hoping you might be able to point me in the right direction as i have no clue what to do next. I am also new to code.
    Thanks
    Bryn

  24. hadara Post author

    There are many ways of doing this, one would be the approach that uses unix pipes that we discussed with Florian in this comment thread earlier.

    What I would suggest instead is to write a simple HTTP service that can turn the light on or off based on the request URI. Then you can easily call it from the configuration of the rc522 utility by using wget command against specific URL on your server (which might run on the same or different machine).

    I originally tested the library with this simple python script that runs a standalone webserver on port 8080 and plays different sounds when different URLs are accessed. You can use it as a basis and just replace sound playing with pin toggling.

    You then just have to use someting like this in your rc522 configuration:

    [your_tag_id] wget -O /dev/null http://localhost:8080/1
    
  25. bryn

    Hi,
    Thanks for the info Hadara, im assuming it was for me. Unfortunately i didnt understand most of what you said, i am an ultra newby at this and as yet have no clue what im doing. If you could possibly explain it like your talking to an idiot ( that would be me) i would really appreciate it. If you dont have the time thats ok also. I am looking at the RC522.conf file now in leafpad and not sure if its the right file. also is it just the number of the keyfob or card that i use.

    Thanks again.
    Bryn

  26. Florian

    Hi bryn,

    i think i could help you πŸ™‚

    After much time I spend in my reader, I’ve created exactly what you want to do. (I think so :P)
    Look right here: https://sourceforge.net/projects/rc522pythonscript/

    If you have the 5V Relais for arduino you have to change some small resistors. If you’re interested, just let me know πŸ™‚

    Regards, Florian

  27. craig

    Florian, i tried your software above but am having issues. I tried the Text file one first, but got the following Syntax error.

    File “rfid_reader.py line 16
    filename=/root/db.txt

    SyntaxError: invalid syntax.

    I couldn’t try the SQL one, because I need better instructions as to how to set up the database.

    On another note, I couldn’t get the basic RC522.conf file to execute commands. When i scan my cards in debug mode, I get the following..
    Type:0400, Serial: 75305f74
    New tag: type=0400 SNlen=4 SN=[75305f74]

    If i edit the RC522.conf file in /etc, and add to the bottom
    [75305f74] wget http://MyIP:8000

    Then scan my card again in debug mode, i get:
    Type: 0400, Serial 75305f74
    Exit

    But no command is ever executed? Any help would be greatly appreciated.

    Thanks

    craig

  28. Peter Laser

    Thank you so much hadara, for making this, and to Florian for posting his pictures.
    I am using the Raspberry Pi Rev. 2, and the Sunfounder RFID-RC522.
    For anyone who is having issues with this certain model, the pin layout in as below:
    RFID-RC522 – Rpi
    VCC- pin 1, 3.3 volts
    RST- pin 22, GPIO25
    GND- pins, 6, 9, 14, 20, or 25, I personally used pin 6
    MISO- pin 21, GPIO9
    MOSI- pin 19, GPIO10
    SCK- pin 23, GPIO11
    NSS- pin 24, GPIO7
    IRQ- Don’t Attach to rpi

    I was having problems installing subversion in debian, it would ask if you are sure with so many bytes of space being taken up
    after installation [Y/n]
    I was doing Y , enter key, and it would abort, so I tried just hitting the enter key, no y, and it worked.

  29. David

    I’ve got multiple collisions. Checked wiring 5 times, replaced RFID reader with another one but still no success. Any help would be greatly appreciated πŸ™

  30. Eli

    when i put those codes into termonal on the pi it says bcm2835_init: Unable to open /dev/mem: Permission denied
    what happened

  31. eric

    hi, sorry for my bad english πŸ™‚
    work perfect with nfc chip but nothing appears with rfid chip or card…. why?

    thanks πŸ™‚

  32. Anupam

    Hi, I am also facing the same problem which David has mentioned. I am getting multiple collisions in the output.
    I have checked my wiring and connections but everything is fine. Also, there is only ONE RFID tag around.
    Guys, please help me out

  33. Ryan

    Hello,

    I have the same issue as Craig here…
    I have it connected, if I scan cards in the debug mode it comes up telling me something like :

    Type:0400, Serial: 75305f74
    New tag: type=0400 SNlen=4 SN=[75305f74]

    If i edit the RC522.conf file in /etc, and add to the bottom
    [75305f74] wget http://MyIP:8000

    Then scan my card again in debug mode, i get:
    Type: 0400, Serial 75305f74
    Exit

    But no command is ever executed?
    I’ve tried different commands and different cards but can’t get anything to execute…

    Has anyone found a solution to this?

    Thanks in advance πŸ™‚

    Ryan

  34. Ryan

    Solved my own issue
    For the reader to execute the commands you put into the config file you have to run :

    sudo nohup /bin/rc522_reader &

    So I put that command into

    /etc/rc.local

    And has been working great ever since πŸ™‚

  35. Alex

    Hi , thanks you a lot for this simply procedure to use this technology. I’ve installed all , no problem , i use this to open gate .
    But i’ve seen that after a time .. 1 day 6 h or 12 h , script stop working .. but when i reboot or reopen script system work normally … you have some idea ?

    I use Raspbian , rfid mc522 standard as you , out but not warn about water or other

    thanks and sorry for english

  36. Alex

    First i recommend to update library bcm2385 :

    For rasberry pi 2 is good use 1.40 version not 1.35 , last 1.42 has some problems
    wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.40.tar.gz

    After for new kernel we must cut user root control to escape from many command issue , for example my command has gip control that not work as guest !

    before compilate rc522 , go on main and at line 70 – 74 :

    HW_init(spi_speed,gpio);
    read_conf_uid(&uid);
    setuid(uid);
    InitRc522();

    exclude uid control if

    and all go πŸ™‚

  37. jay

    hallo alex,
    kannst du das nochmal auf deutsch schreiben.
    dein englisch versteh ich nΓ€mlich nicht πŸ˜‰
    danke.

  38. jay

    hi alex,
    does your modification “before compilate rc522 , go on main and at line 70 – 74…”
    solve your issue “after a time .. 1 day 6 h or 12 h , script stop working”?
    jay

  39. pr0balux

    hi there,

    rc522 is working great, but to push something to the db from the python script you first need to setup corresponded mysql database with the tables given… it would be nice if you could release the db-import file for creating such tables trough the python script you guys provided.

    table rfid_card with rows name,money,counter,access

    http://sourceforge.net/projects/rc522pythonscript
    thx

  40. Steffen

    has anyone tested this setup with a raspi v2 ?
    I used it with the b+ and it works fine but my raspV2-Setup makes problems.

    Maybe I got wiring problems but maybe, you know any software-problems ?

    Greetings

    Steffen

    .

Leave a Reply

Your email address will not be published.


*