A smart door reader that keeps a diary. Every time someone taps an RFID card, the ESP32 lights a green or red LED and records the card, the result and the time. Open the log on your phone to see the last 20 scans, updated every few seconds.
What you need
- ESP32 board, expansion board and USB cable
- RC522 RFID module and S50 card
- Green LED and red LED
- 2 resistors, 220 Ω
- Breadboard and jumper wires (all from the ESP32 IoT Starter Kit)
- A 2.4 GHz Wi-Fi network
Good to know
Plug the ESP32 into the expansion board from the kit, or place it next to the breadboard, and connect the pins with jumper wires.
The RC522 is a 3.3 V module, which suits the ESP32 perfectly. Connect it to 3V3, never to 5V.
Wiring

| From | To |
|---|---|
| RC522 SDA | ESP32 GPIO 5 |
| RC522 SCK | ESP32 GPIO 18 |
| RC522 MOSI | ESP32 GPIO 23 |
| RC522 MISO | ESP32 GPIO 19 |
| RC522 IRQ | Not connected |
| RC522 GND | GND |
| RC522 RST | ESP32 GPIO 22 |
| RC522 3.3V | ESP32 3V3 |
| ESP32 GPIO 26 | 220 Ω resistor, then the green LED's long leg |
| ESP32 GPIO 25 | 220 Ω resistor, then the red LED's long leg |
| Both LEDs' short legs | GND |
Build it step by step
- Install the MFRC522 library (by GithubCommunity).
- Wire the reader to the ESP32's SPI pins (5, 18, 19, 23) plus GPIO 22, and add the two LEDs.
- Enter your Wi-Fi details, upload the code and open the Serial Monitor at 115200 baud.
- Tap your card. The Serial Monitor shows its ID, for example
{0x3A, 0x7F, 0x12, 0xC4}. Paste it intoallowedand upload again. - Open the address shown in the Serial Monitor on your phone and tap a few cards.
The code
Replace YOUR_WIFI_NAME and YOUR_WIFI_PASSWORD with your own network details. The ESP32 only connects to 2.4 GHz Wi-Fi. After uploading, open the Serial Monitor at 115200 baud to see the address to open on your phone. The phone must be on the same Wi-Fi network.
#include <WiFi.h>
#include <WebServer.h>
#include <SPI.h>
#include <MFRC522.h>
#include <time.h>
const char* WIFI_NAME = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* TIME_ZONE = "EET-2EEST,M3.5.0/3,M10.5.0/4"; // Estonia; change for your country
const int SS_PIN = 5;
const int RST_PIN = 22;
const int GREEN_LED = 26;
const int RED_LED = 25;
MFRC522 rfid(SS_PIN, RST_PIN);
WebServer server(80);
// Paste the IDs of allowed cards (shown in the Serial Monitor)
byte allowed[][4] = {
{0x00, 0x00, 0x00, 0x00}
};
const int ALLOWED_COUNT = sizeof(allowed) / sizeof(allowed[0]);
struct Scan { String id; bool ok; String when; };
const int LOG_SIZE = 20;
Scan scans[LOG_SIZE];
int scanCount = 0;
String cardId() {
String id = "{";
for (byte i = 0; i < rfid.uid.size; i++) {
id += "0x";
if (rfid.uid.uidByte[i] < 0x10) id += "0";
id += String(rfid.uid.uidByte[i], HEX);
if (i < rfid.uid.size - 1) id += ", ";
}
id += "}";
id.toUpperCase();
id.replace("0X", "0x");
return id;
}
bool isAllowed() {
if (rfid.uid.size != 4) return false;
for (int c = 0; c < ALLOWED_COUNT; c++) {
if (memcmp(rfid.uid.uidByte, allowed[c], 4) == 0) return true;
}
return false;
}
String timeNow() {
struct tm t;
if (getLocalTime(&t, 10)) {
char text[20];
strftime(text, sizeof(text), "%d.%m %H:%M:%S", &t);
return String(text);
}
return String(millis() / 1000) + " s after start";
}
void addScan(String id, bool ok) {
for (int i = LOG_SIZE - 1; i > 0; i--) scans[i] = scans[i - 1]; // newest first
scans[0] = {id, ok, timeNow()};
if (scanCount < LOG_SIZE) scanCount++;
}
String page() {
String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
html += "<meta http-equiv='refresh' content='5'><title>Door log</title></head>";
html += "<body style='font-family:sans-serif;padding:16px'><h1>Door log</h1>";
if (scanCount == 0) html += "<p>No scans yet.</p>";
else {
html += "<table style='border-collapse:collapse;width:100%'>";
html += "<tr><th align='left'>Time</th><th align='left'>Card</th><th align='left'>Result</th></tr>";
for (int i = 0; i < scanCount; i++) {
html += "<tr style='border-top:1px solid #ddd'><td>" + scans[i].when + "</td><td>" + scans[i].id + "</td><td>";
html += scans[i].ok ? "<b style='color:green'>Allowed</b>" : "<b style='color:#c00'>Denied</b>";
html += "</td></tr>";
}
html += "</table>";
}
html += "</body></html>";
return html;
}
void setup() {
Serial.begin(115200);
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
SPI.begin(); // SCK 18, MISO 19, MOSI 23, SS 5
rfid.PCD_Init();
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.print("Open http://");
Serial.println(WiFi.localIP());
configTzTime(TIME_ZONE, "pool.ntp.org"); // get the time from the internet
server.on("/", []() { server.send(200, "text/html", page()); });
server.begin();
}
void loop() {
server.handleClient();
if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return;
String id = cardId();
bool ok = isAllowed();
Serial.print("Card ID: ");
Serial.print(id);
Serial.println(ok ? " allowed" : " denied");
addScan(id, ok);
digitalWrite(ok ? GREEN_LED : RED_LED, HIGH);
delay(1000);
digitalWrite(ok ? GREEN_LED : RED_LED, LOW);
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
}
How it works
The RC522 talks to the ESP32 over SPI, on the board's standard SPI pins. Each scan is compared with the allowed list and added to the start of a list of the last 20 scans. The ESP32 gets the real time from an internet time server (NTP) and uses your time zone. The web page is rebuilt from that list every time your phone reloads it, which it does every 5 seconds.
Make it your own
- Give each card a name and show it in the log instead of the ID.
- Add the servo from the kit to open a latch for allowed cards.
- Count how many times each card was scanned today.
Troubleshooting
- The time shows "s after start": the ESP32 couldn't reach the time server yet. Check the internet connection, and wait a minute.
- No card is detected: check the SPI wires and that the reader is on 3V3.
- The page doesn't open: make sure your phone is on the same Wi-Fi network.
Learn the basics first
New to these parts? These lessons explain them step by step: Set up the ESP32 in the Arduino IDE and Control a relay from your phone over Wi-Fi.
0 comments