RFID Attendance Portal
An ESP32 card reader and a web portal that together take attendance in seconds and show it live, built for a Philippine school setting.

How it fits together
- 01Card tapRFID card
- 02ESP32 readerMFRC522 · RTC · SD whitelist · OLED
- 03Google Apps ScriptAPI layer
- 04Google SheetsAttendance data
- 05Next.js portalLive stats · reports
The hardware
The whitelist lives on the SD card, so the reader keeps working even if the network drops, and syncs from the backend when it can. One button handles everything: single click, double click, a 2 s hold for the setup portal and a 5 s hold to refresh the whitelist.
Hard problems, and what fixed them
SD card corrupting RFID reads
Problem. Both devices share one SPI bus, and the SD card's chip-select left MISO asserted.
Fix. Both CS pins go HIGH before SPI.begin(), the reader initialises first, and all SD access goes through sdBegin()/sdEnd() wrappers.
Random reboots
Problem. Back-to-back blocking buzzer and LED patterns starved the ESP32 task watchdog.
Fix. A yield() roughly every 40 ms inside those functions.
Whitelist wear and corruption
Problem. Rewriting the whole whitelist file on every scan was slow, and a failed write could truncate the live file.
Fix. In-place 5-byte seek-and-write for scans, and temp-file-plus-rename when sorting.
Garbage in the JSON stream
Problem. Chunked transfer-encoding size markers leaked into the data the ESP32 parsed.
Fix. A three-state chunk filter in front of the JSON parser.
The portal
- Public landing page with a live counter (odometer) powered by a public stats endpoint
- Authenticated live counts by user type, shared across the app
- Late-arrivals report showing each student's earliest IN log
- Language switcher with a click-to-open menu
- Page-progress loader and smooth page-enter transitions
What's next
A free, always-on messenger bot that notifies a parent when their child taps in or out, backed by a separate service that only handles users and data, so the attendance backend stays simple.
