879  NFC IoT Integration and Labs

879.1 Learning Objectives

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

  • Build NFC Gateway Systems: Create NFC-to-cloud pipelines for IoT
  • Implement Access Control: Develop ESP32-based NFC door lock systems
  • Create Smart Home Servers: Build Raspberry Pi NFC automation servers
  • Integrate with MQTT: Connect NFC events to IoT message brokers

879.2 Prerequisites

Before diving into this chapter, you should be familiar with:

NFC Deep Dives: - NFC Communication Fundamentals - Operating modes and NDEF - NFC Implementation and Applications - Tag programming - NFC Security and Comparisons - Security analysis

IoT Protocols: - MQTT Fundamentals - Message broker for IoT - CoAP Protocol - Lightweight IoT protocol


879.3 NFC in IoT Ecosystems

879.3.1 IoT Gateway Pattern

%%{init: {'theme': 'base', 'themeVariables': {'primaryColor': '#2C3E50', 'primaryTextColor': '#fff', 'primaryBorderColor': '#16A085', 'lineColor': '#16A085', 'secondaryColor': '#E67E22', 'tertiaryColor': '#7F8C8D', 'background': '#ffffff', 'mainBkg': '#2C3E50', 'secondBkg': '#16A085', 'tertiaryBkg': '#E67E22'}}}%%
flowchart TD
    Tags[NFC Tags on Assets] -->|Tap| Reader[NFC Reader Gateway]
    Reader -->|Bluetooth/Wi-Fi| Hub[IoT Hub]
    Hub -->|MQTT/HTTP| Cloud[Cloud Platform]

    Cloud -->|Analytics| Dashboard[Web Dashboard]
    Cloud -->|Alerts| Mobile[Mobile App]
    Cloud -->|Track| Inventory[Inventory System]

    style Tags fill:#16A085,stroke:#2C3E50,color:#fff
    style Reader fill:#2C3E50,stroke:#16A085,color:#fff
    style Hub fill:#E67E22,stroke:#2C3E50,color:#fff
    style Cloud fill:#7F8C8D,stroke:#333,color:#fff

Figure 879.1: NFC gateway pattern connecting asset tags to cloud via IoT hub

Example: Smart Factory Asset Tracking

# Requires paho-mqtt 2.0+
import nfc
import paho.mqtt.client as mqtt
import json
from datetime import datetime

# Connect to NFC reader and MQTT broker
clf = nfc.ContactlessFrontend('usb')
mqtt_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="nfc-gateway")
mqtt_client.connect("mqtt.factory.local", 1883)

def on_tag_scan(tag):
    """Process scanned asset tag"""
    asset_id = tag.identifier.hex()

    # Read asset metadata from tag
    if tag.ndef:
        asset_name = tag.ndef.records[0].text
    else:
        asset_name = "Unknown"

    # Publish to MQTT
    data = {
        "asset_id": asset_id,
        "asset_name": asset_name,
        "location": "Assembly Line 3",
        "timestamp": datetime.now().isoformat(),
        "scanned_by": "Worker-042"
    }

    mqtt_client.publish("factory/assets/scans", json.dumps(data))
    print(f"Asset {asset_name} tracked at Assembly Line 3")

    return True

# Listen for tags
print("Factory asset tracking active...")
clf.connect(rdwr={'on-connect': on_tag_scan})

879.4 Hands-On Labs

879.4.1 Lab 1: ESP32 NFC Access Control System

Build an NFC-based door lock system using ESP32 and PN532 module.

Hardware Required: - 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 - Breadboard

Wiring Diagram:

PN532 NFC Module β†’ ESP32
  VCC β†’ 3.3V
  GND β†’ GND
  SDA β†’ GPIO 21 (I2C SDA)
  SCL β†’ GPIO 22 (I2C SCL)

Servo Motor β†’ ESP32
  Signal β†’ GPIO 13
  VCC β†’ 5V (via external power if needed)
  GND β†’ GND

Green LED β†’ GPIO 25 (via 220Ξ© resistor)
Red LED β†’ GPIO 26 (via 220Ξ© resistor)
Buzzer β†’ GPIO 27

Complete Code:

#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");
}

Expected Serial Monitor Output:

=== 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
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

How to Add New Authorized Tags:

  1. Scan an unknown 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",
  "YOUR NEW UID HERE"
};
  1. Update numAuthorizedUIDs count
  2. Re-upload the code

879.4.2 Lab 2: Python NFC Smart Home Automation Server

Create a Raspberry Pi-based NFC smart home control system.

Hardware Required: - Raspberry Pi (3B+ or 4) - PN532 NFC Module (I2C or UART) - NFC tags (Type 2) - Optional: Smart home devices (lights, plugs via MQTT)

Installation:

# Install dependencies
pip3 install nfcpy paho-mqtt flask

# Enable I2C on Raspberry Pi
sudo raspi-config
# Interface Options β†’ I2C β†’ Enable

Complete Code:

#!/usr/bin/env python3
"""
NFC Smart Home Automation Server
Raspberry Pi + PN532 + MQTT

Tap NFC tags to trigger smart home scenes
"""

import nfc
import paho.mqtt.client as mqtt
import json
from datetime import datetime
from flask import Flask, jsonify
import threading

class NFCSmartHomeServer:
    def __init__(self):
        # Tag-to-scene mappings
        self.tag_scenes = {}

        # Registered smart home devices
        self.devices = {}

        # Scene definitions
        self.scenes = {}

        # MQTT client
        self.mqtt_client = None

        # Access log
        self.access_log = []

    def setup_mqtt(self, broker="localhost", port=1883):
        """Connect to MQTT broker for smart home control"""
        self.mqtt_client = mqtt.Client(
            mqtt.CallbackAPIVersion.VERSION2,
            client_id="nfc-smart-home"
        )
        self.mqtt_client.connect(broker, port)
        self.mqtt_client.loop_start()
        print(f"βœ“ Connected to MQTT broker: {broker}")

    def register_device(self, device_id, name, topic):
        """Register a smart home device"""
        self.devices[device_id] = {
            "name": name,
            "topic": topic,
            "state": "OFF"
        }
        print(f"βœ“ Device registered: {name} ({device_id})")

    def create_scene(self, scene_name, description, actions):
        """Create a smart home scene"""
        self.scenes[scene_name] = {
            "description": description,
            "actions": actions
        }
        print(f"βœ“ Scene created: {scene_name}")

    def map_tag_to_scene(self, tag_uid, scene_name):
        """Map NFC tag UID to scene"""
        self.tag_scenes[tag_uid] = scene_name
        print(f"βœ“ Tag {tag_uid} mapped to scene '{scene_name}'")

    def execute_scene(self, scene_name):
        """Execute all actions in a scene"""
        if scene_name not in self.scenes:
            print(f"❌ Unknown scene: {scene_name}")
            return False

        scene = self.scenes[scene_name]
        print(f"\n🎬 Executing scene: {scene_name}")
        print(f"   {scene['description']}")

        for action in scene['actions']:
            self._execute_action(action)

        print(f"βœ… Scene '{scene_name}' completed")
        return True

    def _execute_action(self, action):
        """Execute a single action"""
        device_id = action.get('device')
        command = action.get('command')
        value = action.get('value')

        if device_id in self.devices:
            device = self.devices[device_id]

            # Send MQTT command
            if self.mqtt_client:
                payload = json.dumps({
                    "command": command,
                    "value": value
                })
                self.mqtt_client.publish(device['topic'], payload)

            # Update local state
            device['state'] = value
            print(f"βœ“ {device['name']} {command} {value}")
        else:
            print(f"  β†’ {action.get('description', 'Custom action')}")

    def on_tag_scan(self, tag):
        """Callback when NFC tag is scanned"""
        tag_uid = tag.identifier.hex()

        print("\n" + "=" * 50)
        print("πŸ“± NFC Tag Detected")
        print(f"   UID: {tag_uid}")
        print(f"   Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")

        # Log access
        self.access_log.append({
            "uid": tag_uid,
            "timestamp": datetime.now().isoformat()
        })

        # Find and execute scene
        if tag_uid in self.tag_scenes:
            scene_name = self.tag_scenes[tag_uid]
            self.execute_scene(scene_name)
        else:
            print(f"⚠️  Unknown tag: {tag_uid}")
            print("   Register this tag with a scene")

        print("=" * 50)
        return True

    def start_nfc_listener(self):
        """Start listening for NFC tags"""
        try:
            clf = nfc.ContactlessFrontend('usb')
            print("βœ“ NFC reader initialized")

            print("\n" + "=" * 50)
            print("🏠 NFC Smart Home Server Running")
            print("=" * 50)
            print("πŸ“± Tap NFC tag to trigger scenes...")

            while True:
                clf.connect(
                    rdwr={'on-connect': self.on_tag_scan},
                    terminate=lambda: False
                )

        except Exception as e:
            print(f"❌ NFC Error: {e}")
            print("   Make sure PN532 is connected")


def main():
    """Main entry point"""
    server = NFCSmartHomeServer()

    # Setup MQTT connection
    server.setup_mqtt(broker="localhost", port=1883)

    # Register smart home devices
    server.register_device("light_001", "Living Room Light", "home/lights/living")
    server.register_device("light_002", "Bedroom Light", "home/lights/bedroom")
    server.register_device("thermo_001", "Thermostat", "home/climate/thermostat")

    # Create scenes
    server.create_scene(
        "Goodnight",
        "Turn off all lights, set thermostat to 68Β°F",
        [
            {"device": "light_001", "command": "turn", "value": "OFF"},
            {"device": "light_002", "command": "turn", "value": "OFF"},
            {"device": "thermo_001", "command": "set", "value": "68"}
        ]
    )

    server.create_scene(
        "Wake Up",
        "Turn on bedroom light, set thermostat to 72Β°F",
        [
            {"device": "light_002", "command": "turn", "value": "ON"},
            {"device": "thermo_001", "command": "set", "value": "72"},
            {"description": "Start coffee maker"}
        ]
    )

    server.create_scene(
        "Welcome Home",
        "Turn on lights, adjust temperature",
        [
            {"device": "light_001", "command": "turn", "value": "ON"},
            {"device": "thermo_001", "command": "set", "value": "70"},
            {"description": "Disarm security system"}
        ]
    )

    # Map NFC tags to scenes (replace with your tag UIDs)
    server.map_tag_to_scene("04a3b2c1d45e80", "Goodnight")
    server.map_tag_to_scene("08f7e29a3b1c4d", "Wake Up")
    server.map_tag_to_scene("123456789abcde", "Welcome Home")

    # Start web dashboard in background
    print("βœ“ Web dashboard: http://localhost:5000")

    # Start NFC listener (blocking)
    server.start_nfc_listener()


if __name__ == "__main__":
    main()

Testing (Without Hardware):

If you don’t have NFC hardware, you can simulate tag scans:

# Add to NFCSmartHomeServer class:
def simulate_tag_scan(self, tag_uid: str):
    """Simulate NFC tag scan for testing"""
    class FakeTag:
        def __init__(self, uid):
            self.identifier = bytes.fromhex(uid)

    self.on_tag_scan(FakeTag(tag_uid))

# Usage:
server.simulate_tag_scan("04a3b2c1d45e80")  # Triggers goodnight scene

Expected Output:

βœ“ NFC reader initialized
βœ“ Connected to MQTT broker: localhost
βœ“ Device registered: Living Room Light (light_001)
βœ“ Device registered: Bedroom Light (light_002)
βœ“ Device registered: Thermostat (thermo_001)
βœ“ Scene created: Goodnight
βœ“ Scene created: Wake Up
βœ“ Scene created: Welcome Home
βœ“ Tag 04a3b2c1d45e80 mapped to scene 'Goodnight'
βœ“ Tag 08f7e29a3b1c4d mapped to scene 'Wake Up'
βœ“ Tag 123456789abcde mapped to scene 'Welcome Home'
βœ“ Web dashboard: http://localhost:5000

==================================================
🏠 NFC Smart Home Server Running
==================================================
πŸ“± Tap NFC tag to trigger scenes...

==================================================
πŸ“± NFC Tag Detected
   UID: 04a3b2c1d45e80
   Time: 2025-01-15 22:30:45

🎬 Executing scene: Goodnight
   Turn off all lights, set thermostat to 68Β°F
βœ“ Living Room Light turn OFF
βœ“ Bedroom Light turn OFF
  β†’ Thermostat set to 68Β°F
βœ… Scene 'Goodnight' completed

==================================================

879.5 Python Implementations

879.5.1 Implementation 1: NFC Tag and Reader Simulator

Expected Output:

=== NFC Tag & Reader Simulation ===

✍️  Writing to tag 04:A3:B2:C1:D4:5E:80
βœ“ Record written to tag 04:A3:B2:C1:D4:5E:80
✍️  Writing to tag 04:A3:B2:C1:D4:5E:80
βœ“ Record written to tag 04:A3:B2:C1:D4:5E:80
✍️  Writing to tag 08:F7:E2:9A:3B:1C:4D
❌ Incorrect password for tag 08:F7:E2:9A:3B:1C:4D
✍️  Writing to tag 08:F7:E2:9A:3B:1C:4D
βœ“ Record written to tag 08:F7:E2:9A:3B:1C:4D

--- Reading Tags ---
πŸ“± Reading tag 04:A3:B2:C1:D4:5E:80 at 2.8cm
  Record 1: U = https://iotclass.example.com
  Record 2: T = Welcome to IoT Class!
❌ Tag out of range: 15.8cm (max: 10.0cm)

πŸ”’ Tag 04:A3:B2:C1:D4:5E:80 is now permanently read-only
✍️  Writing to tag 04:A3:B2:C1:D4:5E:80
❌ Tag 04:A3:B2:C1:D4:5E:80 is locked (read-only)

--- Reader Statistics ---
Total reads: 2
Unique tags: 1
Average distance: 9.3cm

--- Tag Memory ---
Poster tag: 62/48 bytes
Payment tag: 30/4096 bytes

879.5.2 Implementation 2: NFC Payment System

Expected Output:

=== NFC Mobile Payment Simulation ===

βœ“ Card ending in 4532 added to iPhone-12-ABC123
βœ“ Card ending in 8765 added to iPhone-12-ABC123

--- Transaction 1: Coffee Purchase ---
πŸ’³ Terminal ready: $4.75 at Coffee Shop
πŸ“± Tap your device to pay...
πŸ‘€ Biometric verified (fingerprint)
βœ… Payment successful: $4.75
   Card: ****4532
   Transaction ID: a3f7c2e1d9b4

--- Transaction 2: Grocery Purchase ---
πŸ’³ Terminal ready: $47.82 at Coffee Shop
πŸ“± Tap your device to pay...
πŸ‘€ Biometric verified (fingerprint)
βœ… Payment successful: $47.82
   Card: ****4532
   Transaction ID: f8e2a7c3b1d6

--- Transaction 3: Large Purchase (Exceeds Limit) ---
❌ Amount $150.00 exceeds contactless limit $100.00

--- Transaction 4: Without Biometric ---
πŸ’³ Terminal ready: $12.50 at Coffee Shop
πŸ“± Tap your device to pay...
⚠️  Biometric not enabled - payment may require PIN
❌ Biometric authentication required

--- Terminal Summary ---
Total transactions: 3
Successful: 2
Today's total: $52.57

879.6 Summary

This chapter covered NFC IoT integration:

  • Gateway Pattern: NFC readers connecting to cloud via MQTT
  • Access Control Lab: ESP32-based door lock with PN532 reader
  • Smart Home Server: Raspberry Pi automation with scene triggers
  • MQTT Integration: Publishing NFC events to message brokers

879.7 What’s Next

Continue to NFC Security and Comparisons to explore NFC security analysis, payment security architecture, and detailed comparisons with Bluetooth LE and QR codes.