IoT / MQTT Template¶
Real-time dashboards for IoT devices and sensors.
What Makes This Different?¶
The IoT Template extends the Base Template with real-time capabilities for connecting to and displaying data from IoT devices.
Key Additions to Base Template¶
| Feature | Purpose |
|---|---|
| Django Channels | WebSocket support |
| MQTT Client | Connect to MQTT brokers |
| ASGI Server | Async request handling |
| Real-time Models | Sensor data storage |
| Dashboard Components | Live data visualization |
The Stack¶
Base Template (unchanged):
├── Wagtail 7.3
├── Django 6.0
└── Tailwind CSS v4
IoT Additions:
├── Django Channels 4.0
├── MQTT Client (paho-mqtt)
├── ASGI (Daphne/Uvicorn)
├── Redis (channel layer)
└── WebSocket consumers
How It Works¶
IoT Device (Sensor)
│
▼ (MQTT Publish)
MQTT Broker (Mosquitto/AWS IoT)
│
▼ (MQTT Subscribe)
RhamaaCMS (MQTT Consumer)
│
├── Store in Database
└── Broadcast via WebSocket
│
▼
Browser (Live Dashboard)
Project Structure¶
myproject/
├── apps/
│ ├── home/ # Standard pages
│ └── mqtt/ # NEW: IoT functionality
│ ├── models.py # Sensor, Reading models
│ ├── consumers.py # WebSocket consumers
│ ├── mqtt_client.py # MQTT connection
│ └── templates/
│ └── mqtt/
│ └── dashboard.html
├── utils/
│ └── models.py # BasePage (unchanged)
├── myproject/
│ ├── asgi.py # NEW: ASGI application
│ └── settings/base.py # MQTT settings
└── templates/
Key Components¶
MQTT Client¶
# apps/mqtt/mqtt_client.py
import paho.mqtt.client as mqtt
from channels.layers import get_channel_layer
from asgiref.sync import async_to_sync
class MQTTClient:
def __init__(self):
self.client = mqtt.Client()
self.client.on_connect = self.on_connect
self.client.on_message = self.on_message
def on_connect(self, client, userdata, flags, rc):
client.subscribe("sensors/+/data")
def on_message(self, client, userdata, msg):
# Broadcast to WebSocket
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
"sensors",
{
"type": "sensor_data",
"data": msg.payload.decode(),
}
)
WebSocket Consumer¶
# apps/mqtt/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class SensorConsumer(AsyncWebsocketConsumer):
async def connect(self):
await self.channel_layer.group_add("sensors", self.channel_name)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard("sensors", self.channel_name)
async def sensor_data(self, event):
await self.send(text_data=json.dumps(event))
Sensor Models¶
# apps/mqtt/models.py
from django.db import models
class Sensor(models.Model):
name = models.CharField(max_length=100)
device_id = models.CharField(max_length=50, unique=True)
location = models.CharField(max_length=200)
sensor_type = models.CharField(
max_length=50,
choices=[
('temperature', 'Temperature'),
('humidity', 'Humidity'),
('pressure', 'Pressure'),
]
)
def __str__(self):
return f"{self.name} ({self.device_id})"
class Reading(models.Model):
sensor = models.ForeignKey(Sensor, on_delete=models.CASCADE)
value = models.FloatField()
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-timestamp']
Running the Server¶
The IoT Template requires ASGI instead of WSGI:
# Development
python manage.py runserver
# Production (with WebSocket support)
daphne -p 8000 myproject.asgi:application
# Or with uvicorn
uvicorn myproject.asgi:application --reload --lifespan on --port 8000
MQTT Dashboard¶
A built-in dashboard for monitoring sensors:
Features: - Real-time sensor readings - Historical data charts - Device status overview - MQTT connection status
Configuration¶
Environment Variables¶
# .env or settings/local.py
MQTT_BROKER_HOST = "localhost"
MQTT_BROKER_PORT = 1883
MQTT_USERNAME = "your_username"
MQTT_PASSWORD = "your_password"
MQTT_USE_TLS = True # For production
# For AWS IoT
MQTT_BROKER_HOST = "your-endpoint.iot.region.amazonaws.com"
MQTT_USE_TLS = True
MQTT_CLIENT_CERT = "/path/to/cert.pem"
MQTT_CLIENT_KEY = "/path/to/private.key"
ASGI Configuration¶
# myproject/asgi.py
import os
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings.production")
application = ProtocolTypeRouter({
"http": get_asgi_application(),
"websocket": URLRouter(
# WebSocket routes
),
})
When to Choose This Template¶
✅ Good for: - IoT device dashboards - Real-time monitoring systems - Sensor data visualization - Smart home interfaces - Industrial monitoring
❌ Not ideal for: - Simple content websites (use Base) - SPAs (use React template) - Sites without real-time needs
Full Documentation¶
Complete IoT template docs are in the docs/ folder of the base-iot branch, including: - MQTT broker setup - WebSocket security - Data visualization - Production deployment