MQTT Brokers Guide¶
Django DeviceHub communicates with IoT devices through MQTT brokers. This guide covers broker configuration, EMQX and Mosquitto setup, TLS, shared subscriptions, multi-broker setups, and the built-in HTTP authentication endpoints.
Broker Configuration¶
Brokers are configured in DJANGO_DEVICEHUB["BROKERS"]. Each entry is a named broker with its connection parameters:
DJANGO_DEVICEHUB = {
"BROKERS": {
"default": {
"ENGINE": "django_devicehub.brokers.mqtt.MQTTBroker",
"HOST": "localhost",
"PORT": 1883,
"USERNAME": "",
"PASSWORD": "",
"CLIENT_ID": "",
"KEEPALIVE": 60,
"USE_TLS": False,
"CA_CERTS": "",
"CERTFILE": "",
"KEYFILE": "",
"USE_SHARED_SUBSCRIPTIONS": True,
"SHARE_GROUP": "django-devicehub",
"AUTH_BACKEND": False,
}
},
}
Configuration keys¶
| Key | Type | Default | Description |
|---|---|---|---|
ENGINE |
str |
"django_devicehub.brokers.mqtt.MQTTBroker" |
Broker backend class |
HOST |
str |
"localhost" |
Broker hostname |
PORT |
int |
1883 |
Broker port (1883 plain, 8883 TLS) |
USERNAME |
str |
"" |
Server-side credentials for the Django listener |
PASSWORD |
str |
"" |
Server-side password |
CLIENT_ID |
str |
"" |
MQTT client ID (auto-generated if empty) |
KEEPALIVE |
int |
60 |
MQTT keepalive interval in seconds |
USE_TLS |
bool |
False |
Enable TLS encryption |
CA_CERTS |
str |
"" |
Path to CA certificate file |
CERTFILE |
str |
"" |
Path to client certificate (mutual TLS) |
KEYFILE |
str |
"" |
Path to client private key (mutual TLS) |
USE_SHARED_SUBSCRIPTIONS |
bool |
True |
Use MQTT 5 shared subscriptions |
SHARE_GROUP |
str |
"django-devicehub" |
Shared subscription group name |
AUTH_BACKEND |
bool |
False |
Enable HTTP auth endpoints for this broker |
EMQX Setup¶
EMQX is recommended for production. It supports MQTT 5.0, shared subscriptions, clustering, and HTTP authentication natively.
Docker Compose¶
services:
emqx:
image: emqx/emqx:5.8
ports:
- "1883:1883" # MQTT
- "8083:8083" # WebSocket
- "18083:18083" # Dashboard
environment:
EMQX_NAME: devicehub
HTTP Authentication¶
EMQX can delegate device authentication to Django DeviceHub via HTTP. Enable AUTH_BACKEND in your broker config:
DJANGO_DEVICEHUB = {
"BROKERS": {
"default": {
"HOST": "emqx",
"PORT": 1883,
"AUTH_BACKEND": True,
}
},
}
Add the auth URLs to your project:
This exposes two endpoints:
POST /iot/broker/auth/-- authenticate device credentialsPOST /iot/broker/acl/-- authorize topic access
Configure EMQX to use these endpoints (via EMQX Dashboard or config file):
# emqx.conf
authentication = [
{
mechanism = password_based
backend = http
method = post
url = "http://django-app:8000/iot/broker/auth/"
body {
username = "${username}"
password = "${password}"
}
headers {
content-type = "application/json"
}
}
]
authorization {
sources = [
{
type = http
method = post
url = "http://django-app:8000/iot/broker/acl/"
body {
username = "${username}"
topic = "${topic}"
action = "${action}"
}
headers {
content-type = "application/json"
}
}
]
}
How the auth endpoints work¶
Authentication (BrokerAuthView): Receives {"username": "...", "password": "..."}, searches all registered device models for a matching mqtt_username, verifies the password hash, and returns {"result": "allow"} or {"result": "deny"}. On success, the device is marked online.
ACL (BrokerACLView): Receives {"username": "...", "topic": "...", "action": "pub"|"sub"}. Devices can only:
- Publish to their own
dataandstatustopics - Subscribe to their own
cmdtopic
This prevents devices from reading other devices' data or sending unauthorized commands.
Mosquitto Setup¶
Mosquitto is a lightweight alternative suitable for development and small deployments.
Docker Compose¶
services:
mosquitto:
image: eclipse-mosquitto:2
ports:
- "1883:1883"
volumes:
- ./mosquitto.conf:/mosquitto/config/mosquitto.conf
Basic config¶
For production, use the mosquitto-auth-plug or mosquitto-go-auth plugin to delegate authentication to Django DeviceHub's HTTP endpoints.
TLS Configuration¶
Enable TLS to encrypt communication between devices and the broker:
DJANGO_DEVICEHUB = {
"BROKERS": {
"default": {
"HOST": "mqtt.example.com",
"PORT": 8883,
"USE_TLS": True,
"CA_CERTS": "/path/to/ca.crt",
}
},
}
Mutual TLS (mTLS)¶
For client certificate authentication, provide both the certificate and key:
DJANGO_DEVICEHUB = {
"BROKERS": {
"default": {
"HOST": "mqtt.example.com",
"PORT": 8883,
"USE_TLS": True,
"CA_CERTS": "/path/to/ca.crt",
"CERTFILE": "/path/to/client.crt",
"KEYFILE": "/path/to/client.key",
}
},
}
Shared Subscriptions¶
MQTT 5.0 shared subscriptions distribute messages across multiple listeners, enabling horizontal scaling. When USE_SHARED_SUBSCRIPTIONS is True (the default), topics are subscribed as:
This means if you run 3 instances of iot_listen, each message is delivered to exactly one instance rather than all three.
Customizing the share group¶
DJANGO_DEVICEHUB = {
"BROKERS": {
"default": {
"USE_SHARED_SUBSCRIPTIONS": True,
"SHARE_GROUP": "my-app-workers",
}
},
}
Disabling shared subscriptions¶
For single-instance deployments or brokers that do not support MQTT 5.0:
Multiple Brokers¶
You can configure multiple brokers for different device types or environments:
DJANGO_DEVICEHUB = {
"BROKERS": {
"default": {
"HOST": "mqtt.internal.example.com",
"PORT": 1883,
},
"lorawan": {
"HOST": "lora-broker.example.com",
"PORT": 8883,
"USE_TLS": True,
"CA_CERTS": "/path/to/ca.crt",
},
"cloud": {
"HOST": "mqtt.cloud-provider.com",
"PORT": 8883,
"USE_TLS": True,
"USERNAME": "cloud-user",
"PASSWORD": "cloud-pass",
},
},
}
Assign device types to specific brokers via Meta:
class LoRaNode(DeviceType):
class Meta:
broker = "lorawan"
class CloudSensor(DeviceType):
class Meta:
broker = "cloud"
Start listeners for specific brokers:
python manage.py iot_listen --broker default
python manage.py iot_listen --broker lorawan
python manage.py iot_listen --broker cloud
MQTTBroker API¶
The MQTTBroker class wraps paho-mqtt with MQTT 5.0 support. Key methods:
from django_devicehub.brokers.mqtt import MQTTBroker
broker = MQTTBroker(name="default")
broker.connect() # connect to the configured host
broker.subscribe("things/+/+/data") # subscribe to a topic pattern
broker.publish("things/ws/001/cmd", # publish a message
{"command": "reboot"},
qos=1,
correlation_id="abc-123",
user_properties={"source": "admin"})
broker.loop_start() # start background message processing
broker.loop_stop() # stop background thread
broker.loop_forever() # blocking message loop
broker.disconnect() # disconnect from broker
broker.set_message_handler(callback) # set the on_message callback
The broker automatically subscribes to all registered device type topics on connect via _subscribe_all().
Writing a Custom Broker¶
Extend BaseBroker to support other protocols:
from django_devicehub.brokers.base import BaseBroker
class CoapBroker(BaseBroker):
def connect(self):
...
def disconnect(self):
...
def subscribe(self, topic, qos=1):
...
def publish(self, topic, payload, qos=1, **kwargs):
...
def loop_forever(self):
...
def loop_start(self):
...
def loop_stop(self):
...
Register it in settings: