FluxBench.AIShared project · read-only

Badge Check-In Station

ESP32 DevKit (WROOM-32)·Arduino C++·Updated Jul 27, 2026·by FluxBench TeamIncludes Lab + Schematic

The MFRC522v2 library, demonstrated properly. Where the Coffee Card and Arcade Token demos use the classic miguelbalboa MFRC522 API, this attendance station is written against the OSSLibraries MFRC522v2 rewrite: chip-select lives in a MFRC522DriverPinSimple, the bus in a MFRC522DriverSPI, the reader brace-initializes around the driver (no RST pin - v2 never drives reset), and the debug helpers are static MFRC522Debug:: calls. Every badge UID is packed into a 32-bit code and logged to an in-RAM roster: first tap checks you in with a green LED and a running head-count on the OLED, a repeat tap flags ALREADY IN with the red LED, and the button wipes the roster to start a fresh session.

sketch.ino
// Badge Check-In Station - built on MFRC522v2, the modern rewrite of the
// classic miguelbalboa RFID library. The v2 API looks different on purpose:
// instead of MFRC522 rfid(SS_PIN, RST_PIN) you compose driver objects -
// a pin driver for chip-select, an SPI bus driver wrapping it, and the
// reader wrapping the bus (brace initialization, no RST pin: v2 never
// drives reset, so the module RST pin is simply tied high). All the debug
// helpers moved into the static MFRC522Debug class, which is why this
// sketch calls MFRC522Debug::PCD_DumpVersionToSerial and
// MFRC522Debug::PrintUID instead of methods on the reader object.
//
// The station keeps an attendance roster in RAM: every badge UID is packed
// into a 32-bit code, first tap checks you in (green LED + running count),
// tapping again flags a duplicate (red LED). The button starts a fresh
// session and clears the roster. Tap card A and card B to see both paths.

#include <SPI.h>
#include <MFRC522v2.h>
#include <MFRC522DriverSPI.h>
#include <MFRC522DriverPinSimple.h>
#include <MFRC522Debug.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define LED_OK 4      // green: checked in
#define LED_DUP 2     // red: already checked in / roster full
#define BTN_RESET 14  // start a new session (clears the roster)
#define ROSTER_MAX 16

MFRC522DriverPinSimple ss_pin(5);  // chip-select on GPIO 5
MFRC522DriverSPI driver{ss_pin};   // v2 style: the driver owns the SPI bus
MFRC522 reader{driver};            // the reader wraps the driver
Adafruit_SSD1306 display(128, 64, &Wire, -1);

unsigned long roster[ROSTER_MAX];
int checkedIn = 0;
int lastBtn = 1;

void showScreen(const char* line1, const char* line2) {
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.print("BADGE STATION in:");
  display.print(checkedIn);
  display.setTextSize(2);
  display.setCursor(0, 16);
  display.print(line1);
  display.setTextSize(1);
  display.setCursor(0, 40);
  display.print(line2);
  display.setCursor(0, 54);
  display.print("Button = new session");
  display.display();
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_OK, OUTPUT);
  pinMode(LED_DUP, OUTPUT);
  pinMode(BTN_RESET, INPUT_PULLUP);
  SPI.begin();
  reader.PCD_Init();
  MFRC522Debug::PCD_DumpVersionToSerial(reader, Serial);
  Wire.begin();
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  showScreen("CHECK-IN", "Tap your badge");
  Serial.println("Check-in station ready - tap a badge");
}

void loop() {
  int btn = digitalRead(BTN_RESET);
  if (btn == 0 && lastBtn == 1) {
    checkedIn = 0;
    Serial.println("Roster cleared - new session started");
    showScreen("NEW SESSION", "Tap your badge");
  }
  lastBtn = btn;

  if (!reader.PICC_IsNewCardPresent()) {
    delay(50);
    return;
  }
  if (!reader.PICC_ReadCardSerial()) {
    delay(50);
    return;
  }

  // Pack the badge UID into one 32-bit code for the roster.
  unsigned long code = 0;
  for (byte i = 0; i < reader.uid.size; i++) {
    code = (code << 8) | reader.uid.uidByte[i];
  }

  Serial.print("Badge");
  MFRC522Debug::PrintUID(Serial, reader.uid);

  bool already = false;
  for (int i = 0; i < checkedIn; i++) {
    if (roster[i] == code) already = true;
  }

  if (already) {
    digitalWrite(LED_DUP, HIGH);
    Serial.println(" -> ALREADY CHECKED IN");
    showScreen("ALREADY IN", "Badge seen before");
  } else if (checkedIn < ROSTER_MAX) {
    roster[checkedIn] = code;
    checkedIn = checkedIn + 1;
    digitalWrite(LED_OK, HIGH);
    Serial.print(" -> CHECKED IN #");
    Serial.println(checkedIn);
    showScreen("WELCOME!", "You are on the list");
  } else {
    digitalWrite(LED_DUP, HIGH);
    Serial.println(" -> ROSTER FULL - press the button");
    showScreen("ROSTER FULL", "Press new session");
  }

  reader.PICC_HaltA();
  reader.PCD_StopCrypto1();
  delay(700);
  digitalWrite(LED_OK, LOW);
  digitalWrite(LED_DUP, LOW);
}

Built with FluxBench.AI — the AI workbench for embedded projects.