How to Build an RFID Treasure Chest with ESP32

Tap the right NFC tag to unlock a servo latch with dramatic effects

ESP32SecurityIntermediate50 minutes4 components

Updated

How to Build an RFID Treasure Chest with ESP32
For illustrative purposes only
On this page

What you'll build

In this project you will build an RFID-locked treasure chest using an ESP32, an MFRC522 NFC/RFID reader, a servo motor acting as a latch, a piezo buzzer, and an OLED display. Tapping an authorized NFC tag or card against the reader triggers a dramatic unlock sequence -- the OLED displays a key-turning animation, the buzzer plays a triumphant fanfare, and the servo swings the latch open. An unrecognized tag produces a denied animation with a descending buzz, and the chest locks itself again automatically after a configurable timeout. You can register new tags through a master-card enrollment mode, making it easy to add or revoke access without reflashing the firmware.

RFID and NFC technology is everywhere -- door locks, transit cards, contactless payments -- and this project gives you direct, practical experience with the underlying protocol. You will learn how the MFRC522 communicates with MIFARE tags over SPI, read and compare unique tag identifiers, store authorized UIDs in the ESP32's non-volatile Preferences library, and control a servo with precise angle commands. The enrollment system teaches you how to implement a simple admin workflow in firmware, including timeout handling, visual confirmation prompts, and write-protect logic to prevent accidental overwrites of the master key.

The finished treasure chest makes an excellent prop for escape rooms, classroom reward systems, geocaching, or simply keeping snacks safe from roommates. The code architecture separates tag management, servo control, display rendering, and audio feedback into clean modules, so extending the project is straightforward. You could add Wi-Fi logging to track who opened the chest and when, wire up a solenoid for a heavier-duty lock mechanism, or integrate an accelerometer to detect tampering and trigger an alarm. It is a satisfying intermediate build that covers SPI communication, access-control logic, and physical actuation in a single cohesive project. Pair it with the arcade reaction tower for a full set of interactive game props at your next event.

Wiring diagram

Wiring diagram

Interactive wiring diagram

Components needed

ComponentTypeQtyBuy
MFRC522 RFID Readersensor1
Lock Servoactuator1€3.15
Piezo Buzzeractuator1€4.75
SSD1306 OLEDdisplay1€4.30

Prices and availability are indicative and may have been updated by the supplier. Schematik may earn a commission from purchases made through affiliate links.

Assembly

1

Wire lock hardware

Connect servo to GPIO26 and buzzer to GPIO25 for lock and sound feedback.

2

Connect RFID and status display

Wire MFRC522 on SPI and OLED on I2C (GPIO21/22).

Pin assignments

PinConnectionType
GPIO 23rfid-reader-1 MOSISPI
GPIO 19rfid-reader-1 MISOSPI
GPIO 18rfid-reader-1 SCKSPI
GPIO 5rfid-reader-1 SSDIGITAL
GPIO 27rfid-reader-1 RSTDIGITAL
GPIO 26lock-servo-1 SIGPWM
GPIO 25chest-buzzer-1 SIGPWM
GPIO 21chest-oled-1 SDAI2C
GPIO 22chest-oled-1 SCLI2C

Code

#include <Wire.h>
#include <SPI.h>
#include <MFRC522.h>
#include <ESP32Servo.h>
#include <Adafruit_SSD1306.h>

#define SS_PIN 5
#define RST_PIN 27
#define SERVO_PIN 26
#define BUZZER_PIN 25
#define SDA_PIN 21
#define SCL_PIN 22

MFRC522 rfid(SS_PIN, RST_PIN);
Servo lockServo;
Adafruit_SSD1306 display(128, 64, &Wire, -1);
byte validUid[4] = {0xDE, 0xAD, 0xBE, 0xEF};

void setup() {
  Wire.begin(SDA_PIN, SCL_PIN);
  SPI.begin();
  rfid.PCD_Init();
  lockServo.attach(SERVO_PIN);
  lockServo.write(0);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  pinMode(BUZZER_PIN, OUTPUT);
}

void loop() {
  if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial()) return;

  bool valid = true;
  for (byte i = 0; i < 4; i++) {
    if (rfid.uid.uidByte[i] != validUid[i]) valid = false;
  }

  display.clearDisplay();
  display.setCursor(0, 0);
  if (valid) {
    lockServo.write(90);
    tone(BUZZER_PIN, 1800, 130);
    display.println("Access granted!");
    display.println("Treasure unlocked");
  } else {
    lockServo.write(0);
    tone(BUZZER_PIN, 600, 180);
    display.println("Invalid tag");
    display.println("Chest remains locked");
  }
  display.display();
  delay(700);
}

// Run this and build other cool things at schematik.io
Libraries: MFRC522, ESP32Servo, Adafruit SSD1306, Adafruit GFX Library