893  NFC Access Control Systems

893.1 Learning Objectives

By the end of this chapter, you will be able to:

  • Build NFC Access Control: Implement door lock systems using ESP32 and PN532 modules
  • Configure I2C Communication: Set up reliable NFC tag reading via I2C protocol
  • Design Authorization Logic: Create authorized tag databases with UID matching
  • Integrate Hardware Components: Wire servo locks, LEDs, and buzzers for feedback
  • Implement Access Logging: Track access attempts with circular buffer storage
  • Debug NFC Issues: Diagnose communication, range, and interference problems

This chapter guides you through building a complete NFC-based door lock system. When someone taps an authorized NFC tag (like an employee badge), the system:

  1. Reads the tag’s unique ID
  2. Checks if the ID is in the authorized list
  3. Unlocks the door (servo motor)
  4. Provides visual feedback (green LED = granted, red LED = denied)
  5. Logs the access attempt for security auditing

Think of it like the key card systems in hotels or offices, but one you build yourself!

Prerequisites: - NFC Fundamentals - Core NFC concepts and operating modes - NFC Architecture - Protocol stack and tag types

Continue Learning: - NFC Smart Home Automation - Python-based scene control - NFC Security and Comparisons - Payment security and technology selection - NFC Hands-On - Practical implementations

893.2 Prerequisites

Required Knowledge: - Understanding of NFC operating modes (Reader/Writer, Peer-to-Peer, Card Emulation) - Basic Arduino/ESP32 programming experience - Familiarity with I2C communication protocol

Required Hardware: - ESP32 Development Board - PN532 NFC Reader Module (I2C) - Servo motor (SG90) for lock mechanism - NFC tags (Type 2 recommended) - LED (Green for granted, Red for denied) - Buzzer (optional) - Jumper wires and breadboard

Estimated Time: 45 minutes

893.3 System Architecture

The NFC access control system follows a straightforward flow: tag detection, authorization check, and hardware response.

Flowchart diagram

Flowchart diagram
Figure 893.1: NFC access control system architecture showing tag reading, authorization checking, and hardware feedback mechanisms including servo lock, LEDs, and buzzer.

This decision tree helps select the appropriate NFC operating mode based on application requirements.

%% fig-alt: Decision tree for selecting NFC operating modes including Reader/Writer, Peer-to-Peer, and Card Emulation based on use case
%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#E67E22'}}}%%
flowchart TD
    START([NFC Mode<br/>Selection]) --> Q1{Interaction<br/>type?}

    Q1 -->|Read tags| RW[/Reader/Writer Mode/]
    Q1 -->|Exchange data| Q2{Both NFC<br/>enabled?}
    Q1 -->|Act as card| CE[/Card Emulation/]

    Q2 -->|Yes phones| P2P[/Peer-to-Peer Mode/]
    Q2 -->|No one passive| RW

    RW --> RW_USE["Access control<br/>Asset tracking<br/>Smart posters"]
    P2P --> P2P_USE["File sharing<br/>Bluetooth pairing<br/>Wi-Fi handover"]
    CE --> CE_USE["Mobile payments<br/>Transit cards<br/>Loyalty cards"]

    RW --> RW_TAG{Tag type?}
    RW_TAG -->|Simple UID| TYPE1["Type 1/2<br/>Low cost"]
    RW_TAG -->|Secure data| TYPE4["Type 4<br/>NDEF + crypto"]

    CE --> CE_SEC{Security<br/>level?}
    CE_SEC -->|High HCE| SE["Secure Element<br/>TEE/eSE"]
    CE_SEC -->|App-level| HCE["Host Card<br/>Emulation"]

    style START fill:#2C3E50,color:#fff
    style RW fill:#16A085,color:#fff,stroke:#2C3E50,stroke-width:3px
    style P2P fill:#E67E22,color:#fff,stroke:#2C3E50,stroke-width:2px
    style CE fill:#9B59B6,color:#fff,stroke:#2C3E50,stroke-width:3px

893.4 Hardware Wiring

Connect the ESP32 to the PN532 NFC module and output devices as shown:

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D'}}}%%
flowchart LR
    subgraph ESP32["ESP32 Development Board"]
        direction TB
        P3V3[3.3V]
        P5V[5V]
        GND[GND]
        G21[GPIO 21<br/>I2C SDA]
        G22[GPIO 22<br/>I2C SCL]
        G13[GPIO 13]
        G25[GPIO 25]
        G26[GPIO 26]
        G27[GPIO 27]
    end

    subgraph NFC["PN532 NFC Module"]
        NFC_VCC[VCC]
        NFC_GND[GND]
        NFC_SDA[SDA]
        NFC_SCL[SCL]
    end

    subgraph Servo["Servo Motor SG90"]
        S_SIG[Signal]
        S_VCC[VCC]
        S_GND[GND]
    end

    subgraph Output["Output Indicators"]
        LED_G[Green LED<br/>+ 220Ξ©]
        LED_R[Red LED<br/>+ 220Ξ©]
        BUZ[Buzzer]
    end

    P3V3 --> NFC_VCC
    GND --> NFC_GND
    G21 <--> NFC_SDA
    G22 <--> NFC_SCL

    G13 --> S_SIG
    P5V --> S_VCC
    GND --> S_GND

    G25 --> LED_G
    G26 --> LED_R
    G27 --> BUZ

    style ESP32 fill:#2C3E50,stroke:#16A085,color:#fff
    style NFC fill:#16A085,stroke:#2C3E50,color:#fff
    style Servo fill:#E67E22,stroke:#2C3E50,color:#fff
    style Output fill:#7F8C8D,stroke:#2C3E50,color:#fff

Figure 893.2: ESP32 NFC access control system wiring showing I2C communication with PN532 reader, servo motor control, and LED/buzzer feedback indicators.

Wiring Summary Table:

Component Pin ESP32 GPIO Notes
PN532 VCC VCC 3.3V Power supply
PN532 GND GND GND Common ground
PN532 SDA SDA GPIO 21 I2C data
PN532 SCL SCL GPIO 22 I2C clock
Servo Signal Orange GPIO 13 PWM control
Servo VCC Red 5V Higher voltage for motor
Servo GND Brown GND Common ground
Green LED Anode GPIO 25 Via 220Ξ© resistor
Red LED Anode GPIO 26 Via 220Ξ© resistor
Buzzer + GPIO 27 Active buzzer

893.5 Complete Implementation

The following code implements a fully functional NFC access control system:

#include <Wire.h>
#include <PN532_I2C.h>
#include <PN532.h>
#include <NfcAdapter.h>
#include <ESP32Servo.h>

// Pin definitions
#define SERVO_PIN 13
#define GREEN_LED 25
#define RED_LED 26
#define BUZZER 27

// NFC setup
PN532_I2C pn532i2c(Wire);
NfcAdapter nfc = NfcAdapter(pn532i2c);

// Servo for lock
Servo lockServo;

// Authorized UIDs (add your NFC tag UIDs here)
String authorizedUIDs[] = {
  "04 A3 B2 C1 D4 5E 80",  // Alice's badge
  "08 F7 E2 9A 3B 1C 4D",  // Bob's badge
  "12 34 56 78 9A BC DE"   // Admin card
};
const int numAuthorizedUIDs = 3;

// Lock states
const int LOCKED_ANGLE = 0;
const int UNLOCKED_ANGLE = 90;
bool isLocked = true;

// Access log (circular buffer)
struct AccessLog {
  String uid;
  String status;
  unsigned long timestamp;
};
AccessLog accessHistory[10];
int accessLogIndex = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("\n=== ESP32 NFC Access Control System ===");

  // Initialize pins
  pinMode(GREEN_LED, OUTPUT);
  pinMode(RED_LED, OUTPUT);
  pinMode(BUZZER, OUTPUT);

  // Initial state: deny
  digitalWrite(GREEN_LED, LOW);
  digitalWrite(RED_LED, HIGH);

  // Initialize servo
  lockServo.attach(SERVO_PIN);
  lockServo.write(LOCKED_ANGLE);

  // Initialize NFC
  nfc.begin();
  Serial.println("βœ“ NFC Reader initialized");
  Serial.println("πŸ“± Ready to scan NFC tags...\n");

  // Startup beep
  beep(100);
}

void loop() {
  // Check for NFC tag
  if (nfc.tagPresent(1000)) {  // 1 second timeout
    NfcTag tag = nfc.read();

    String uid = tag.getUidString();
    Serial.println("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    Serial.println("πŸ“± NFC Tag Detected");
    Serial.print("   UID: ");
    Serial.println(uid);

    // Check authorization
    if (isAuthorized(uid)) {
      grantAccess(uid);
    } else {
      denyAccess(uid);
    }

    Serial.println("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");

    delay(2000);  // Prevent multiple reads
  }

  delay(100);
}

bool isAuthorized(String uid) {
  /**
   * Check if UID is in authorized list
   */
  for (int i = 0; i < numAuthorizedUIDs; i++) {
    if (uid == authorizedUIDs[i]) {
      return true;
    }
  }
  return false;
}

void grantAccess(String uid) {
  /**
   * Grant access: unlock door, green LED, success beep
   */
  Serial.println("βœ… ACCESS GRANTED");

  // Visual feedback
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, HIGH);

  // Unlock door
  lockServo.write(UNLOCKED_ANGLE);
  isLocked = false;

  // Audio feedback
  beep(50);
  delay(100);
  beep(50);

  Serial.println("πŸ”“ Door unlocked");
  Serial.println("   Relocking in 5 seconds...");

  // Log access
  logAccess(uid, "GRANTED");

  // Keep door unlocked for 5 seconds
  delay(5000);

  // Re-lock door
  lockServo.write(LOCKED_ANGLE);
  isLocked = true;
  digitalWrite(GREEN_LED, LOW);
  digitalWrite(RED_LED, HIGH);

  Serial.println("πŸ”’ Door locked");
}

void denyAccess(String uid) {
  /**
   * Deny access: red LED, error beep
   */
  Serial.println("❌ ACCESS DENIED");
  Serial.println("   Unauthorized NFC tag");

  // Visual feedback (red LED already on)
  // Blink red LED
  for (int i = 0; i < 3; i++) {
    digitalWrite(RED_LED, LOW);
    delay(100);
    digitalWrite(RED_LED, HIGH);
    delay(100);
  }

  // Audio feedback (long error beep)
  beep(500);

  // Log denied attempt
  logAccess(uid, "DENIED");
}

void beep(int duration_ms) {
  /**
   * Sound buzzer for specified duration
   */
  digitalWrite(BUZZER, HIGH);
  delay(duration_ms);
  digitalWrite(BUZZER, LOW);
}

void logAccess(String uid, String status) {
  /**
   * Record access attempt in circular buffer
   */
  accessHistory[accessLogIndex].uid = uid;
  accessHistory[accessLogIndex].status = status;
  accessHistory[accessLogIndex].timestamp = millis();

  accessLogIndex = (accessLogIndex + 1) % 10;  // Circular buffer

  // Print log entry
  Serial.print("πŸ“ Logged: ");
  Serial.print(status);
  Serial.print(" - ");
  Serial.println(uid);
}

// Optional: Add command to print access history via Serial
void printAccessHistory() {
  Serial.println("\n=== Access History (Last 10 attempts) ===");
  for (int i = 0; i < 10; i++) {
    if (accessHistory[i].uid != "") {
      Serial.print(i + 1);
      Serial.print(". ");
      Serial.print(accessHistory[i].status);
      Serial.print(" - ");
      Serial.print(accessHistory[i].uid);
      Serial.print(" @ ");
      Serial.print(accessHistory[i].timestamp / 1000);
      Serial.println("s");
    }
  }
  Serial.println("=====================================\n");
}

893.6 Expected Serial Output

When the system is running, you’ll see output like this:

=== ESP32 NFC Access Control System ===
βœ“ NFC Reader initialized
πŸ“± Ready to scan NFC tags...

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
πŸ“± NFC Tag Detected
   UID: 04 A3 B2 C1 D4 5E 80
βœ… ACCESS GRANTED
πŸ”“ Door unlocked
   Relocking in 5 seconds...
πŸ“ Logged: GRANTED - 04 A3 B2 C1 D4 5E 80
πŸ”’ Door locked
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
πŸ“± NFC Tag Detected
   UID: FF AA BB CC DD EE 11
❌ ACCESS DENIED
   Unauthorized NFC tag
πŸ“ Logged: DENIED - FF AA BB CC DD EE 11
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

893.7 Adding New Authorized Tags

To add new authorized tags to the system:

  1. Scan the new tag to get its UID from Serial Monitor
  2. Add the UID to the authorizedUIDs array:
String authorizedUIDs[] = {
  "04 A3 B2 C1 D4 5E 80",
  "08 F7 E2 9A 3B 1C 4D",
  "YOUR NEW UID HERE"     // Add new tag
};
  1. Update the count: Change numAuthorizedUIDs to match
  2. Re-upload the code to ESP32
TipPro Tip: Dynamic Tag Management

For production systems, consider storing authorized UIDs in EEPROM or SPIFFS (ESP32’s flash filesystem) so you can add/remove tags without re-uploading code. You could also implement a web interface for remote management.

893.8 Troubleshooting

Common issues and solutions:

Problem Cause Solution
NFC not initializing I2C wiring issue Check SDA/SCL connections, verify 3.3V power
Tag not detected Range too far Hold tag within 2-3cm of reader
Wrong UID format Tag type mismatch Use Type 2 tags (NTAG213/215/216)
Servo jittering Power issue Use separate 5V supply for servo
Intermittent reads Interference Keep away from metal surfaces

893.9 Security Considerations

This basic implementation demonstrates NFC access control concepts. For production use, consider:

  • Encrypted UIDs: Use tag types with encryption (NTAG 424 DNA)
  • Challenge-Response: Implement mutual authentication between reader and tag
  • Audit Logging: Store logs to external database with timestamps
  • Anti-Passback: Prevent same tag from entering twice without exit
  • Tamper Detection: Add sensors to detect physical attacks on reader

893.10 Summary

This chapter covered building an ESP32-based NFC access control system:

  • Hardware Integration: Connecting PN532 NFC reader, servo motor, and feedback indicators
  • I2C Communication: Configuring ESP32 for reliable tag reading
  • Authorization Logic: Matching tag UIDs against an authorized list
  • Access Logging: Recording all access attempts in a circular buffer
  • User Feedback: Providing visual (LED) and audio (buzzer) confirmation

The system demonstrates the Reader/Writer operating mode of NFC, where the ESP32 acts as an NFC reader and passive tags provide identification.

893.11 What’s Next

Continue to NFC Smart Home Automation to build a Raspberry Pi-based smart home controller that triggers scenes when users tap NFC tags placed around the house.