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 flaskEstimated Time: 45 minutes
894.3 System Architecture
The NFC smart home system uses a three-layer architecture: tag detection, scene mapping, and device control.
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 flask894.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 test894.8 NFC Mode Selection Analysis
For smart home applications, Read/Write mode with passive NFC tags is the optimal choice:
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:
- Cost-effective: Passive tags cost $0.20-$2.00 each
- No power required: Tags powered by phoneβs RF field
- Simple deployment: Stick tags anywhere
- Permanent placement: No battery replacement needed
- 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:
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.