Introduction: Simple Multilevel Rfid Sercurity Using Esp32 and RC522

In this project we will make a scalable multilevel RFID security programmer and reader.

We will use an ESP32 board and RC522 RFID sensor.

Supplies

Supplies:

  • 2x ESP32
  • 2x sets of jumper cables
  • 2x red LEDs
  • 8x green LEDs
  • 5x buttons
  • 5x 1k ohm resistors (for the buttons)
  • 10x 220 ohm resistors (for the LEDs)
  • 2x RC522 RFID reader/writers
  • At least 1 RFID tag (but scalable for more)
  • Supplies are scalable depending on the number of security places or levels you want to implement.

Other Requirements:

  • A laptop for programming the ESP32
  • The newest version of the Arduino IDE installed on your laptop
  • Download the esp32 boardmanager by Espressif Systems in Arduino IDE
  • The MFRC522 library by GithubCommunity (version 1.4.10)

Step 1: Making the Writer Circuit

To build the writer for the RFID tag, you should follow the circuit diagram closely to ensure proper connections. If you encounter any wiring problems, make sure to check the version of your ESP32 and the GPIO pinout to ensure you're using the correct pins and connections. If you have specific questions or need assistance with any part of the project, feel free to ask, and I'll do my best to help.

Step 2: ESP32 Devkit V1 Pinout

Step 3: RC522 Pinout

Step 4: Uploading the Writer Code

#include <SPI.h>
#include <MFRC522.h>

#define SDA_PIN 5  // SDA Pin
#define RST_PIN 4  // Reset Pin


// Create an instance of MFRC522
MFRC522 mfrc522(SDA_PIN, RST_PIN);


// Create an instance of MIFARE_Key
MFRC522::MIFARE_Key key;          


int blockNum = 2;         //choose which block to write to
byte leveltoken;          //level stored on the token
byte inputLevel = 7;      //value which will not be reached by the buttons to make sure the user can only select one level to be written
byte blockData[2];        //array to store the input level


void setup()
{
  // Initialize serial communications with the PC
  Serial.begin(115200);
  // Initialize SPI bus
  SPI.begin();
  // Initialize MFRC522 Module
  mfrc522.PCD_Init();
  pinMode(13, OUTPUT); //Red Led
  pinMode(12, OUTPUT); //LVL1
  pinMode(14, OUTPUT); //LVL2
  pinMode(27, OUTPUT); //LVL3
  pinMode(26, OUTPUT); //LVL4
  pinMode(25, INPUT); //Button LVL0
  pinMode(33, INPUT); //Button LVL1
  pinMode(32, INPUT); //Button LVL2
  pinMode(35, INPUT); //Button LVL3
  pinMode(34, INPUT); //Button LVL4
}


void loop()
{
  // by checking if inputlevel equals 7, the program makes sure that multiple levels can't be selected by spamming buttons.
  while (inputLevel == 7){
    if (digitalRead(25) == 1){
      inputLevel = 0;
      digitalWrite(13, HIGH);
    }
    if ((digitalRead(33) == 1) && (inputLevel == 7)){
      inputLevel = 1;
      digitalWrite(12, HIGH);
    }
    if ((digitalRead(32) == 1) && (inputLevel == 7)){
      inputLevel = 2;
      digitalWrite(12, HIGH);
      digitalWrite(14, HIGH);
    }
    if ((digitalRead(35) == 1) && (inputLevel == 7)){
      inputLevel = 3;
      digitalWrite(12, HIGH);
      digitalWrite(14, HIGH);
      digitalWrite(27, HIGH);
    }
    if ((digitalRead(34) == 1) && (inputLevel == 7)){
      inputLevel = 4;
      digitalWrite(12, HIGH);
      digitalWrite(14, HIGH);
      digitalWrite(27, HIGH);
      digitalWrite(26, HIGH);
    }
    blockData[0] = inputLevel;
    Serial.println(inputLevel);
  }


  // Prepare the ksy for authentication
  // All keys are set to FFFFFFFFFFFFh at chip delivery from the factory
  for (byte i = 0; i < 6; i++)
  {
    key.keyByte[i] = 0xFF;
  }


  // Look for new cards
  // Reset the loop if no new card is present on RC522 Reader
  if ( ! mfrc522.PICC_IsNewCardPresent())
  {
    return;
  }


  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial())
  {
    return;
  }


  // Authenticating the desired data block for write access using Key A
  mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, blockNum, &key, &(mfrc522.uid));
  // Write data to the block
  mfrc522.MIFARE_Write(blockNum, blockData, 16);


  //flash the red light
  if(inputLevel == 0){
    digitalWrite(13, LOW);
    delay(500);
    digitalWrite(13, HIGH);
  }
  //flash one green light
  else if(inputLevel == 1){
    digitalWrite(12, LOW);
    delay(500);
    digitalWrite(12, HIGH);
  }
  //flash 2 green lights
  else if(inputLevel == 2){
    digitalWrite(12, LOW);
    digitalWrite(14, LOW);
    delay(500);
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
  }
  //flash 3 green lights
  else if(inputLevel == 3){
    digitalWrite(12, LOW);
    digitalWrite(14, LOW);
    digitalWrite(27, LOW);
    delay(500);
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
    digitalWrite(27, HIGH);
  }
  //flash 4 green lights
  else if(inputLevel == 4){
    digitalWrite(12, LOW);
    digitalWrite(14, LOW);
    digitalWrite(27, LOW);
    digitalWrite(26, LOW);
    delay(500);
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
    digitalWrite(27, HIGH);
    digitalWrite(26, HIGH);
  }
  //error flash
  else{
    digitalWrite(13, HIGH);
    digitalWrite(12, LOW);
    digitalWrite(14, HIGH);
    digitalWrite(27, LOW);
    digitalWrite(26, HIGH);
  }


  delay(500);
  //turn all leds off
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(14, LOW);
  digitalWrite(27, LOW);
  digitalWrite(26, LOW);


  ESP.restart();
}


Step 5: Writing to a Tag

Here are the steps:

  1. Use the buttons to select the desired access level for the tag (ranging from level 0 to 4). The LEDs will illuminate to indicate the selected access level.
  2. Present the tag to the RC522 writer. If the LEDs blink once more and then turn off, the write operation was successful.
  3. In case the write operation was unsuccessful, the red LED, as well as levels 2 and 4, will flash.
  4. If the ESP32 is still connected to a PC with Arduino open, you can open the serial monitor to view the written access level.

Step 6: Making the Reader Circuit

To build the reader for the RFID tag, you should follow the circuit diagram closely to ensure proper connections. If you encounter any wiring problems, make sure to check the version of your ESP32 and the GPIO pinout to ensure you're using the correct pins and connections. If you have specific questions or need assistance with any part of the project, feel free to ask, and I'll do my best to help.

Step 7: Uploading the Reader Code

#include <SPI.h>
#include <MFRC522.h>

#define SDA_PIN 5         //define SDA Pin
#define RST_PIN 4         //define RST Pin
#define SecurityLevel 1   //define securitylevel


// Create an instance of MFRC522
MFRC522 mfrc522(SDA_PIN, RST_PIN);


// Create an instance of MIFARE_Key
MFRC522::MIFARE_Key key;          


//
int blockNum = 2;         //choose which block to write to
byte bufferLen = 18;      //determine the bufferlength (2 more than the read array)
byte readBlockData[16];   //read array
byte leveltoken;          //level stored on the token
byte SL = SecurityLevel;   //the determines security level


void setup()
{
  // Initialize serial communications with the PC
  Serial.begin(115200);
  // Initialize SPI bus
  SPI.begin();
  // Initialize MFRC522 Module
  mfrc522.PCD_Init();
  pinMode(13, OUTPUT); //Red Led
  pinMode(12, OUTPUT); //LVL1
  pinMode(14, OUTPUT); //LVL2
  pinMode(27, OUTPUT); //LVL3
  pinMode(26, OUTPUT); //LVL4
}


void loop()
{
  // Prepare the ksy for authentication
  // All keys are set to FFFFFFFFFFFFh at chip delivery from the factory
  for (byte i = 0; i < 6; i++)
  {
    key.keyByte[i] = 0xFF;
  }
  // Look for new cards
  // Reset the loop if no new card is present on RC522 Reader
  if ( ! mfrc522.PICC_IsNewCardPresent())
  {
    return;
  }
  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial())
  {
    return;
  }
  // Authenticating the desired data block for Read access using Key A
  mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, blockNum, &key, &(mfrc522.uid));
  // Reading data from the Block
  mfrc522.MIFARE_Read(blockNum, readBlockData, &bufferLen);


  // Print the data read from block
  leveltoken = readBlockData[0];


  //if token level is bigger or equal to securitylevel
  if(int(leveltoken) >= int(SL)){
  Serial.println("Acces Granted!");
  }
  //else turn on the red light, this will make sure the current level is shown with a red light to indicate restricted access
  else{
    Serial.println("Acces Restricted.");
    //turn on the red light
    digitalWrite(13, HIGH);
  }
  //flash one green light
  if(leveltoken == 1){
    digitalWrite(12, HIGH);
  }
  //flash 2 green lights
  else if(leveltoken == 2){
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
  }
  //flash 3 green lights
  else if(leveltoken == 3){
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
    digitalWrite(27, HIGH);
  }
  //flash 4 green lights
  else if(leveltoken == 4){
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
    digitalWrite(27, HIGH);
    digitalWrite(26, HIGH);
  }
  else if(leveltoken == 0){
    Serial.println("Red led turned on");
  }
  //error flash
  else{
    digitalWrite(13, HIGH);
    digitalWrite(12, LOW);
    digitalWrite(14, HIGH);
    digitalWrite(27, LOW);
    digitalWrite(26, HIGH);
  }
  delay(2000);
  //turn all leds off
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(14, LOW);
  digitalWrite(27, LOW);
  digitalWrite(26, LOW);
  ESP.restart();
}


Step 8: Reading the Tag

With all the libraries and code successfully installed on the board, we are now ready to read a tag.

Here are the steps:

  1. Place the programmed tag against the reader. If the programmed access level is higher than the reader's access level, the corresponding level LEDs will illuminate.
  2. If the programmed access level is lower than the reader's access level, the red light will flash.
  3. In the case of an error, the red LED, along with the LEDs for levels 2 and 4, will flash.

Step 9: Explaning the Writing Code

Setup

In this part we deal with the inclusion of the libraries and define the different pins and block sizes.
#include <SPI.h>
#include <MFRC522.h>

#define SDA_PIN 5  // SDA Pin
#define RST_PIN 4  // Reset Pin


// Create an instance of MFRC522
MFRC522 mfrc522(SDA_PIN, RST_PIN);


// Create an instance of MIFARE_Key
MFRC522::MIFARE_Key key;          


int blockNum = 2;         //choose which block to write to
byte leveltoken;          //level stored on the token
byte inputLevel = 7;      //value which will not be reached by the buttons to make sure the user can only select one level to be written
byte blockData[2];        //array to store the input level


Setting up the pinModes for the buttons and leds
void setup() 
{
  // Initialize serial communications with the PC
  Serial.begin(115200);
  // Initialize SPI bus
  SPI.begin();
  // Initialize MFRC522 Module
  mfrc522.PCD_Init();
  pinMode(13, OUTPUT); //Red Led
  pinMode(12, OUTPUT); //LVL1
  pinMode(14, OUTPUT); //LVL2
  pinMode(27, OUTPUT); //LVL3
  pinMode(26, OUTPUT); //LVL4
  pinMode(25, INPUT); //Button LVL0
  pinMode(33, INPUT); //Button LVL1
  pinMode(32, INPUT); //Button LVL2
  pinMode(35, INPUT); //Button LVL3
  pinMode(34, INPUT); //Button LVL4
}

Step 10: Writing Code Part:2

Loop

the loop is always checking if a button is pressed and stops searching when a level is pressed.
the leds of the corresponding level will turn on.
void loop()
{
  // by checking if inputlevel equals 7, the program makes sure that multiple levels can't be selected by spamming buttons.
  while (inputLevel == 7){
    if (digitalRead(25) == 1){
      inputLevel = 0;
      digitalWrite(13, HIGH);
    }
    if ((digitalRead(33) == 1) && (inputLevel == 7)){
      inputLevel = 1;
      digitalWrite(12, HIGH);
    }
    if ((digitalRead(32) == 1) && (inputLevel == 7)){
      inputLevel = 2;
      digitalWrite(12, HIGH);
      digitalWrite(14, HIGH);
    }
    if ((digitalRead(35) == 1) && (inputLevel == 7)){
      inputLevel = 3;
      digitalWrite(12, HIGH);
      digitalWrite(14, HIGH);
      digitalWrite(27, HIGH);
    }
    if ((digitalRead(34) == 1) && (inputLevel == 7)){
      inputLevel = 4;
      digitalWrite(12, HIGH);
      digitalWrite(14, HIGH);
      digitalWrite(27, HIGH);
      digitalWrite(26, HIGH);
    }
the pressed level number will be pushed to the blockdata in bytes.
    blockData[0] = inputLevel;
    Serial.println(inputLevel);
  }

Step 11: Writing Code Part:3

Reading and Setting the RFID Tag

Resetting and setting up the card to be configured
  // Prepare the key for authentication 
  // All keys are set to FFFFFFFFFFFFh at chip delivery from the factory
  for (byte i = 0; i < 6; i++)
  {
    key.keyByte[i] = 0xFF;
  }

Looking for a card in a loop
  // Look for new cards 
  // Reset the loop if no new card is present on RC522 Reader
  if ( ! mfrc522.PICC_IsNewCardPresent())
  {
    return;
  }


  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial())
  {
    return;
  }


  // Authenticating the desired data block for write access using Key A
  mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, blockNum, &key, &(mfrc522.uid));
  // Write data to the block
  mfrc522.MIFARE_Write(blockNum, blockData, 16);

Step 12: Writing Code Part:4

LED STATES

all the possible led states based on the security level
//flash the red light
  if(inputLevel == 0){
    digitalWrite(13, LOW);
    delay(500);
    digitalWrite(13, HIGH);
  }
  //flash one green light
  else if(inputLevel == 1){
    digitalWrite(12, LOW);
    delay(500);
    digitalWrite(12, HIGH);
  }
  //flash 2 green lights
  else if(inputLevel == 2){
    digitalWrite(12, LOW);
    digitalWrite(14, LOW);
    delay(500);
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
  }
  //flash 3 green lights
  else if(inputLevel == 3){
    digitalWrite(12, LOW);
    digitalWrite(14, LOW);
    digitalWrite(27, LOW);
    delay(500);
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
    digitalWrite(27, HIGH);
  }
  //flash 4 green lights
  else if(inputLevel == 4){
    digitalWrite(12, LOW);
    digitalWrite(14, LOW);
    digitalWrite(27, LOW);
    digitalWrite(26, LOW);
    delay(500);
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
    digitalWrite(27, HIGH);
    digitalWrite(26, HIGH);
  }

Step 13: Writing Code Part:5

Error and looping

The error flash happens if all other options don't work and flashes 3 leds.
 //error flash
  else{
    digitalWrite(13, HIGH);
    digitalWrite(12, LOW);
    digitalWrite(14, HIGH);
    digitalWrite(27, LOW);
    digitalWrite(26, HIGH);
  }

After all the code all the leds get turned off.
  delay(500);
  //turn all leds off
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(14, LOW);
  digitalWrite(27, LOW);
  digitalWrite(26, LOW);

For the best results the ESP gets restarted by code for a full loop and start with the loop again.
  ESP.restart();
}

Step 14: Explaning the Reading Code

Setup

In this part we deal with the inclusion of the libraries and define the different pins and block sizes.
In the #define SecurityLevel we will set the security level for the reader.
For this example we use level 1 but changing this level will change the level for the whole code.
#include <SPI.h>
#include <MFRC522.h>

#define SDA_PIN 5         //define SDA Pin
#define RST_PIN 4         //define RST Pin
#define SecurityLevel 1   //define securitylevel


// Create an instance of MFRC522
MFRC522 mfrc522(SDA_PIN, RST_PIN);


// Create an instance of MIFARE_Key
MFRC522::MIFARE_Key key;          


//
int blockNum = 2;         //choose which block to write to
byte bufferLen = 18;      //determine the bufferlength (2 more than the read array)
byte readBlockData[16];   //read array
byte leveltoken;          //level stored on the token
byte SL = SecurityLevel;   //the determines security level


void setup()
{
  // Initialize serial communications with the PC
  Serial.begin(115200);
  // Initialize SPI bus
  SPI.begin();
  // Initialize MFRC522 Module
  mfrc522.PCD_Init();
  pinMode(13, OUTPUT); //Red Led
  pinMode(12, OUTPUT); //LVL1
  pinMode(14, OUTPUT); //LVL2
  pinMode(27, OUTPUT); //LVL3
  pinMode(26, OUTPUT); //LVL4
}

Step 15: Reading Code Part:2

Loop

Setting up the Tag
void loop()
{
  // Prepare the key for authentication
  // All keys are set to FFFFFFFFFFFFh at chip delivery from the factory
  for (byte i = 0; i < 6; i++)
  {
    key.keyByte[i] = 0xFF;
  }
The RC522 is searching for a RFID tag.
  // Look for new cards 
  // Reset the loop if no new card is present on RC522 Reader
  if ( ! mfrc522.PICC_IsNewCardPresent())
  {
    return;
  }
  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial())
  {
    return;
  }
When a tag is found the data is read from the tag.
  // Authenticating the desired data block for Read access using Key A 
  mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, blockNum, &key, &(mfrc522.uid));
  // Reading data from the Block
  mfrc522.MIFARE_Read(blockNum, readBlockData, &bufferLen);

  // Print the data read from block
  leveltoken = readBlockData[0];

Level Checking of the card and securitylevel
  //if token level is bigger or equal to securitylevel
  if(int(leveltoken) >= int(SL)){
  Serial.println("Acces Granted!");
  }
  //else turn on the red light, this will make sure the current level is shown with a red light to indicate restricted access
  else{
    Serial.println("Acces Restricted.");
    //turn on the red light
    digitalWrite(13, HIGH);
  }
  //flash one green light
  if(leveltoken == 1){
    digitalWrite(12, HIGH);
  }
  //flash 2 green lights
  else if(leveltoken == 2){
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
  }
  //flash 3 green lights
  else if(leveltoken == 3){
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
    digitalWrite(27, HIGH);
  }
  //flash 4 green lights
  else if(leveltoken == 4){
    digitalWrite(12, HIGH);
    digitalWrite(14, HIGH);
    digitalWrite(27, HIGH);
    digitalWrite(26, HIGH);
  }
  else if(leveltoken == 0){
    Serial.println("Red led turned on");
  }

Step 16: Reading Code Part:3

Error flash for when a tag was not read right
  //error flash
  else{
    digitalWrite(13, HIGH);
    digitalWrite(12, LOW);
    digitalWrite(14, HIGH);
    digitalWrite(27, LOW);
    digitalWrite(26, HIGH);
  }
  delay(2000);
Turning all the leds off before looping
  //turn all leds off
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(14, LOW);
  digitalWrite(27, LOW);
  digitalWrite(26, LOW);
Restarting the esp32 for a new loop
  ESP.restart();
}