In this project, you’ll build an RFID user management system with a web server that runs on an ESP32. The ESP32 board is connected to an MFRC522 RFID reader and a microSD card that will store all the user data. The ESP32 will be programmed using Arduino IDE and with the Arduino_MFRC522v2 library.
In this tutorial, we’ll cover the following topics:
- Project Overview
- Parts Required For This Project
- MFRC522 RFID Reader/Writer
- MicroSD Card Module
- ESP32 Project Circuit – Wiring to All the Components
- Preparing the Arduino IDE
- Organizing Your Files
- Code – ESP32 RFID User Management System Web Server
- Demonstration
Project Overview
The following diagram shows a high-level overview of how the project works.
1) When you approximate an RFID tag to the MIFARE reader, it will read its UID and send information about it to the ESP32. When it reads a tag, the buzzer will beep and an LED will turn on.
2) The ESP32 records the time of that interaction and saves the time and UUID on the microSD card on a file called log.txt.
3) The ESP32 also hosts a web server to display and manage the information from the microSD card.
4) The root (/) URL shows the full log (saved on the microSD card module log.txt) with the timestamp and the user UID.
5) There’s another page on /add-user that allows you to add users and their role using a form.
6) The data entered via this form will be saved on the user.txt file saved on the microSD card.
7) There is another page on /manage-users that allows to consult and delete users.
8) Basically, this page allows you to interact with the users.txt file.
Parts Required
Here’s a list of the required components for this project:
- ESP32 DOIT DEVKIT V1 Board (read Best ESP32 Dev Boards)
- MFRC522 RFID Reader/Writer + tags
- MicroSD Card Module
- MicroSD Card
- 1x 5mm LED
- 1x 220 Ohm Resistor
- Piezo Buzzer
- 1x 1k Ohm Resistor
- Breadboard
- Jumper wires
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
MFRC522 RFID Reader/Writer
In this tutorial, we’ll be using the MFRC522 RFID reader/writer and that’s the one we recommend you getting to interface with the ESP32.
You also need some RFID tags, we have a keychain and an electromagnetic card that come with the MFRC522 RFID Reader/Writer module. Each tag has a unique identification (UID) that will be assigned to each user.
Recommended reading: ESP32 with MFRC522 RFID Reader/Writer (Arduino IDE) – Getting Started Guide.
Wiring the ESP32 to the MFRC522 RFID Reader
The MFRC522 RFID reader works at 3.3V and we’ll be using SPI communication protocol. We’ll connect the MFRC522 RFID Reader to the ESP32 default SPI pins, use the next table as a reference.
MFRC522 RFID Reader | ESP32 | Description |
---|---|---|
SDA | GPIO 5 | SPI signal input, I2C data line, or UART data input |
SCK | GPIO 18 | SPI clock |
MOSI | GPIO 23 | SPI data input |
MISO | GPIO 19 | SPI master-in-slave-out, I2C serial clock, or UART serial output |
IRQ | Don’t connect | Interrupt pin; signals the microcontroller when an RFID tag is nearby |
GND | GND | |
RST | GPIO 21 | LOW signal to put the module in power-down mode; send a HIGH signal to reset the module |
3.3V | 3.3V | Power supply (2.5-3.3V) |
MicroSD Card Module
There are different microSD card modules compatible with the ESP32. We’re using the microSD card module sown in the following figure – it communicates using SPI communication protocol. You can use any other microSD card module with an SPI interface.
To learn how to use the microSD card module with the ESP32, you can read the next tutorial:
Wiring the MicroSD Card Module to the ESP32
The microSD card module communicates using SPI communication protocol. You can connect it to the ESP32 using the default SPI pins.
MicroSD card module | ESP32 |
3V3 | 3.3V |
CS | GPIO 15 |
MOSI | GPIO 23 |
CLK | GPIO 18 |
MISO | GPIO 19 |
GND | GND |
Preparing the microSD Card
Before proceeding with the tutorial, make sure you format your microSD card as FAT32. Follow the next instructions to format your microSD card or use a software tool like SD Card Formater (compatible with Windows and Mac OS).
1. Insert the microSD card into your computer. Go to My Computer and right-click on the SD card. Select Format as shown in the figure below.
2. A new window pops up. Select FAT32, press Start to initialize the formatting process and follow the onscreen instructions.
ESP32 Project Circuit – Wiring to All the Components
Besides the RFID reader/writer and the microSD card, we’ll also connect a piezzo buzzer and an LED to give us some feedback to let us know that the MFRC522 RFID Reader read a new tag.
- LED — connected to GPIO 22 (via a 220 Ohm resistor)
- Buzzer — connected to GPIO 4 (via a 1k Ohm resistor
Here’s how the final circuit looks like:
Preparing the Arduino IDE
We’ll program the ESP32 board using Arduino IDE. So, make sure you have the ESP32 add-on installed:
To upload the HTML and CSS files needed to build this project to the ESP32 flash memory filesystem (LittleFS), we’ll use a plugin for Arduino IDE: LittleFS Filesystem uploader. Follow the next tutorial to install the filesystem uploader plugin in your Arduino IDE 2 if you haven’t already:
Installing the Arduino_MFRC522v2 Library
For this tutorial, we’ll use the MFRC522v2.h library to control the RFID reader. In the Arduino IDE, go to Sketch > Include Library > Manage Libraries or click on the Libary Manager icon at the left sidebar.
Search for MFRC522v2 and install the library by GithubCommunity.
Installing the ESPAsyncWebServer and AsyncTCP Libraries
To guarantee that you’re using the latest version of the ESPAsyncWebServer and AsyncTCP libraries, please install them via .ZIP folder (instead of the Library Manager). Click the following links to download the library files.
- Click here to download the ESPAsyncWebServer library.
- Click here to download the Async TCP library.
- In your Arduino IDE, go to Sketch > Include Library > Add .zip Library and select the libraries you’ve just downloaded.
Important: These libraries are a forked version of the ones we used to use in our projects. This new libraries are well maintained and updated and compatible with the latest core of the ESP32. Make sure to uninstall any previous versions or forks of the library and install the new versions we recommend here. Are you having issues with the libraries? Check how to solve the problem here.
Organizing Your Files
To keep the project organized and make it easier to understand, we’ll create 6 files to build the web server:
- Arduino sketch: to handle the web server, RFID reader and MicroSD card;
- full-log.html: loads all the log of every RFID card that has been scanned and its user data;
- manage-users.html: web page that allows you to view and delete users;
- add-user.html: web page that allows you to add new users with a unique UID;
- get.html: handles all the HTTP GET requests;
- style.css: to style the web page.
You should save the HTML and CSS files inside a folder called data inside the Arduino sketch folder, as shown in the previous diagram. We’ll upload these files to the ESP32 filesystem (LittleFS).
You can download all project files:
HTML Files
Copy the following to the full-log.html file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Manage Users</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav>
<div class="nav-container">
<a href="/" class="brand">User Management</a>
<ul class="nav-menu">
<li><a href="/">📄 Full Log</a></li>
<li><a href="add-user">➕ Add User</a></li>
<li><a href="manage-users">👤 Manage Users</a></li>
</ul>
</div>
</nav>
<div class="main-container">
<section class="main-section">
<h2>📄 Full Access Log</h2>
<table id="tableData">
<thead>
<tr>
<th>Date</th>
<th>Time</th>
<th>UID</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<!-- Data from log.txt will be loaded here -->
</tbody>
</table>
</section>
</div>
<div class="main-container">
<a href="get?delete=log"><button class="button button-delete">🗑️ Delete log.txt File</button></a>
</div>
<script>
// JavaScript to load and parse log.txt
async function loadTableData() {
try {
const response = await fetch('view-log');
const data = await response.text();
const rows = data.trim().split('\n').slice(1); // Skip the header line
const tableBody = document.querySelector('#tableData tbody');
rows.forEach(row => {
const columns = row.split(',');
const tr = document.createElement('tr');
columns.forEach(column => {
const td = document.createElement('td');
td.textContent = column;
tr.appendChild(td);
});
tableBody.appendChild(tr);
});
} catch (error) {
console.error('Error loading log data:', error);
}
}
// Call the function to load log data
loadTableData();
</script>
</body>
</html>
Copy the following to the manage-users.html file.
Copy the following to the add-user.html file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Add User</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav>
<div class="nav-container">
<a href="/" class="brand">User Management</a>
<ul class="nav-menu">
<li><a href="/">📄 Full Log</a></li>
<li><a href="add-user">➕ Add User</a></li>
<li><a href="manage-users">👤 Manage Users</a></li>
</ul>
</div>
</nav>
<div class="main-container">
<section class="main-section">
<h2>➕ Add User</h2>
<p>Enter the UID in lower case letters and no spaces.</p><br>
<form action="get" class="user-form">
<label for="uid">UID</label>
<input type="text" id="uid" name="uid" required>
<label for="role">Role</label>
<select id="role" name="role">
<option value="admin">Admin</option>
<option value="user">User</option>
</select>
<button type="submit">✅ Save</button>
</form>
</section>
</div>
</body>
</html>
Copy the following to the get.html file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Add User</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<nav>
<div class="nav-container">
<a href="/" class="brand">User Management</a>
<ul class="nav-menu">
<li><a href="/">📄 Full Log</a></li>
<li><a href="add-user">➕ Add User</a></li>
<li><a href="manage-users">👤 Manage Users</a></li>
</ul>
</div>
</nav>
<div class="main-container">
<section class="main-section">
<p>%inputmessage%</p>
</section>
</div>
</body>
</html>
CSS File
Copy the following to the style.css file. Feel free to change it to make the web page look as you wish.
/* General Styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
background-color: #f4f4f9;
color: #333;
display: flex;
flex-direction: column;
align-items: center;
height: 100vh;
margin: 0;
}
/* Navigation Bar Styles */
nav {
width: 100%;
background-color: #333;
padding: 1rem 0;
}
.nav-container {
max-width: 1200px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 1rem;
}
.brand {
color: #fff;
text-decoration: none;
font-size: 1.5rem;
font-weight: bold;
}
.nav-menu {
list-style-type: none;
display: flex;
}
.nav-menu li {
margin-left: 1.5rem;
}
.nav-menu a {
color: #fff;
text-decoration: none;
font-size: 1rem;
transition: color 0.3s;
}
.nav-menu a:hover, .nav-menu a.active {
color: #f4f4f9;
}
.main-container {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
width: 100%;
}
.main-section {
max-width: 500px;
padding: 2rem;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
text-align: center;
}
.main-section h2 {
margin-bottom: 1rem;
color: #333;
}
.user-form label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
color: #333;
}
.user-form input, .user-form select {
width: 100%;
padding: 0.5rem;
margin-bottom: 1rem;
border: 1px solid #ddd;
border-radius: 4px;
}
.user-form button {
width: 100%;
padding: 0.7rem;
background-color: #333;
color: #fff;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.3s;
}
.user-form button:hover {
background-color: #555;
}
.button {
display: inline-block;
padding: 10px 20px;
margin: 10px;
font-size: 16px;
border: none;
border-radius: 5px;
cursor: pointer;
transition-duration: 0.4s;
}
.button-delete {
background-color: #780320;
color: #fff;
}
.button-home {
background-color: #333;
color: #fff;
}
#tableData {
font-family: Arial, Helvetica, sans-serif;
border-collapse: collapse;
width: 100%;
}
#tableData td, #tableData th {
border: 1px solid #ddd;
padding: 8px;
}
#tableData tr:nth-child(even) {
background-color: #f2f2f2;
}
#tableData tr:hover {
background-color: #ddd;
}
#tableData th {
padding-top: 12px;
padding-bottom: 12px;
text-align: left;
background-color: #1f1f1f;
color: white;
}
Code – ESP32 RFID User Management System Web Server
The following code handles the web server to handle the RFID user management system as explained in the project overview.
/*********
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete instructions at https://RandomNerdTutorials.com/esp32-rfid-user-management-web-server/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
#include <Arduino.h>
#include <MFRC522v2.h>
#include <MFRC522DriverSPI.h>
//#include <MFRC522DriverI2C.h>
#include <MFRC522DriverPinSimple.h>
#include <MFRC522Debug.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <LittleFS.h>
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include <time.h>
#include <WiFi.h>
// Learn more about using SPI/I2C or check the pin assigment for your board: https://github.com/OSSLibraries/Arduino_MFRC522v2#pin-layout
MFRC522DriverPinSimple ss_pin(5);
MFRC522DriverSPI driver{ss_pin}; // Create SPI driver
//MFRC522DriverI2C driver{}; // Create I2C driver
MFRC522 mfrc522{driver}; // Create MFRC522 instance
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
long timezone = 0;
byte daysavetime = 1;
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
const char* PARAM_INPUT_1 = "uid";
const char* PARAM_INPUT_2 = "role";
const char* PARAM_INPUT_3 = "delete";
const char* PARAM_INPUT_4 = "delete-user";
String inputMessage;
String inputParam;
const int ledPin = 22;
const int buzzerPin = 4;
// Write to the SD card
void writeFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file) {
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)) {
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
// Append data to the SD card
void appendFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file) {
Serial.println("Failed to open file for appending");
return;
}
time_t t = file.getLastWrite();
struct tm *tmstruct = localtime(&t);
char bufferDate[50]; // Adjust buffer size as needed
snprintf(bufferDate, sizeof(bufferDate), "%d-%02d-%02d",
(tmstruct->tm_year) + 1900,
(tmstruct->tm_mon) + 1,
tmstruct->tm_mday);
char bufferTime[50]; // Adjust buffer size as needed
snprintf(bufferTime, sizeof(bufferTime), "%02d:%02d:%02d",
tmstruct->tm_hour,
tmstruct->tm_min,
tmstruct->tm_sec);
String lastWriteTime = bufferDate;
String finalString = String(bufferDate) + "," + String(bufferTime) + "," + String(message) + "\n";
Serial.println(lastWriteTime);
if(file.print(finalString.c_str())) {
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
// Append data to the SD card
void appendUserFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file) {
Serial.println("Failed to open file for appending");
return;
}
String finalString = String(message) + "\n";
if(file.print(finalString.c_str())) {
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
void deleteFile(fs::FS &fs, const char *path) {
Serial.printf("Deleting file: %s\n", path);
if (fs.remove(path)) {
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
String processor(const String& var){
return String("HTTP GET request sent to your ESP on input field ("
+ inputParam + ") with value: " + inputMessage +
"<br><a href=\"/\"><button class=\"button button-home\">Return to Home Page</button></a>");
}
void deleteLineFromFile(const char* filename, int lineNumber) {
File file = SD.open(filename);
if (!file) {
Serial.println("Failed to open file for reading.");
return;
}
// Read all lines except the one to delete
String lines = "";
int currentLine = 0;
while (file.available()) {
String line = file.readStringUntil('\n');
if (currentLine != lineNumber) {
lines += line + "\n";
}
currentLine++;
}
file.close();
// Write back all lines except the deleted one
file = SD.open(filename, FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing.");
return;
}
file.print(lines);
file.close();
Serial.println("Line deleted successfully.");
}
String getRoleFromFile(const char* filename, String uid) {
File file = SD.open(filename);
if (!file) {
Serial.println("Failed to open file for reading.");
return "";
}
// Skip the header line
file.readStringUntil('\n');
// Read each line and check for UID
while (file.available()) {
String line = file.readStringUntil('\n');
int commaIndex = line.indexOf(',');
if (commaIndex > 0) {
String fileUID = line.substring(0, commaIndex);
String role = line.substring(commaIndex + 1);
// Compare UID
if (fileUID == uid) {
file.close();
role.trim(); // Remove any extra spaces or newline characters
return role;
}
}
}
file.close();
return ""; // Return empty string if UID not found
}
void initRFIDReader() {
mfrc522.PCD_Init(); // Init MFRC522 board.
MFRC522Debug::PCD_DumpVersionToSerial(mfrc522, Serial); // Show details of PCD - MFRC522 Card Reader details.
Serial.println(F("Scan PICC to see UID"));
}
void initLittleFS() {
if(!LittleFS.begin()){
Serial.println("An Error has occurred while mounting LittleFS");
return;
}
}
void initWifi() {
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
// Print ESP32 Local IP Address
Serial.print("ESP IP Address: ");
Serial.println(WiFi.localIP());
}
void initTime() {
Serial.println("CInitializing Time");
struct tm tmstruct;
delay(2000);
tmstruct.tm_year = 0;
getLocalTime(&tmstruct, 5000);
Serial.printf(
"Time and Date right now is : %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct.tm_year) + 1900, (tmstruct.tm_mon) + 1, tmstruct.tm_mday, tmstruct.tm_hour, tmstruct.tm_min,
tmstruct.tm_sec
);
}
void initSDCard() {
// CS pin = 15
if (!SD.begin(15)) {
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
Serial.println("No SD card attached");
return;
}
Serial.print("SD Card Type: ");
if (cardType == CARD_MMC) {
Serial.println("MMC");
} else if (cardType == CARD_SD) {
Serial.println("SDSC");
} else if (cardType == CARD_SDHC) {
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
// If the log.txt file doesn't exist, create a file on the SD card and write the header
File file = SD.open("/log.txt");
if(!file) {
Serial.println("log.txt file doesn't exist");
Serial.println("Creating file...");
writeFile(SD, "/log.txt", "Date,Time,UID,Role\r\n");
}
else {
Serial.println("log.txt file already exists");
}
file.close();
// If the users.txt file doesn't exist, create a file on the SD card and write the header
file = SD.open("/users.txt");
if(!file) {
Serial.println("users.txt file doesn't exist");
Serial.println("Creating file...");
writeFile(SD, "/users.txt", "UID,Role\r\n");
}
else {
Serial.println("users.txt file already exists");
}
file.close();
}
void setup() {
Serial.begin(115200); // Initialize serial communication
while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4).
initRFIDReader();
initLittleFS();
initWifi();
configTime(3600 * timezone, daysavetime * 3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
initTime();
initSDCard();
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
pinMode(buzzerPin, OUTPUT);
digitalWrite(buzzerPin, LOW);
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/full-log.html");
});
// Route for root /add-user web page
server.on("/add-user", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/add-user.html");
});
// Route for root /manage-users web page
server.on("/manage-users", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/manage-users.html");
});
// Serve Static files
server.serveStatic("/", LittleFS, "/");
// Loads the log.txt file
server.on("/view-log", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SD, "/log.txt", "text/plain", false);
});
// Loads the users.txt file
server.on("/view-users", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SD, "/users.txt", "text/plain", false);
});
// Receive HTTP GET requests on <ESP_IP>/get?input=<inputMessage>
server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
// GET input1 and input2 value on <ESP_IP>/get?input1=<inputMessage1>&input2=<inputMessage2>
if (request->hasParam(PARAM_INPUT_1) && request->hasParam(PARAM_INPUT_2)) {
inputMessage = request->getParam(PARAM_INPUT_1)->value();
inputParam = String(PARAM_INPUT_1);
inputMessage += " " + request->getParam(PARAM_INPUT_2)->value();
inputParam += " " + String(PARAM_INPUT_2);
String finalMessageInput = String(request->getParam(PARAM_INPUT_1)->value()) + "," + String(request->getParam(PARAM_INPUT_2)->value());
appendUserFile(SD, "/users.txt", finalMessageInput.c_str());
}
else if (request->hasParam(PARAM_INPUT_3)) {
inputMessage = request->getParam(PARAM_INPUT_3)->value();
inputParam = String(PARAM_INPUT_3);
if(request->getParam(PARAM_INPUT_3)->value()=="users") {
deleteFile(SD, "/users.txt");
}
else if(request->getParam(PARAM_INPUT_3)->value()=="log") {
deleteFile(SD, "/log.txt");
}
}
else if (request->hasParam(PARAM_INPUT_4)) {
inputMessage = request->getParam(PARAM_INPUT_4)->value();
inputParam = String(PARAM_INPUT_4);
deleteLineFromFile("/users.txt", inputMessage.toInt());
}
else {
inputMessage = "No message sent";
inputParam = "none";
}
request->send(LittleFS, "/get.html", "text/html", false, processor);
});
// Start server
server.begin();
}
void loop() {
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if (!mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards.
if (!mfrc522.PICC_ReadCardSerial()) {
return;
}
// Save the UID on a String variable
String uidString = "";
for (byte i = 0; i < mfrc522.uid.size; i++) {
if (mfrc522.uid.uidByte[i] < 0x10) {
uidString += "0";
}
uidString += String(mfrc522.uid.uidByte[i], HEX);
}
Serial.print("Card UID: ");
Serial.println(uidString);
String role = getRoleFromFile("/users.txt", uidString);
if (role != "") {
Serial.print("Role for UID: ");
Serial.print(uidString);
Serial.print(" is ");
Serial.println(role);
} else {
role = "unknown";
Serial.print("UID: ");
Serial.print(uidString);
Serial.println(" not found, set user role to unknown");
}
String sdMessage = uidString + "," + role;
appendFile(SD, "/log.txt", sdMessage.c_str());
digitalWrite(buzzerPin, HIGH);
digitalWrite(ledPin, HIGH);
delay(500);
digitalWrite(buzzerPin, LOW);
delay(2500);
digitalWrite(ledPin, LOW);
}
Before uploading the code, you need to insert your network credentials in the following lines so that the ESP32 can establish a Wi-Fi connection.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_SSID";
Resources to Help You Understand the Code
This code is quite long and we won’t explain in detail how it works because all subjects covered here were already explained in previous projects.
Here’s a list of the tutorials you should look at to learn about the subjects covered here:
1) Reading the UID of an RFID tag with the ESP32: ESP32: Getting Started with MFRC522 RFID Reader/Writer (Arduino IDE).
2) Getting a timestamp using an NTP server: ESP32 NTP Client-Server: Get Date and Time (Arduino IDE).
3) Reading and writing from/to the microSD card: ESP32: Guide for MicroSD Card Module using Arduino IDE.
4) Datalogging with the ESP32: ESP32: How to Log Data (10 Different Ways)
5) Creating a web server with the ESP32: a list of all our web server projects.
6) Sending data from a web page to the ESP32 via HTML form: Input Data on HTML Form ESP32/ESP8266 Web Server using Arduino IDE.
7) Everything you need to know about creating a web server with HTML and CSS files with the ESP32: our Build Web Server with ESP32 eBook covers a lot of subjects in great detail.
Upload Code and Data Folder
After inserting your network credentials, save the code. Go to Sketch > Show Sketch Folder, and create a folder called data.
Inside that folder, you should place the HTML, and CSS files provided previously.
Uploading the Filesystem Image
Upload those files to the filesystem: press [Ctrl] + [Shift] + [P] on Windows or [⌘] + [Shift] + [P] on MacOS to open the command palette. Search for the Upload LittleFS to Pico/ESP8266/ESP32 command and click on it.
If you don’t have this option is because you didn’t install the filesystem uploader plugin. Check this tutorial.
Important: make sure the Serial Monitor is closed before uploading to the filesystem. Otherwise, the upload will fail.
Uploading the Code
Then, upload the code to your ESP32 board. Make sure you inserted your network credentials in the code.
When everything is successfully uploaded, open the Serial Monitor at a baud rate of 115200. Press the ESP32 EN/RST button, and it should print the ESP32 IP address.
Troubleshooting
Are you getting this error? assert failed: tcp_alloc /IDF/components/lwip/lwip/src/core/tcp.c:1851 (Required to lock TCPIP core functionality!)
It means you’re not using the recommended libraries. Check this explanation on how to solve the issue.
Demonstration
Open a browser on your local network and type the ESP32 IP address. You should get access to the web server page that looks like this, it should have a blank table by default.
Grab an RFID tag, and scan it in the RFID reader. Every time you scan an RFID tag, the LED should light up and the piezo buzzer will beep briefly. In your Arduino IDE Serial Monitor, the UID of your RFID card will be printed:
For testing purposes, I recommend scanning multiple RFID tags, so that you have more data displayed in your web server. Now open your web server Full Log page, your table should look similar:
Copy the UID of one of your RFID cards, please note that it should be in lower-case letters and without any spaces (for example: bd31152b). Then, open the Add User tab.
Type the UID and select the role (user or admin). Finally, click the “Save” button. I’ll be repeating this process for other RFID tags for demonstration purposes.
Now, if you browse to the Manager Users web page:
It loads a table with all the UIDs and their corresponding user roles, you can click the “X” to delete a user.
Scan the RFID tags a few more times, then open the web server home page. The log table should have all the entries with a timestamp, UID and their corresponding user roles.
At the bottom of the Full Log and Manager Users web pages, you have the option to delete the log.txt and users.txt files from the microSD card at any time.
You can also access the web server page on your smartphone.
Wrapping Up
In this tutorial, you combined different subjects to build an RFID Management System and Logger with the ESP32. Here’s a list of the subjects we covered: different web server features, getting a timestamp, datalogging, interfacing an RFID reader, reading and writing files to a microSD card, and much more.
We hope you found this project useful, if you want to learn more about RFID reader/writer module with the ESP32 or about the microSD card module you can read the following guides:
- ESP32: Getting Started with MFRC522 RFID Reader/Writer (Arduino IDE)
- ESP32: Guide for MicroSD Card Module using Arduino IDE
- ESP32 Data Logging Temperature to MicroSD Card
To learn more about building web servers with the ESP32, check out our ebook:
If you would like to learn more about the ESP32, and for inspiration for new projects, make sure to take a look at our resources:
- Learn ESP32 with Arduino IDE (eBook)
- Free ESP32 Projects and Tutorials
- ESP32: 26 Free Guides for Sensors and Modules
Thanks for reading.