NFC Visitor Pass Reader
ESP32 DevKit (WROOM-32)·Arduino C++·Updated Jul 27, 2026·by FluxBench TeamIncludes Lab + Schematic + PCB
Tap-to-enter access reader: a PN532 NFC module (I2C) enrolls the first card tapped as a 3-use visitor pass, then answers each tap with a green "granted" or red "denied" LED and buzzer chirps — in the Lab simulator a virtual tag taps the antenna every few seconds, or use the reader panel to tap two virtual cards yourself and watch the pass get enrolled, used up and a foreign card rejected. Bundled Lab bench, schematic and routed PCB included.
sketch.ino
// NFC Visitor Pass Reader — PN532 (I2C) + green/red LEDs + buzzer
// The first card tapped is enrolled as a 3-use visitor pass. Later taps of
// the same card are granted until the 3 uses run out, then denied.
// PN532: SDA = GPIO21, SCL = GPIO22, VCC = 3V3, GND
// Buzzer + = GPIO5; green LED = GPIO4; red LED = GPIO2 (each LED via 330 Ω)
#include <Wire.h>
#include <Adafruit_PN532.h>
#define LED_OK 4
#define LED_NO 2
#define BUZZER 5
Adafruit_PN532 nfc(-1, -1); // I2C mode (IRQ/RSTO unused)
uint8_t master[4];
bool enrolled = false;
int grantsLeft = 3;
void chirp(int freq, int ms) {
tone(BUZZER, freq, ms);
delay(ms + 30);
}
void setup() {
Serial.begin(115200);
pinMode(LED_OK, OUTPUT);
pinMode(LED_NO, OUTPUT);
Wire.begin();
nfc.begin();
uint32_t ver = nfc.getFirmwareVersion();
if (!ver) {
Serial.println("PN532 not found - check wiring");
while (true) delay(100);
}
char vbuf[40];
sprintf(vbuf, "PN532 chip 0x%02X firmware %d.%d", (ver >> 24) & 0xFF, (ver >> 16) & 0xFF, (ver >> 8) & 0xFF);
Serial.println(vbuf);
nfc.SAMConfig();
Serial.println("Tap the first card to enroll it as the visitor pass (3 uses)...");
}
void loop() {
uint8_t uid[7];
uint8_t uidLen = 0;
if (!nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLen)) {
delay(150); // no card in the field
return;
}
char idbuf[24];
sprintf(idbuf, "%02X:%02X:%02X:%02X", uid[0], uid[1], uid[2], uid[3]);
if (!enrolled) {
for (int i = 0; i < 4; i++) master[i] = uid[i];
enrolled = true;
Serial.print("Enrolled visitor pass ");
Serial.println(idbuf);
chirp(1568, 120);
chirp(2093, 160);
delay(4000); // wait for the card to leave the field
return;
}
bool ok = true;
for (int i = 0; i < 4; i++) {
if (uid[i] != master[i]) ok = false;
}
if (ok && grantsLeft <= 0) {
ok = false;
Serial.println("Pass expired - all 3 uses consumed");
}
if (ok) {
grantsLeft--;
Serial.print("Access GRANTED to ");
Serial.print(idbuf);
Serial.print(" (uses left: ");
Serial.print(grantsLeft);
Serial.println(")");
digitalWrite(LED_OK, HIGH);
chirp(1760, 200);
digitalWrite(LED_OK, LOW);
} else {
Serial.print("Access DENIED for ");
Serial.println(idbuf);
digitalWrite(LED_NO, HIGH);
chirp(220, 400);
digitalWrite(LED_NO, LOW);
}
delay(4000);
}
Built with FluxBench.AI — the AI workbench for embedded projects.