Build a Raspberry Pi RFID Attendance System

In this Raspberry Pi RFID attendance system project, we will be showing you how to set up and program your very own attendance system that makes use of the RC522 RFID reader.

Raspberry Pi RFID Attendance System


Throughout this project, we will be showing you will learn how to put together a circuit that makes use of both the RFID RC522 reader and a 16×2 LCD.

We start by showing you all the steps required to connect these circuits to the Raspberry Pi’s GPIO pins. We will also show you how to test each circuit so that it is working as it should. This helps ensure everything will be ready to be utilized in our RFID attendance system.

In the second part of the tutorial, we will walk you through all the steps to setting up a database. We will also be writing Python scripts that will talk to the database to mark attendance for individual RFID cards.

Finally, we get you to set up a straightforward PHP script that allows you to see the data produced by the RFID attendance system visually.

There is quite a bit to do in this tutorial but you will be quite happy once you have a working attendance system.

Equipment

You will need the following pieces of equipment to be able to complete this project.

Recommended

Optional

Video

We have put together a video that will go through all the steps to set up this RFID attendance system. It’s quite long but covers all the steps.

If you like a more thorough explanation, then I highly recommend reading through the full written tutorial underneath the video. We have put a lot of work into it and hope that you like it.

Adblock removing the video? Subscribe to premium for no-ads.

Preparing Raspbian for your RFID Attendance System

1. To start, we will first ensure that everything is up to date on our Raspbian installation by running the following two commands on the Raspberry Pi.

sudo apt-get update
sudo apt-get upgrade

2. We will now install all the packages that we will be relying on for the next few sections.

Let’s begin by installing build-essential, git,python3-dev, python3-pip, and python3-smbus by running the command below.

sudo apt-get install build-essential git python3-dev python3-pip python3-smbus

Building the 16×2 LCD Display Circuit

1. To start our tutorial, we will first begin setting up the 16×2 LCD. We will be quickly running through the process of setting this all up. If you want to learn more you can check out our tutorial on the 16×2 LCD Display.

For this section of the tutorial make sure that you have the following ready to go.

  • 8 pieces of Male to Male Breadboard Wire
  • 8 pieces of Male to Female Breadboard Wire
  • 16×2 LCD Display
  • 10k Ohm Potentiometer
  • Breadboard

2. Once you have all the parts required, you can start assembling the circuit by observing the diagrams and steps below.

Connecting the LCD to your Raspberry Pi is a pretty simple process if you follow our guide. We have included the physical pin number for each connection that you need to make.

To begin with, let’s connect up our various components with the breadboard.

  • 5V (Physical Pin 2) to breadboard positive rail
  • Ground (Physical Pin 6) to breadboard ground rail
  • Place the 16×2 LCD Display into the right side of the breadboard
  • Place the potentiometer into the left side of the breadboard next to the LCD Display.
  • Connect the left pin of the potentiometer to the ground rail
  • Connect the right pin of the potentiometer to the positive rail

3. Now begin connecting the LCD display to your Raspberry Pi.

  • Pin 1 of LCD (Ground) to breadboard ground rail
  • Pin 2 of LCD (VCC / 5V) to breadboard positive rail
  • Pin 3 of LCD (V0) to middle wire of the potentiometer
  • Pin 4 of LCD (RS) to GPIO4 (Physical Pin 7)
  • Pin 5 of LCD (RW) to breadboard ground rail
  • Pin 6 of LCD (EN) to GPIO24 (Physical Pin 18)
  • Pin 11 of LCD (D4) to GPIO23 (Physical Pin 16)
  • Pin 12 of LCD (D5) to GPIO17 (Physical Pin 11)
  • Pin 13 of LCD (D6) to GPIO18 (Physical Pin 12)
  • Pin 14 of LCD (D7) to GPIO22 (Physical Pin 15)
  • Pin 15 of LCD (LED +) to breadboard positive rail
  • Pin 16 of LCD (LED -) to breadboard ground rail

RFID Attendance System LCD Wiring Diagram

LCD Display Wiring Schematic
LCD Display GPIO Pins Layout

Testing the 16×2 LCD Display

1. Now that the circuit has been set up let’s go ahead and test it to ensure that everything was wired correctly.

To start, go ahead and clone the Adafruit CharLCD library that we will be utilizing for this project. If your display board uses the HD44780 controller, then it will work with no issues.

To clone the library to your Raspberry Pi run the following command on it.

git clone https://github.com/pimylifeup/Adafruit_Python_CharLCD.git

2. Now with the library cloned to our Raspberry Pi, we need to run the setup script. This script will install the library so that any Python scripts can utilize it.

Run the following two commands to move into the newly cloned directory and run the setup.py script.

cd ./Adafruit_Python_CharLCD
sudo python3 setup.py install

3. With the library installed to the Raspberry Pi, we need to go ahead and edit an example file. We need to do this to test the circuit as we are using different pins to what the example utilizes.

Begin editing the file by running the following command.

nano ~/Adafruit_Python_CharLCD/examples/char_lcd.py

4. In this file, find the “# Raspberry Pi pin configuration:” section and change it so that the values match what we have below.

# Raspberry Pi pin configuration:
lcd_rs        = 4
lcd_en        = 24
lcd_d4        = 23
lcd_d5        = 17
lcd_d6        = 18
lcd_d7        = 22

Once the changes are made, save the file by pressing CTRL + X then Y and then ENTER.

5. Now before we go ahead and run our new modified example we will need to install the Raspberry Pi’s GPIO Python library.

To install the required library run the following command.

sudo pip3 install RPi.GPIO

6. To test that everything is working lets now run that python script by running the command below. If everything is working as it should, you should now see text displayed across your LCD.

python3 ~/Adafruit_Python_CharLCD/examples/char_lcd.py

Building the RFID RC522 Reader Circuit

1. Now that you have set up the 16×2 LCD Display we will now move onto adding the RFID reader into this circuit.

For this section on wiring the RFID RC522 to the circuit, you will require the following pieces of equipment ready.

  • 1 piece of Male to Male Breadboard Wire
  • 6 pieces of Male to Female Breadboard Wire
  • RFID RC522 Read/Writer
  • Breadboard

2. Once you have everything that you need for the RFID circuit we can then proceed on to wiring everything up, this will be slightly more complicated thanks to the LCD circuit being already set up.

Please note that this circuit diagram is assuming that you have followed the steps in the previous section for the LCD Display. If you are not utilizing the LCD, make sure you connect Physical Pin 6 on the Raspberry Pi to the ground rail on the breadboard.

Follow the diagrams and steps below to wire the RFID circuit up to the Raspberry Pi.

  • SDA connects to GPIO8 (Physical Pin 24)
  • SCK connects to GPIO11 (Physical Pin 23)
  • MOSI connects to GPIO10 (Physical Pin 19)
  • MISO connects to GPIO9 (Physical Pin 21)
  • GND connects to Breadboard Ground Rail.
  • RST connects to GPIO25 (Physical Pin 22)
  • 3.3v connects to 3v3 (Physical Pin 1)

RC522 RFID Attendance System Wiring Diagrams

RFID RC522 Attendance System Wiring Schematic
RFID RC522 Attendance System GPIO Pins Layout

Enabling the SPI interface

1. With the RFID now wired to our Raspberry Pi, we will need to go into the raspi-config tool to enable the SPI interface. This interface is required so that we can communicate with the RC522 module.

To do this, you need to first launch the raspi-config tool by running the following command.

sudo raspi-config

2. Upon running the command, you will see with a screen showing various options that you can configure.

For now, we are only interested in activating the SPI interface. If you want to learn more, you can check out our ultimate guide to the Raspi-Config tool.

On this screen use your ARROW keys to go down and select “5 Interfacing Options” and press ENTER.

3. On the next screen, you will want to use your ARROW keys to select the “P4 SPI” option, once selected press ENTER.

4. You will now need to confirm if you want to enable the SPI Interface. To this, you will want to use your ARROW keys to select “Yes” and then press ENTER once it’s selected.

5. The SPI Interface should now be successfully enabled, and you should now see the text “The SPI interface is enabled” appear on the screen.

Now before the SPI interface is fully enabled, we will need to restart the Raspberry Pi. We can achieve this by going back to the terminal by pressing ENTER and then ESC.

Enter the following command to restart the Raspberry Pi.

sudo reboot

6. Once the Raspberry Pi has finished rebooting, you can verify that the SPI interface has been enabled by running the following command.

This command will retrieve the list of enabled kernel modules and grab anything from that list that contains the text “spi“.

lsmod | grep spi

If you see the text “spi_bcm2835” appear in the command line, then you are now ready to proceed to test that the circuit is working correctly. Once that is done we can set up our RFID powered attendance system.

If it doesn’t appear, then we recommend you check out our guide on setting up the RFID RC522 for other methods of enabling the correct kernel module.

Testing the RFID RC522

1. Let’s now install the spidev library to our Raspberry Pi by using the following “pip” command.

We rely on the spidev library to interact with the RFID reader interface.

sudo pip3 install spidev

2. Now that we have installed the spidev library to our Raspberry Pi we need to proceed to download the MFRC522 library by using the “pip” command.

This library is what will handle the grunt work for our RFID attendance system.

sudo pip3 install mfrc522

3. Now that we have both the MFRC522 library and the spidev library installed to our Raspberry Pi let’s go ahead and make a directory to keep our test script.

mkdir ~/pi-rfid

4. Now we will need to write a short script to test that our RC522 is, in fact, able to read RFID cards and that everything is wired correctly.

First, let’s open up our new script by running the following command, this will create a file called “read.py” in our recently created directory.

nano ~/pi-rfid/read.py

5. Enter the following lines of code into this file. If you want an explanation of everything here, then we recommend checking out our full guide on the RFID RC522.

#!/usr/bin/env python

import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522

reader = SimpleMFRC522()
try:
        id, text = reader.read()
        print(id)
        print(text)
finally:
        GPIO.cleanup()

Once done, save the file by pressing CTRL + X then Y and ENTER.

6. Now test the RFID RC522 by running the following script and tapping your RFID chip on the reader.

python3 ~/pi-rfid/read.py

The Full Raspberry Pi RFID Attendance System Circuit

1. With both circuits now setup, double check that everything is working correctly. Test by running the test scripts that we quickly put together in a previous couple of sections.

If you are having issues, you can compare your final circuit to the diagrams below. These diagrams are designed to give you an idea of how the final circuit should look.

RFID Attendance System Circuit Schematic

LCD Display and RFID RC522 Schematic

RFID Attendance System GPIO Pins Utilized

LCD Display and RFID Raspberry Pi GPIO Pins Layout

Preparing the RFID Attendance System Database

1. Now before we go ahead and program our RFID attendance system, we must first prepare and set up the MYSQL database. This database is where we will be keeping track of each RFID cards attendance and who owns that RFID card.

You can delve into setting up MYSQL a bit deeper by following our MySQL tutorial and PHPMyAdmin guide. Our RFID Attendance system will walk you through most of the basics but the extra guide will teach you how to setup useful tools like PHPMyAdmin.

Begin by installing MYSQL to your Raspberry Pi by running the following command on your Pi.

sudo apt-get install mysql-server -y

2. Next, we will need to run the “secure installation” script that comes packaged with MYSQL. This script will run you through some processes on making your MYSQL server more secure.

Run this script by running the following command within the terminal on the Raspberry Pi.

sudo mysql_secure_installation

When prompted make sure that you set a new password for the root MYSQL server. Additionally, you should answer “y” to most prompts such as disabling root login access to your MYSQL server.

3. Now let’s load up into the MYSQL command-line tool by running the following command. You will be prompted to enter the password you set in the previous step.

As MariaDB when installed utilizes “UNIX_SOCKET” as the authentication method by default, we are required to log in using the superuser, do this by using “sudo“.

sudo mysql -u root -p

4. Let’s begin by creating a database where we will be storing all of the data that we will be utilizing for our RFID attendance system.

We will be naming this database, “attendancesystem“. To create this database, run the following command.

CREATE DATABASE attendancesystem;

5. With our database created, let’s now create a user called “attendanceadmin” we will utilize this user in our Python scripts to read from our newly created database.

Make sure you set the password for this to something unique and hard to guess. For our example, we will be just using “pimylifeup” as the password.

CREATE USER 'attendanceadmin'@'localhost' IDENTIFIED BY 'pimylifeup';

6. Now that we have created our user we need to give it the rights to access our “attendancesystem” database.

We can do this by running the following command. This command will give our “attendanceadmin” user full privileges on any table within our database.

GRANT ALL PRIVILEGES ON attendancesystem.* TO 'attendanceadmin'@'localhost';

7. Before we create our tables, we need to utilize the “use” command so that we are directly interacting with the “attendancesystem” database.

Begin interacting with the database by running the following command.

use attendancesystem;

8. Now that we are dealing directly with the database that we want to utilize we can now start creating the tables where all our data will be stored.

Running the following two commands will create the tables that we will rely on for storing data. We will explain the fields in these tables after we have created them.

create table attendance(
   id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
   user_id INT UNSIGNED NOT NULL,
   clock_in TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
   PRIMARY KEY ( id )
);

create table users(
   id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
   rfid_uid VARCHAR(255) NOT NULL,
   name VARCHAR(255) NOT NULL,
   created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
   PRIMARY KEY ( id )
);

You can leave the MYSQL tool by entering exit;

Now that we have created the tables let’s take a look at the data we will be storing and how we will be using it in our script.

For the attendance table, we are holding three pieces of data for each recorded RFID tap.

  • id – This is an integer that is used to keep track of the current row and increases automatically.
  • user_id – This is an integer, and we utilize this to tie attendance with a user in our users table that has the same id.
  • clock_in – This variable stores a SQL timestamp. This timestamp is used to track when the user taps their RFID card onto the RFID reader.

For the users table, we are holding four pieces of data for each user that we add.

  • id – This is an integer that is used to keep track of the current user and increases automatically.
  • rfid_uid – This variable is used to store the UID that is captured when an RFID card is tapped on the RFID reader.
  • name – This variable stores the name of the person who owns the RFID card.
  • created – We use this variable to keep track of when the user was created.

Recording a User in the Attendance System

1. Before we get writing our attendance system scripts, we need first to install the Python “MYSQL Connector” using pip.

Install the connector library by running the following command on your Pi.

sudo pip3 install mysql-connector-python

2. Let’s now create a folder to keep everything for this project.

mkdir ~/attendancesystem

3. Time to start writing our first Python script for our attendance system. This first script will allow you to create a user based on a tapped RFID card.

Upon tapping the RFID card, the Python script will ask you to enter a username to register this card to a person.

Start writing the first part of our attendance system by running the following command.

nano ~/attendancesystem/save_user.py

4. Into this new file write the following lines of code. We will explain what each section of code does as we go and why we are utilizing that code.

#!/usr/bin/env python

We add this line so that the operating system knows that this file should execute using Python.

import time

We import the time library so that we can put the script to sleep, so things don’t occur instantly.

import RPi.GPIO as GPIO

We require the GPIO library so that we can run the cleanup function when the script ends.

from mfrc522 import SimpleMFRC522

The SimpleMFRC522 library is used to make it easy to talk with our RFID reader.

import mysql.connector

We utilize the MySQL connector so that we can talk with the database that we set up earlier.

import Adafruit_CharLCD as LCD

Finally, we load in the Adafruit library for talking with LCDs. This library simplifies the process of communicating with our 16×2 display significantly.

db = mysql.connector.connect(
  host="localhost",
  user="attendanceadmin",
  passwd="pimylifeup",
  database="attendancesystem"
)

In this section of the code, we create our connection to our MYSQL server. For this function, we pass in all the information required to make the connection such as the host, user, database name and the password.

The object created by the connector is stored in the “db” variable so that we can interact with the database easily.

Make sure when entering this code that you replace the password with the one you set earlier in this guide for the “attendanceadmin” SQL user.

cursor = db.cursor()

Here we instantiate a copy of the cursor object from our database connection. We utilize this object to interact with the database and to execute SQL queries.

reader = SimpleMFRC522()

Now we prepare the SimpleMFRC522 library by instantiating it to our reader object. This library will allow us to easily talk with the RC522 later in the script to read input from the reader.

lcd = LCD.Adafruit_CharLCD(4, 24, 23, 17, 18, 22, 16, 2, 4);

Our final setup line, this line prepares the CharLCD library for dealing with out 16×2 display. For this function, we pass in all the required pin numbers, amount of rows and more.

try:
  while True:
    lcd.clear()
    lcd.message('Place Card to\nregister')
    id, text = reader.read()

This block of code is the start of our user creation logic. We will be wrapping the entirety of our logic first in a “try:” statement, we will explain why later on in this guide.

We also wrap our logic in a while True loop. This loop will ensure that the code below will run indefinitely so that the end user can register multiple users in succession.

Next, we clear the LCD on every loop to ensure we are dealing with a clean display before writing “Place card to register” to the screen. This text prompts the user to place their RFID card onto the reader.

Finally, we utilize our SimpleMFRC522 library to read input in from our reader. This function will wait until a user places their RFID reader before it returns both the id of the card and the text stored on it.

    cursor.execute("SELECT id FROM users WHERE rfid_uid="+str(id))
    cursor.fetchone()

In this section, we use the cursor to execute our first bit of SQL. In this SQL statement we are simply searching our “users” table to see if any rows have a matching RFID UID to the ID we retrieved when reading the RFID card.

To grab the data that we retrieved we utilize another function from the cursor object, specifically the “fetchone()” function. This function will grab one row from the returned results.

    if cursor.rowcount >= 1:
      lcd.clear()
      lcd.message("Overwrite\nexisting user?")
      overwrite = input("Overwite (Y/N)? ")

      if overwrite[0] == 'Y' or overwrite[0] == 'y':
        lcd.clear()
        lcd.message("Overwriting user.")
        time.sleep(1)
        sql_insert = "UPDATE users SET name = %s WHERE rfid_uid=%s"
      else:
        continue;
    else:
      sql_insert = "INSERT INTO users (name, rfid_uid) VALUES (%s, %s)"

We start in this section by checking how many rows were returned by our last SQL call.

If the SQL call returns any rows,  we need to prompt the user whether they want to overwrite the already existing user.

Inside the if statement we proceed to clear the LCD screen and display the message “Overwrite existing user?” and provide a prompt in the command line for the user to respond either Y to overwrite or anything else to cancel.

Once the input function has received the input, we then check to see if the first character of the returned data is equal to ‘Y‘ or ‘y‘.

If the first character does equal what we expect we then clear the LCD again. Next we display a message “Overwriting user” for one second.

Lastly, we build the SQL query to update the existing entry with the new name that we specify in the next step. We do this process instead of deleting the old entry and re-adding it.

If the user responds anything but ‘Y‘ and ‘y‘ to the input function we then skip back to the start of the loop by using “continue“.

If this was not a duplicate entry, we build a different SQL query to create a new entry in our “users” table. This new entry will contain the new name that we specify in the next block of code and the RFID ID that we obtained when the user tapped their card.

    lcd.clear()
    lcd.message('Enter new name')
    new_name = input("Name: ")

    cursor.execute(sql_insert, (new_name, id))

    db.commit()

    lcd.clear()
    lcd.message("User " + new_name + "\nSaved")
    time.sleep(2)
finally:
  GPIO.cleanup()

Our final segment of code is quite simple and wraps everything up. We start by clearing the LCD again and prompting the user on the LCD that they need to enter a new name.

Meanwhile on the console, the text “Name: ” should appear as we utilize “input” to await the user’s input.

Once a user has input a name into the console and pressed enter we then proceed to utilize the cursor object to execute the query that we formed in the previous section of code.

We also create a tuple that’s passed into the execute function. This tuple contains the new name and the RFID card’s id. Both these values will automatically pass into our query strings on execution.

Finally, we commit the changes to the database by calling the “db” object with the “.commit()” function. If we don’t call this function, our INSERT and UPDATE queries will not occur.

We end our main code logic by clearing the LCD again and displaying a message that the new user has saved. We run a quick 2-second sleep to give the user enough time to see the message before we restart the loop.

Lastly, we have our “finally:” statement, this is the other part of our “try:” statement. This bit of code ensures that no matter what happens we will run the “GPIO.cleanup” function. For example, if we press CTRL + C while the script is running, it should still clean up the GPIO status.

6. Hopefully, at this point, you will have finished writing the script into the file.

However, if you would like to check over and ensure that everything is correct, then you can find the full version of the code below.

Once you are happy with everything, save the file by pressing CTRL + X then Y and finally ENTER.

#!/usr/bin/env python

import time
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import Adafruit_CharLCD as LCD

db = mysql.connector.connect(
  host="localhost",
  user="attendanceadmin",
  passwd="pimylifeup",
  database="attendancesystem"
)

cursor = db.cursor()
reader = SimpleMFRC522()
lcd = LCD.Adafruit_CharLCD(4, 24, 23, 17, 18, 22, 16, 2, 4);

try:
  while True:
    lcd.clear()
    lcd.message('Place Card to\nregister')
    id, text = reader.read()
    cursor.execute("SELECT id FROM users WHERE rfid_uid="+str(id))
    cursor.fetchone()

    if cursor.rowcount >= 1:
      lcd.clear()
      lcd.message("Overwrite\nexisting user?")
      overwrite = input("Overwite (Y/N)? ")
      if overwrite[0] == 'Y' or overwrite[0] == 'y':
        lcd.clear()
        lcd.message("Overwriting user.")
        time.sleep(1)
        sql_insert = "UPDATE users SET name = %s WHERE rfid_uid=%s"
      else:
        continue;
    else:
      sql_insert = "INSERT INTO users (name, rfid_uid) VALUES (%s, %s)"
    lcd.clear()
    lcd.message('Enter new name')
    new_name = input("Name: ")

    cursor.execute(sql_insert, (new_name, id))

    db.commit()

    lcd.clear()
    lcd.message("User " + new_name + "\nSaved")
    time.sleep(2)
finally:
  GPIO.cleanup()

7. With our “save_user” script saved let’s go ahead and take it for a whirl to ensure that everything is operating as it should be and there are no mistakes from copying the code.

Run the script by running the following command.

python3 ~/attendancesystem/save_user.py

8. Tap your RFID card and see if everything is working as intended if it’s not double check your code and wiring. If you see “User Saved” then everything should be working.

Recording Attendance

1. Now that we have written our “save_user” script and ensured that it is working correctly let’s move onto our “check_attendance” script.

This script will run in an infinite loop checking for any taps from an RFID chip. When someone taps their RFID chip, we will check that chip’s ID in the database.

If it finds a user, we set a welcome message and insert an entry into our attendance table that will have the current date and time.

Let’s start the process of writing the script by using the following command.

nano ~/attendancesystem/check_attendance.py

2. Enter the following lines of code. We will explain each new section of code as we go, you will be familiar with some of this as we utilized it within the save user script in the previous section.

#!/usr/bin/env python
import time
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import Adafruit_CharLCD as LCD

db = mysql.connector.connect(
  host="localhost",
  user="attendanceadmin",
  passwd="pimylifeup",
  database="attendancesystem"
)

cursor = db.cursor()
reader = SimpleMFRC522()

lcd = LCD.Adafruit_CharLCD(4, 24, 23, 17, 18, 22, 16, 2, 4);

try:
  while True:

We won’t go too much into this block of code as it is all reused from our first “save_user.py” script that we wrote in the last section of this Raspberry Pi RFID attendance system tutorial.

The main thing that you need to remember is to replace your database password that is specified next to “passwd” as by default it is our example password, “pimylifeup“.

    lcd.clear()
    lcd.message('Place Card to\nrecord attendance')
    id, text = reader.read()

In this block of code, we clear the LCD screen and display a message to prompt the user to place their card to record attendance. We then wait for a response from the RFID reader.

    cursor.execute("SELECT id, name FROM users WHERE rfid_uid="+str(id))
    result = cursor.fetchone()

    lcd.clear()

Here we execute our first bit of SQL. This SQL statement grabs both the “id” and “name” from our “users” table where the user has the same RFID ID as the card that was tapped on the reader.

We then grab the row that is returned by the SQL query and store its result into our “result” variable for later use.

Finally, we clear the LCD screen so that it’s ready to print a new message to in our next section of code.

    cursor.execute("SELECT id, name FROM users WHERE rfid_uid="+str(id))
    result = cursor.fetchone()

    lcd.clear()

In this section, we first check to see if the last SQL request returned any rows. If it returned 0, then we display a message to the 16×2 display that the “User does not exist.

If we do have a row, we then proceed to display a message welcoming the user. We use their name that was retrieved from the database as result[1].

Afterward, we make an SQL statement to insert a row into our attendance table. We need to pass in the user’s id that we retrieved from our previous SQL call and is stored in result[0].

Finally, we commit changes to the database.

    time.sleep(2)
finally:
  GPIO.cleanup()

Our final section of code is straightforward. We put the script to sleep for two seconds to give the user time to read the message we display on the 16×2 display and to remove the RFID card.

The “finally:” statement ensures that we clean up the GPIO once the script has finished.

3. Once you have finished entering all the code, you can check it against the full version that is right below.

The main thing to pay attention to when entering all the code is to ensure all the indentations are the same. Two spaces should separate each level.

Once you are happy that everything is correct, save the file by pressing CTRL + X then Y and finally ENTER.

#!/usr/bin/env python
import time
import RPi.GPIO as GPIO
from mfrc522 import SimpleMFRC522
import mysql.connector
import Adafruit_CharLCD as LCD

db = mysql.connector.connect(
  host="localhost",
  user="attendanceadmin",
  passwd="pimylifeup",
  database="attendancesystem"
)

cursor = db.cursor()
reader = SimpleMFRC522()

lcd = LCD.Adafruit_CharLCD(4, 24, 23, 17, 18, 22, 16, 2, 4);

try:
  while True:
    lcd.clear()
    lcd.message('Place Card to\nrecord attendance')
    id, text = reader.read()

    cursor.execute("Select id, name FROM users WHERE rfid_uid="+str(id))
    result = cursor.fetchone()

    lcd.clear()

    if cursor.rowcount >= 1:
      lcd.message("Welcome " + result[1])
      cursor.execute("INSERT INTO attendance (user_id) VALUES (%s)", (result[0],) )
      db.commit()
    else:
      lcd.message("User does not exist.")
    time.sleep(2)
finally:
  GPIO.cleanup()

4. With our script saved let’s go ahead and quickly run through it to check that everything is working as it should be.

Run the script by entering the following command and follow the prompts displayed on the 16×2 display.

python3 ~/attendancesystem/check_attendance.py

If you run into any errors, make sure you double check all the code has been entered correctly.

Checking the Database

1. Now that we have written and tested both our save user script and our check attendance script lets go ahead and take a look at our database to see the new entries.

Fire up the MYSQL command line tool by running the following command. You will be prompted to enter the password that you entered for the root user before continuing.

We utilize sudo for this command as MariaDB by default uses UNIX_SOCKET for authentication.

sudo mysql -u root -p

2. Once you have connected into the MYSQL command line, we need to utilize the “use” command. We need to use this command so that we can interact our “attendancesystem” database.

Run the following command to interact with the “attendancesystem” database.

use attendancesystem;

3. Now that we are directly interacting with our “attendancesystem” database let’s start by checking out all the users that have been created by our script.

We can do this by running a simple SELECT SQL call that specifies our “users” table. The asterisk (*) used in the query below means that we want to grab all columns.

Type in the following command to grab all the users available in the “users” table.

SELECT * FROM users;

From this command, you should see something like what we have below.

+--+------------------+---------+------------------------+
| id | rfid_uid       | name    | created                |
+--+------------------+---------+------------------------+
|  1 | 160747764001   | Emmet   | 2019-01-31 11:28:04    |
+--+------------------+---------+------------------------+

4. Now that we have checked the “users” table let’s go ahead and take a look at our “attendance” table. Just like the previous query we made we are just selecting all columns from the “attendance” table.

Enter the following command to grab all the data.

SELECT * FROM attendance;

From this command you should see something like what we have below in the command line. You can reference the “user_id” back to the “users” table “id” to see which user clocked in.

+----+---------+---------------------+
| id | user_id | clock_in            |
+----+---------+---------------------+
|  6 |       1 | 2019-02-01 03:23:30 |
|  7 |       1 | 2019-02-01 03:35:36 |
|  8 |       1 | 2019-02-01 03:36:51 |
+----+---------+---------------------+

You can leave the MYSQL tool by entering “exit;“.

Building a Web Front-End

1. Before you start this section, we require that you to have set up NGINX for use with PHP. You can find out how to do this by following our Raspberry Pi NGINX guide.

Once you have NGINX and PHP up and running, we can now begin writing a bit of a frontend to our attendance system. This frontend is so that you can visually see the current users and when they have tapped on the reader.

Start by making a directory to keep our scripts within the default NGINX folder.

sudo mkdir /var/www/html/attendance

2. You should already have GIT installed on the Raspberry Pi, so now is the time to clone our frontend scripts to the folder that we created in the first step.

Clone the code from our GitHub repository by running the following command. This command will use git to clone the code into the attendance folder.

sudo git clone https://github.com/pimylifeup/attendance-system-frontend.git /var/www/html/attendance

3. With the script now cloned, we will need to make one modification to the “common.php” file so that we utilize the database logins that you set up during this guide.

Begin modifying the script by running the following line.

sudo nano /var/www/html/attendance/common.php

4. Within this script, find the following section and make sure to replace the password with your own.

Find:

    'password'      => 'pimylifeup'

Once you have changed the line, save the file by pressing CTRL + X then Y and ENTER.

5. For our frontend scripts, we make use of “medoo” and “bootstrap“. Medoo is a lightweight framework for dealing with databases like the one we set up for our attendance system.

Bootstrap, on the other hand, is a front-end framework that makes it much easier to develop clean looking front ends without having to worry about writing a ton of CSS.

With the scripts now cloned to the directory, you should now be able to check out the frontend by going to your Raspberry Pi’s IP Address and adding “/attendance” to the end of the URL as shown below.

http://192.168.160/attendance

6. Upon going to the website, you will be greeted by the following webpage, from here you can either check out your current users by clickingUsers” or viewing the attendance of users by clicking the “Attendance” button.

If you have gotten to this point, then everything is working as it should be and you should now have a basic RFID, and Raspberry Pi powered attendance system up and running.

Welcome Page

Raspberry Pi RFID Attendance Welcome Page

Attendance System Users Page

RFID Attendance System Users Page

Attendance Page

Raspberry Pi RFID Web Attendance Page

The overall system is relatively basic but covers everything you need for a good attendance system. You can further extend both the backend and frontend to implement new features, a nicer user interface and much more.

I hope by now that you have a full working Raspberry Pi RFID attendance system. If you have some feedback, tips or anything else, then please don’t hesitate to leave a comment below.

48 Comments

  1. Avatar for manar
    manar on

    by any chance do you know how to delete an attendance? sometimes while putting the RFID card it record attendance more then one time at the same second
    so i was wondering if there’s a way to delete and attendance

    1. Avatar for manar
      manar on

      i found how by DELETE FROM products WHERE product_id=1;

  2. Avatar for Celly
    Celly on

    This is awesome, works like a charm also with MariaDB, Thank you Emmet for sharing 🙂

  3. Avatar for Graham Brown
    Graham Brown on

    Thanks so much for this, I have been playing to try to get a “Clocked in status” always recorded for a quick and easy check of who is on site. I have modified the user table with a status column and I used the script below in attendance.py but I get errors pertaining to inconsistent use of tabs on the UPDATE command.

    try:
      while True:
        lcd.clear()
        lcd.message('Place Card to\nrecord attendance')
        id, text = reader.read()
    
        cursor.execute("Select id, name, status FROM users WHERE rfid_uid="+str(id))
        result = cursor.fetchone()
    
        lcd.clear()
    
        if cursor.rowcount >= 1:
          lcd.message("Welcome " + result[1])
          cursor.execute("INSERT INTO attendance (user_id) VALUES (%s)", (result[0],) )
          if result[2] = 0:
    		cursor.execute(UPDATE names SET status = 1 WHERE id = rfid_uid)
    	  else:
    		cursor.execute(UPDATE names SET status = 0 WHERE id = rfid_uid)
    	  db.commit()
        else:
          lcd.message("User does not exist.")
        time.sleep(2)
    finally:
      GPIO.cleanup()

    Any idea what’s wrong there?

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Graham,

      From a quick look at the code you provided the whitespace for your lines is completely out of whack which is where the issues would be occurring.

      In the code examples we have used spaces and not tabs which is possibly where this issue is stemming from. The new bits of code that you have added are using a tab rather than just several spaces.

      Quickly cleaning it up it should end up looking a bit like we what have below.

      try:
          while True:
              lcd.clear()
              lcd.message(‘Place Card to\nrecord attendance’)
              id, text = reader.read()
      
              cursor.execute(“Select id, name, status FROM users WHERE rfid_uid=”+str(id))
              result = cursor.fetchone()
      
              lcd.clear()
      
              if cursor.rowcount >= 1:
                  lcd.message(“Welcome ” + result[1])
                  cursor.execute(“INSERT INTO attendance (user_id) VALUES (%s)”, (result[0],) )
                  if result[2] = 0:
                      cursor.execute(UPDATE names SET status = 1 WHERE id = rfid_uid)
                  else:
                      cursor.execute(UPDATE names SET status = 0 WHERE id = rfid_uid)
                  db.commit()
              else:
                  lcd.message(“User does not exist.”)
                  time.sleep(2)
      finally:
          GPIO.cleanup()

      Basically all you should need to do is ensure that all your indentation is consistent as Python is whitespace sensitive. Something one space ahead is considered to be in a different block and a tab is considered completely different to a space.

      Cheers,
      Emmet

  4. Avatar for Bola
    Bola on

    Hi,
    I am currently using windows 10 and I notice that my computer terminal does not recognise
    sudo apt-get update
    sudo apt-get upgrade
    Does the sudo command only work for mac?

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Bola,

      These commands need to be ran on your Raspberry Pi not your PC.

      You can do this by using your Raspberry Pi’s terminal directly or by connecting to it using SSH.

      Cheers,
      Emmet

  5. Avatar for EWAN PARRY
    EWAN PARRY on

    What are the possibilities of adapting this system to a book control system for the school library. Im thinking in terms of cost for the tags. Can you get the stick on types for books that would work with this system?

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Ewan,

      Honestly it would not take much to convert this system to be usable for a school library.

      I haven’t looked in to it to much but you can purchase sticker versions of the tags, you would have to look up for the best pricing of it. All they need to do is support the RC522 chip (So should use the MIFARE Classic 1K standard)

      Cheers,
      Emmet

  6. Avatar for Dechen
    Dechen on

    Hello Author,
    I don’t have LCD display, how should i proceed with the code?

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Dechen,

      Please refer to my reply to Maria Sabatini below.

      It should answer your question.

      Cheers,
      Emmet

  7. Avatar for Ervin Bartha
    Ervin Bartha on

    Hello Emmet,

    thanks for your tutorial it was really easy to set it up using your great tutorial, everything is working as you described.

    BR
    Ervin

  8. Avatar for David B
    David B on

    Hi Emmet,

    Great tutorial. Before I dive into buying parts, at what minimum and maximum distance can the detector work? i.e. Could my students walk through the door 10′ away and be detected in class?

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi David,

      The problem with this is that as its a near-field device it is not designed to have a very long range. From waht I have read even if you maxed out the gain on the RC522 you would only get a range of about 5cm.

      For this solution you would need to get the students to tap the card to be able to record their attendance.

      Cheers,
      Emmet

  9. Avatar for Elaine
    Elaine on

    Hi,
    I’m using SQLite to create a database but the “id INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE” give me a syntax error. I’m not sure if SQLite is using different syntax.

    Do you know the solution to this problem? Thank you

    regards,
    Elaine Teoh.

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Elaine,

      SQLite doesn’t have the same functionality and data type support as MySQL. However I can’t see anything that we are using in this tutorial a quick glance that would break in SQLite.

      Can you please provide the syntax error that you are running into?

      Cheers,
      Emmet

  10. Avatar for Jan
    Jan on

    Hi Emmet,

    Thanks a lot for this wonderful straight forward tutorial.
    Even with my 9 left thums I got it.

    I run it on a Raspberry Pi Zero WH V3.0 with the I2C-Version of the LCD1602.

    Real fun.

    Thanks a lot and best wishes
    Jan

  11. Avatar for Maria Sabatini
    Maria Sabatini on

    hello, thank you for providing this tutorial. I was wondering if this tutorial is or can be provided in a version which doesnt incorporate the LCD screen as when setting up the save_user file i am strugling to write the code to just have the information displayed on the terminal. Is there any way to do this?

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Maria,

      Removing the need for the LCD is a fairly straightforward process.

      First remove the LCD import.

      import Adafruit_CharLCD as LCD

      Next remove the LCD instantiation.

      lcd = LCD.Adafruit_CharLCD(4, 24, 23, 17, 18, 22, 16, 2, 4);

      Remove all references to clearing the LCD screen.

      lcd.clear()

      Replace the following text.

      lcd.message(

      With the following

      print(

      For example the following

      lcd.message('Place Card to\nregister')

      Would become

      print('Place Card to\nregister')

      Cheers,
      Emmet

  12. Avatar for Tetauru Pihama
    Tetauru Pihama on

    Hi Emmet,

    Thanks for this tutorial I followed every step and it worked perfectly. I was wondering if you have made any advancements on this tutorial. ie. At the frontend only seeing the last seven days, if users are late but before 10:30am an alert email is sent to the admins email address, creating a report for daily, weekly, monthly, and term attendance to name a few :). If so could you point me to the links of these.

    Thanks for your awesome work!

    1. Avatar for Tetauru Pihama
      Tetauru Pihama on

      Also forgot to mention that I didn’t install the 16 x 2 LCD screen as I did not require it. All cards are written via terminal and students and staff will not need to view anything.

    2. Avatar for Emmet
      Emmet on
      Editor

      Hi Tetauru,

      Im glad that you are having success with using the system as it currently stands.

      Sadly I haven’t done any improvements to the system since I first wrote the guide, however I am considering writing a guide on the PHP scripts itself and doing a series of tutorials based around improving it and adding extra fuctionality to it.
      We are currently trying to see how much interest there is in guides like that.

      Cheers,
      Emmet

  13. Avatar for raul
    raul on

    Hi Emmet
    Thanks for this great tutorial.
    would it be possible to add new users via the website instead of the command line?
    I was thinking to have a website to add users and read the RFID cards.
    thanks

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Raul,

      It is possible but you would have to write a far more complex system then what this tutorial comes with.

      Cheers,
      Emmet

  14. Avatar for David
    David on

    Hi!
    I want to order the equipment but I don’t know what kind of cable do i need for the project. Male to male, male to female or female to female?
    Looking for your answer!

    Dave

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi David,

      You will need at least the following amount of breadboard wire and type.

      9 pieces of Male to Male Breadboard Wire
      14 pieces of Male to Female Breadboard Wire

      Cheers,
      Emmet

  15. Avatar for Shaan B
    Shaan B on

    Hey Emmet!

    I was able to follow along and get everything working with some additional changes :D. I wanted to make some further changes/additions but I don’t know the best approach.

    Regarding the website, I’d only like to see two days in the month rather than the whole calendar. Right now, I need to scroll to the 24th to see the logs from the RFID reader. Any thoughts on how I can make this change?

    Also, I want to create another column that outputs the delta of the past two timestamps or scans. Not to familiar with MySQL, so I wasn’t sure how to do this.

    Any advice would be appreciated, thanks for the great guide!

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Shaan,

      This shouldn’t be super difficult (I might actually write a tutorial on the php script at one point if there is enough interest)

      Here’s some quick modifications I came up with quickly. I haven’t had the chance to test these changes, but they should work.

      Within the attendance.php file you could modify the for loops slightly so that it will only show the current day and the previous day.

      Add the following code somewhere near the top. This code will basically grab the current day then work out the day

      $start_days = date('j') - 1;
      if ($start_days <=0) { $start_days = 1; } $end_days = date('j');

      Then replace the following two loops
      for ( $iter = 1; $iter <= $num_days; $iter++) {
      With
      for ( $iter = $start_days; $iter <= $end_days; $iter++) {

      This is very basic, and it wont handle new months well. Like on the 1st you will get two of the same day displayed as it doesn't take the previous month's days into consideration.

      Ideally the script would be improved so that it can handle date ranges a lot better rather then its static behaviour at the moment.

      Cheers,
      Emmet

  16. Avatar for joseph
    joseph on

    hello Emmet,
    Thanks for the great work this is indeed a wonderful project, i really appreciate your effort to share this information with us. Have a quick question.
    Have followed every step in this tutorial and i must admit its perfect.
    when it comes to Building a Web Front-End STEP Number 5.
    i Cannot get the frontend running.
    Nginx php-v7 is running properly.
    when i put my https:// ip address /attendance
    nothing comes

    hope to hear from you thanks in advance.
    Regards
    Jo.

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Joseph,

      Could you please try installing the MYSQL component for PHP. I’ve seen some cases where this was not installed which has caused issues previously.

      You can install it by running the command below.

      sudo apt-get install php7.0-mysql

      Cheers,
      Emmet

    2. Avatar for Thomas
      Thomas on

      This is exactly what I need. Thank you so much for this awesome tutorial!

      I’m having the same issue as Joseph though. I have `php7.3.4-2` installed. I followed your tutorial for setting up NGINX, and can see the `phpinfo()` output when I navigate to the IP address. However, when I navigate to http://ip_address/attendance, I get a 500. “`This page isn’t working. ip_address is currently unable to handle this request. HTTP ERROR 500“`.

      Do you have any troubleshooting ideas?

    3. Avatar for Thomas
      Thomas on

      I realize my issue. I did the MySQL setup on Stretch, then updated to Buster, where MySQL was replaced by MariaDB. I installed and setup MariaDB and php-mysql again, and it works now.

    4. Avatar for Wendy
      Wendy on

      Hi Emmet,
      A great tutorial that’s for sure, tank you so much.

      Could you please help me with something. Whenever I try making the frontend I’m having problems when tying the https://ip adress/attendance. I would get the error that the site can’t be reached. Do you know what is the problem? Already a lot of thank you in advance!

      Kind regards,
      Wendy

    5. Avatar for Emmet
      Emmet on
      Editor

      Hi Wendy,

      Assuming that you have set up NGINX correctly through our tutorials it could simply be that HTTPS hasn’t been set up.

      Try connecting to your server by replacing https with http.

      Cheers,
      Emmet

  17. Avatar for Nando
    Nando on

    Hi,

    What about checking-out with your rfid chip? Is this feature also working with this Guide?

    If not: Is this a feature that could be easily added to this setup?

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Nando,

      That is definitely something that should easily be able to be added. The code is fairly simple to follow and should be easily expandable and adjustable.

      Cheers,
      Emmet

  18. Avatar for Simeon
    Simeon on

    Works fine Kudos. How do I set a check to make sure no double attendance taken for one card like if the attendance has been marked for a day it shouldn’t allow it again until next day?

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Simeon,

      You could do this by writing a SQL call to select any rows that contain that RFID on the current date. If it returns a row then don’t proceed with it.
      It shouldn’t be to hard to add that just learning from the code currently there.

      You will likely need to make use of the python datetime package to generate the correctly formatted date for searching the database.

      Cheers,
      Emmet

  19. Avatar for HADI
    HADI on

    can I do this project with raspberry pi zero W ???

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi Hadi,

      Yes it is fully possible to do this tutorial on a Raspberry Pi Zero W.

      Cheers,
      Emmet

    2. Avatar for Shane
      Shane on

      And you can simplify the lcd wiring by using the I2C backpack and using an rfid reader that is also i2c interface. You can then pretty much use 4 wires chained to both devices. Just be aware of the voltages, may need a logic level converter or add a voltage divider. Raspberry uses 3.3v I2C…don’t want to let the smoke out by connection to a 5v device 😁

  20. Avatar for Muhammad Tahmid
    Muhammad Tahmid on

    Hello, I am getting this error code:

    Traceback (most recent call last):
    File “/home/pi/attendancesystem/save_user.py”, line 6, in
    import mysql.connector
    ImportError: No module named ‘mysql’

    Do you know the solution to this?

    1. Avatar for Emmet
      Emmet on
      Editor

      Hi,

      You need to of followed step 1 in the “Recording a User in the Attendance System” section.

      This step installs the python mysql connector.

      Cheers,
      Emmet

Leave a Reply

Your email address will not be published. Required fields are marked *