ESP32 With RFID: Access Control
by Fernando Koyanagi in Circuits > Microcontrollers
125960 Views, 47 Favorites, 0 Comments
ESP32 With RFID: Access Control
How about a method of automatic identification through radio signals that can bring you security and control the access of people to a certain location? This is possible through radio frequency identification or RFID from the English Radio Frequency Identification. And it is the assembly of this system that I am going to teach you today.
This system works with a card or it can also be a key chain that has a chip inside it. Through the identification of the data of this card or chip is that it is possible to do access control, a method widely used in records of employee points, public transportation, libraries, among others.
Our goal, therefore, is to create a program in which we can either read an RFID card (or tag) or write the data to it. We use a WiFi NodeMCU-32S and an RFID-RC522 module.
It is important to note that we can store and retrieve data on these chips or cards remotely through devices, as these have up to 1k of memory.
Operation
An RFID system basically consists of a transceiver with a decoder and an antenna and a transponder. And how it works? These cards have a reel inside them. When you approach them from the reader, they emit a radio signal through the antennas connected to the reader. The energized tag, which is the card, modulates the information stored in its memory and sends that data to the reader. This card then enters the reading field and receives power from the reader to perform the operations. The RFID reader receives the information sent by the tag, decodes and sends the data to the server application.
Memory
As mentioned, we have 1k of memory inside this type of chip. And, the EEPROM memory is organized as follows: there are 16 sectors of 4 blocks. Each block contains 16 bytes. Remember that within the source code, you only reference the block number.
Circuit
In this image we have a keychain that has an RFID chip and we have the traditional card, besides our assembly. And how does this circuit work? Well, on the internet, you will find the RFID-RC522 module being very used with Arduino, but the problem is that this Arduino, be it Mega, Nano, regardless of the model, it does not have communication, like WiFi network, Ethernet, between others. So we use ESP32 here. It already has Bluetooth, RF, that is, easy communication. I point out here, then, that almost anything that works with Arduino also works with ESP32.
Returning to the circuit, when, during the analysis of a card or chip, the green LED lights up, this means that the identification has been made and the access is released. When the red LED is lit, the data has not been authenticated.
WiFi NodeMCU-32S ESP-WROOM-32
RFID-RC522
Here we have images of the card and the key ring, as well as the RFID antenna. An important detail is that its Interface is SPI.
Assembly
In our assembly we have the ESP32 powered by USB and also connected in the serial of the Arduino IDE, two leds to indicate whether the reading was successful or not, and the RFID reader, the RC522. We have the keyring with chip and the card.
Placing the key ring over the player shows the option of 0 for reading data and 1 for recording this data. We do an example that shows that after reading the chip or card, if the green led is lit the reader recognized the number. In case of the red led, it means that some type of error occurred and the authentication was not performed.
In the example, I still show how to write data to the tag, which will be explained below.
Libraries
Add the following library "MFRC522".
Simply access "Sketch >> Include Libraries >> Manage Libraries ..."
Source Code
Our program will work as follows: after starting, the program will wait for a card or tag to be identified. After that, a menu will appear for the user to choose between making a reading or recording something. Then the operation will be performed.
Setup
In this part we deal with the inclusion of the libraries and define the buffer and block data sizes. We create objects and initialize the pins, as well as serial, SPI communication, LEDs and antenna service. I already start to include messages on the serial monitor.
#include <MFRC522.h> //library responsible for communicating with the module RFID-RC522 #include <SPI.h> //library responsible for communicating of SPI bus #define SS_PIN 21 #define RST_PIN 22 #define SIZE_BUFFER 18 #define MAX_SIZE_BLOCK 16 #define greenPin 12 #define redPin 32 //used in authentication MFRC522::MIFARE_Key key; //authentication return status code MFRC522::StatusCode status; // Defined pins to module RC522 MFRC522 mfrc522(SS_PIN, RST_PIN); void setup() { Serial.begin(9600); SPI.begin(); // Init SPI bus pinMode(greenPin, OUTPUT); pinMode(redPin, OUTPUT); // Init MFRC522 mfrc522.PCD_Init(); Serial.println("Approach your reader card..."); Serial.println();
Loop
In the Loop we wait for the card to approach and select the same one. In the menu, we offer the options of reading or writing data. We instruct this part when the device should leave the ACTIVE state for the STOP state. We have to use such a method to enable new readings.
void loop() { // Aguarda a aproximacao do cartao //waiting the card approach if ( ! mfrc522.PICC_IsNewCardPresent()) { return; } // Select a card if ( ! mfrc522.PICC_ReadCardSerial()) { return; } // Dump debug info about the card; PICC_HaltA() is automatically called // mfrc522.PICC_DumpToSerial(&(mfrc522.uid));</p><p> //call menu function and retrieve the desired option int op = menu(); if(op == 0) readingData(); else if(op == 1) writingData(); else { Serial.println(F("Incorrect Option!")); return; } //instructs the PICC when in the ACTIVE state to go to a "STOP" state mfrc522.PICC_HaltA(); // "stop" the encryption of the PCD, it must be called after communication with authentication, otherwise new communications can not be initiated mfrc522.PCD_StopCrypto1(); }
Reading
In this part we treat the reading of the data of the card / tag. We have to prepare all the keys, handle the size of the buffer and authenticate the block that we are going to operate. Finally, we set the printing of the data read.
//reads data from card/tag void readingData() { //prints the technical details of the card/tag mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); //prepare the key - all keys are set to FFFFFFFFFFFFh for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; //buffer for read data byte buffer[SIZE_BUFFER] = {0}; //the block to operate byte block = 1; byte size = SIZE_BUFFER;</p><p> //authenticates the block to operate status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid)); //line 834 of MFRC522.cpp file if (status != MFRC522::STATUS_OK) { Serial.print(F("Authentication failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); digitalWrite(redPin, HIGH); delay(1000); digitalWrite(redPin, LOW); return; } //read data from block status = mfrc522.MIFARE_Read(block, buffer, &size); if (status != MFRC522::STATUS_OK) { Serial.print(F("Reading failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); digitalWrite(redPin, HIGH); delay(1000); digitalWrite(redPin, LOW); return; } else{ digitalWrite(greenPin, HIGH); delay(1000); digitalWrite(greenPin, LOW); } Serial.print(F("\nData from block [")); Serial.print(block);Serial.print(F("]: ")); //prints read data for (uint8_t i = 0; i < MAX_SIZE_BLOCK; i++) { Serial.write(buffer[i]); } Serial.println(" "); }
Recording
To write data to the card / tag we have to follow some steps. From the moment we choose the recording option, we have 30 seconds to make the data entry via serial. Enter the data to be written with the "#" character and prepare the key. You will need to clear the buffer and write to block 1, since in block 0 we have saved the card number, which is already in the factory. So we do not touch block 0.
We deal with the size of data and insert a command for authentication and enable secure communication. We also put error messages equal to the part of the reading for display in case of unauthenticated data. We recorded the data in the block due.
//prints thecnical details from of the card/tag
mfrc522.PICC_DumpDetailsToSerial(&(mfrc522.uid)); // waits 30 seconds dor data entry via Serial Serial.setTimeout(30000L) ; Serial.println(F("Enter the data to be written with the '#' character at the end \n[maximum of 16 characters]:"));//prepare the key - all keys are set to FFFFFFFFFFFFh for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF;
//buffer para armazenamento dos dados que iremos gravar //buffer for storing data to write byte buffer[MAX_SIZE_BLOCK] = ""; byte block; //the block to operate byte dataSize; //size of data (bytes)
//recover on buffer the data from Serial //all characters before chacactere '#' dataSize = Serial.readBytesUntil('#', (char*)buffer, MAX_SIZE_BLOCK); //void positions that are left in the buffer will be filled with whitespace for(byte i=dataSize; i < MAX_SIZE_BLOCK; i++) { buffer[i] = ' '; } block = 1; //the block to operate String str = (char*)buffer; //transforms the buffer data in String Serial.println(str);
//authenticates the block to operate //Authenticate is a command to hability a secure communication status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) { Serial.print(F("PCD_Authenticate() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); digitalWrite(redPin, HIGH); delay(1000); digitalWrite(redPin, LOW); return; } //else Serial.println(F("PCD_Authenticate() success: ")); //Writes in the block status = mfrc522.MIFARE_Write(block, buffer, MAX_SIZE_BLOCK); if (status != MFRC522::STATUS_OK) { Serial.print(F("MIFARE_Write() failed: ")); Serial.println(mfrc522.GetStatusCodeName(status)); digitalWrite(redPin, HIGH); delay(1000); digitalWrite(redPin, LOW); return; } else{ Serial.println(F("MIFARE_Write() success: ")); digitalWrite(greenPin, HIGH); delay(1000); digitalWrite(greenPin, LOW); } }
Menu
Here we program the Menu. The monitor exposes all options and waits for data to be sent. When an option is selected, it removes 48 from the read value, which is 0 from the Ascii table. This table is old and not used on the PC, but on Arduino and microcontrollers you will have to deal with it. If you do not know, give one searched on the internet to know what it is.
//menu to operation choice
int menu() { Serial.println(F("\nChoose an option:")); Serial.println(F("0 - Reading data")); Serial.println(F("1 - Writing data\n"));//waits while the user does not start data while(!Serial.available()){}; //retrieves the chosen option int op = (int)Serial.read(); //remove all characters after option (as \n per example) while(Serial.available()) { if(Serial.read() == '\n') break; Serial.read(); } return (op-48);//subtract 48 from read value, 48 is the zero from ascii table }