894  NFC Smart Home Automation

894.1 Learning Objectives

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

  • Design NFC Scene Systems: Create tap-to-activate smart home automation
  • Build Python NFC Servers: Implement nfcpy-based tag reading on Raspberry Pi
  • Integrate MQTT Control: Connect NFC events to smart home devices
  • Create Tag-Scene Mappings: Associate NFC tags with multi-device automation sequences
  • Implement Web Dashboards: Build Flask-based control interfaces
  • Compare Technology Options: Select optimal technology for museum/gallery applications

Imagine placing small NFC stickers around your home: - Bedside tag: Tap before sleep to turn off all lights, lock doors, set thermostat - Desk tag: Tap when working to set office lighting and Do Not Disturb mode - Kitchen tag: Tap to start coffee maker and turn on morning news

This chapter teaches you to build the server that responds to these taps and orchestrates all your smart devices!

Prerequisites: - NFC Access Control - ESP32 NFC fundamentals - NFC Fundamentals - Core NFC concepts

Continue Learning: - NFC Security and Comparisons - Payment security and technology selection - NFC Applications - Real-world NFC deployments

894.2 Prerequisites

Required Knowledge: - Python programming fundamentals - Basic understanding of MQTT publish/subscribe - Familiarity with Flask web framework (helpful)

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

Software Dependencies:

pip3 install nfcpy paho-mqtt flask

Estimated Time: 45 minutes

894.3 System Architecture

The NFC smart home system uses a three-layer architecture: tag detection, scene mapping, and device control.

Flowchart diagram

Flowchart diagram
Figure 894.1: NFC smart home automation architecture showing tag-to-scene mapping, MQTT-based device control, and web dashboard integration for multi-device orchestration.

894.4 Installation and Setup

894.4.1 Enable I2C on Raspberry Pi

# Enable I2C interface
sudo raspi-config
# Interface Options β†’ I2C β†’ Enable

# Install dependencies
pip3 install nfcpy paho-mqtt flask

894.4.2 Verify NFC Reader

# Check if PN532 is detected
python3 -c "import nfc; clf = nfc.ContactlessFrontend('i2c'); print(clf)"

894.5 NFC Smart Home Server Implementation

The following Python implementation provides a complete NFC smart home automation server:

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

import nfc
import paho.mqtt.client as mqtt
from flask import Flask, jsonify, render_template_string
from threading import Thread
from datetime import datetime
from typing import Dict, List, Optional
from dataclasses import dataclass, field

@dataclass
class SmartDevice:
    """Represents a controllable smart home device"""
    id: str
    name: str
    device_type: str  # 'light', 'switch', 'thermostat', 'lock'
    mqtt_topic: str
    state: str = "off"

@dataclass
class Scene:
    """Collection of device actions triggered by NFC tag"""
    id: str
    name: str
    description: str
    actions: List[Dict] = field(default_factory=list)

class NFCSmartHomeServer:
    def __init__(self, mqtt_broker: str = "localhost", mqtt_port: int = 1883):
        # Device registry
        self.devices: Dict[str, SmartDevice] = {}

        # Scene definitions
        self.scenes: Dict[str, Scene] = {}

        # NFC tag to scene mapping
        self.tag_scene_map: Dict[str, str] = {}

        # Event log
        self.event_log: List[Dict] = []

        # MQTT client
        self.mqtt_client = mqtt.Client()
        self.mqtt_broker = mqtt_broker
        self.mqtt_port = mqtt_port

        # Flask app for dashboard
        self.app = Flask(__name__)
        self._setup_routes()

        # NFC reader
        self.clf = None

    def register_device(self, device: SmartDevice) -> None:
        """Register a smart device for control"""
        self.devices[device.id] = device
        print(f"βœ“ Device registered: {device.name} ({device.id})")

    def create_scene(self, scene: Scene) -> None:
        """Create a new automation scene"""
        self.scenes[scene.id] = scene
        print(f"βœ“ Scene created: {scene.name}")

    def map_tag_to_scene(self, tag_uid: str, scene_id: str) -> None:
        """Associate NFC tag with scene"""
        if scene_id not in self.scenes:
            raise ValueError(f"Scene '{scene_id}' not found")
        self.tag_scene_map[tag_uid.lower()] = scene_id
        print(f"βœ“ Tag {tag_uid} mapped to scene '{scene_id}'")

    def execute_scene(self, scene_id: str) -> bool:
        """Execute all actions in a scene"""
        if scene_id not in self.scenes:
            return False

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

        for action in scene.actions:
            device_id = action.get("device")
            command = action.get("command")
            value = action.get("value")

            if device_id in self.devices:
                device = self.devices[device_id]
                self._send_command(device, command, value)

        print(f"βœ… Scene '{scene.name}' completed")
        return True

    def _send_command(self, device: SmartDevice, command: str, value: any) -> None:
        """Send MQTT command to device"""
        topic = device.mqtt_topic
        payload = f'{{"command": "{command}", "value": {value}}}'

        if self.mqtt_client.is_connected():
            self.mqtt_client.publish(topic, payload)

        # Update local state
        if command == "turn_on":
            device.state = "on"
            print(f"βœ“ {device.name} turned ON")
        elif command == "turn_off":
            device.state = "off"
            print(f"βœ“ {device.name} turned OFF")
        elif command == "set":
            device.state = str(value)
            print(f"  β†’ {device.name} set to {value}")

    def on_tag_scan(self, tag) -> None:
        """Handle NFC tag detection"""
        uid = tag.identifier.hex()
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        print("\n" + "=" * 50)
        print("πŸ“± NFC Tag Detected")
        print(f"   UID: {uid}")
        print(f"   Time: {timestamp}")

        # Log event
        event = {
            "timestamp": timestamp,
            "tag_uid": uid,
            "action": "scan"
        }
        self.event_log.append(event)

        # Check for scene mapping
        if uid.lower() in self.tag_scene_map:
            scene_id = self.tag_scene_map[uid.lower()]
            self.execute_scene(scene_id)
            event["scene"] = scene_id
            event["result"] = "success"
        else:
            print(f"❌ Unknown tag: {uid}")
            event["result"] = "unknown_tag"

        print("=" * 50)

    def _nfc_loop(self) -> None:
        """Continuous NFC tag reading loop"""
        try:
            self.clf = nfc.ContactlessFrontend('i2c')
            print("βœ“ NFC reader initialized")

            while True:
                # Wait for tag (blocking)
                tag = self.clf.connect(rdwr={'on-connect': lambda t: False})
                if tag:
                    self.on_tag_scan(tag)
        except Exception as e:
            print(f"NFC Error: {e}")

    def _setup_routes(self) -> None:
        """Setup Flask web dashboard routes"""

        @self.app.route('/')
        def dashboard():
            return render_template_string(DASHBOARD_HTML,
                devices=self.devices.values(),
                scenes=self.scenes.values(),
                events=self.event_log[-20:])

        @self.app.route('/api/devices')
        def api_devices():
            return jsonify([{
                'id': d.id,
                'name': d.name,
                'type': d.device_type,
                'state': d.state
            } for d in self.devices.values()])

        @self.app.route('/api/scenes')
        def api_scenes():
            return jsonify([{
                'id': s.id,
                'name': s.name,
                'description': s.description
            } for s in self.scenes.values()])

        @self.app.route('/api/events')
        def api_events():
            return jsonify(self.event_log[-50:])

        @self.app.route('/api/trigger/<scene_id>')
        def trigger_scene(scene_id):
            success = self.execute_scene(scene_id)
            return jsonify({'success': success})

    def simulate_tag_scan(self, tag_uid: str) -> None:
        """Simulate NFC tag scan for testing without hardware"""
        class FakeTag:
            def __init__(self, uid):
                self.identifier = bytes.fromhex(uid.replace(' ', ''))

        self.on_tag_scan(FakeTag(tag_uid))

    def start(self) -> None:
        """Start all services"""
        # Connect to MQTT broker
        try:
            self.mqtt_client.connect(self.mqtt_broker, self.mqtt_port)
            self.mqtt_client.loop_start()
            print(f"βœ“ Connected to MQTT broker: {self.mqtt_broker}")
        except Exception as e:
            print(f"⚠ MQTT connection failed: {e}")

        # Start NFC reader in background thread
        nfc_thread = Thread(target=self._nfc_loop, daemon=True)
        nfc_thread.start()

        # Start Flask dashboard
        print(f"βœ“ Web dashboard: http://localhost:5000")
        print("\n" + "=" * 50)
        print("🏠 NFC Smart Home Server Running")
        print("=" * 50)
        print("πŸ“± Tap NFC tag to trigger scenes...")

        self.app.run(host='0.0.0.0', port=5000, debug=False)

# HTML template for web dashboard
DASHBOARD_HTML = '''
<!DOCTYPE html>
<html>
<head>
    <title>NFC Smart Home</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
        h1 { color: #2C3E50; }
        .section { background: white; padding: 20px; margin: 10px 0; border-radius: 8px; }
        .device { display: inline-block; padding: 10px 20px; margin: 5px;
                  border-radius: 4px; background: #16A085; color: white; }
        .scene { cursor: pointer; padding: 10px 20px; margin: 5px;
                 border-radius: 4px; background: #E67E22; color: white; border: none; }
        .scene:hover { background: #D35400; }
        .event { padding: 5px 10px; border-bottom: 1px solid #eee; }
    </style>
</head>
<body>
    <h1>🏠 NFC Smart Home Dashboard</h1>

    <div class="section">
        <h2>Devices</h2>
        {% for device in devices %}
        <div class="device">
            {{ device.name }}: {{ device.state }}
        </div>
        {% endfor %}
    </div>

    <div class="section">
        <h2>Scenes</h2>
        {% for scene in scenes %}
        <button class="scene" onclick="triggerScene('{{ scene.id }}')">
            {{ scene.name }}
        </button>
        {% endfor %}
    </div>

    <div class="section">
        <h2>Recent Events</h2>
        {% for event in events|reverse %}
        <div class="event">
            {{ event.timestamp }} - Tag: {{ event.tag_uid[:8] }}...
            β†’ {{ event.get('scene', 'unknown') }}
        </div>
        {% endfor %}
    </div>

    <script>
        function triggerScene(sceneId) {
            fetch('/api/trigger/' + sceneId)
                .then(r => r.json())
                .then(d => location.reload());
        }
    </script>
</body>
</html>
'''

def main():
    """Example setup and run"""
    server = NFCSmartHomeServer()

    # Register devices
    server.register_device(SmartDevice(
        id="light_001",
        name="Living Room Light",
        device_type="light",
        mqtt_topic="home/living_room/light"
    ))
    server.register_device(SmartDevice(
        id="light_002",
        name="Bedroom Light",
        device_type="light",
        mqtt_topic="home/bedroom/light"
    ))
    server.register_device(SmartDevice(
        id="thermo_001",
        name="Thermostat",
        device_type="thermostat",
        mqtt_topic="home/thermostat"
    ))

    # Create scenes
    server.create_scene(Scene(
        id="goodnight",
        name="Goodnight",
        description="Turn off all lights, set thermostat to 68Β°F",
        actions=[
            {"device": "light_001", "command": "turn_off", "value": None},
            {"device": "light_002", "command": "turn_off", "value": None},
            {"device": "thermo_001", "command": "set", "value": 68}
        ]
    ))
    server.create_scene(Scene(
        id="wakeup",
        name="Wake Up",
        description="Turn on bedroom light, set thermostat to 72Β°F",
        actions=[
            {"device": "light_002", "command": "turn_on", "value": None},
            {"device": "thermo_001", "command": "set", "value": 72}
        ]
    ))
    server.create_scene(Scene(
        id="welcome",
        name="Welcome Home",
        description="Turn on lights, comfortable temperature",
        actions=[
            {"device": "light_001", "command": "turn_on", "value": None},
            {"device": "thermo_001", "command": "set", "value": 70}
        ]
    ))

    # Map NFC tags to scenes
    server.map_tag_to_scene("04a3b2c1d45e80", "goodnight")
    server.map_tag_to_scene("08f7e29a3b1c4d", "wakeup")
    server.map_tag_to_scene("123456789abcde", "welcome")

    # Start server
    server.start()

if __name__ == "__main__":
    main()

894.6 Expected Output

When the server is running:

βœ“ 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 turned OFF
βœ“ Bedroom Light turned OFF
  β†’ Thermostat set to 68Β°F
βœ… Scene 'Goodnight' completed

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

894.7 Testing Without Hardware

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

# After server initialization, before server.start()
server.simulate_tag_scan("04a3b2c1d45e80")  # Triggers goodnight scene
server.simulate_tag_scan("08f7e29a3b1c4d")  # Triggers wake up scene
server.simulate_tag_scan("unknown_tag_id")   # Unknown tag test

894.8 NFC Mode Selection Analysis

For smart home applications, Read/Write mode with passive NFC tags is the optimal choice:

Flowchart diagram

Flowchart diagram
Figure 894.2: Read/Write mode for smart home scene triggering using passive NFC tags placed at strategic locations, enabling tap-to-activate automation with zero battery maintenance.

Why Read/Write Mode:

Factor Advantage
Cost Tags cost $0.20-$2.00 each
Power No batteries - powered by phone’s RF field
Deployment Stick tags anywhere (bedside, door, desk)
Maintenance Tags don’t need battery replacement
Compatibility NDEF records work across iOS and Android

Cost Comparison:

Approach Component Cost 5-Year Maintenance
NFC Tags 10 tags Γ— $0.50 $5.00 $0
BLE Beacons 10 beacons Γ— $15 $150 $90 (batteries)
Active ESP32 10 modules Γ— $5 + power $80 $50

NFC saves 95% vs active device approach!

894.9 Knowledge Check: Smart Home Mode Selection

Question: You’re designing a smart home system where users tap their smartphone to NFC tags placed around the house to trigger scenes. Which NFC operating mode is most appropriate?

Read/Write mode - Phone reads passive NFC tags

Read/Write mode is ideal because:

  1. Cost-effective: Passive tags cost $0.20-$2.00 each
  2. No power required: Tags powered by phone’s RF field
  3. Simple deployment: Stick tags anywhere
  4. Permanent placement: No battery replacement needed
  5. Standardized: NDEF records work across all phones

Why not other modes:

  • Peer-to-Peer: Requires two active devices - impractical to have active devices at every location
  • Card Emulation: Phone emulates a card for terminals - reversed roles from what we need

894.10 Museum Audio Guide Comparison

NFC excels for museum and gallery applications where visitors tap exhibits for information:

Flowchart diagram

Flowchart diagram
Figure 894.3: Museum audio guide technology comparison showing total cost of ownership over 5 years, with NFC winning due to zero maintenance costs and long lifespan despite higher upfront cost than QR codes.

5-Year Total Cost of Ownership (150 exhibits):

Technology Initial Annual Maint. 5-Year Total Per Exhibit
NFC Tags $75 $0 $75 $0.50
BLE Beacons $2,250 $900 $6,750 $45.00
QR Codes $82.50 $16.50 $165 $1.10

Winner: NFC Tags (93% score)

  • Best user experience: Intuitive tap gesture
  • Zero maintenance: No batteries to replace
  • Perfect accuracy: Explicit exhibit selection
  • Durable: Waterproof, 10+ year lifespan
  • Discreet: Small 2cm sticker

Hybrid Approach (Recommended):

For maximum compatibility: - Primary: NFC tags for 99% of visitors (NFC-enabled phones) - Fallback: Small QR code printed below NFC sticker - Cost: $0.55 per exhibit (NFC $0.50 + QR $0.05) - Benefits: Works with ALL smartphones

894.11 Summary

This chapter covered building a Python-based NFC smart home automation system:

  • System Architecture: Tag detection, scene mapping, and MQTT-based device control
  • Python Implementation: Using nfcpy for NFC reading and Flask for web dashboard
  • Scene Management: Creating and executing multi-device automation sequences
  • Technology Selection: NFC’s advantages over BLE and QR codes for tap-to-activate scenarios
  • Cost Analysis: NFC tags provide lowest total cost of ownership for permanent installations

The combination of passive NFC tags and a central server enables intuitive, maintenance-free smart home control.

894.12 What’s Next

Continue to NFC Security and Comparisons to understand how NFC mobile payments achieve bank-level security and when to choose NFC over alternative technologies.