MQTT Topic Structure¶
Django DeviceHub uses a structured topic hierarchy for MQTT communication. This page documents the topic format, standard channels, wildcard subscriptions, and how to customize topics.
Topic Format¶
The default topic template is:
Example topics for a WeatherStation device with prefix "myproject":
myproject/weatherstation/STATION-001/data
myproject/weatherstation/STATION-001/status
myproject/weatherstation/STATION-001/cmd
Segments¶
| Segment | Source | Example |
|---|---|---|
prefix |
DJANGO_DEVICEHUB["TOPIC_PREFIX"] setting |
myproject |
type_name |
DeviceType class name, lowercased | weatherstation |
device_id |
device.device_id field |
STATION-001 |
message_type |
Channel: data, status, or cmd |
data |
Standard Channels¶
data¶
Direction: Device -> Server
Devices publish sensor readings to the data channel. The MessageRouter parses the payload, creates a Reading record, and fires the device_data_received signal.
Payload (flat format):
Payload (readings list format):
status¶
Direction: Device -> Server
Devices publish status updates (heartbeat, battery level, firmware version) to the status channel.
Payload:
Valid status values: online, offline, error, maintenance, low_battery, provisioning.
cmd¶
Direction: Server -> Device
The server publishes commands to the cmd channel. Devices subscribe to this channel to receive instructions.
Payload:
Commands without payload:
Wildcard Subscriptions¶
The iot_listen command subscribes to topics using MQTT + wildcards for the device_id segment:
This subscribes to data and status messages from all devices of a given type. The + wildcard matches exactly one topic level.
Generating subscribe topics¶
topics = WeatherStation.get_subscribe_topics()
# ['myproject/weatherstation/+/data', 'myproject/weatherstation/+/status']
Shared Subscriptions¶
When USE_SHARED_SUBSCRIPTIONS is enabled (the default), subscriptions use the MQTT 5.0 shared subscription format:
This distributes messages across multiple iot_listen instances, enabling horizontal scaling. Each message is delivered to exactly one listener in the share group.
The share group name is configurable via SHARE_GROUP (default: "django-devicehub").
Topic Utilities¶
The django_devicehub.utils.topic module provides helper functions for working with topics:
build_topic(type_name, device_id, message_type="data", template=None)¶
Build a topic string:
from django_devicehub.utils.topic import build_topic
topic = build_topic("weatherstation", "STATION-001", "data")
# "myproject/weatherstation/STATION-001/data"
topic = build_topic("weatherstation", "STATION-001", "cmd")
# "myproject/weatherstation/STATION-001/cmd"
parse_topic(topic)¶
Parse a topic string into its components:
from django_devicehub.utils.topic import parse_topic
result = parse_topic("myproject/weatherstation/STATION-001/data")
# ("weatherstation", "STATION-001", "data")
result = parse_topic("unrelated/topic")
# None
Returns a 3-tuple (type_name, device_id, message_type) or None if the topic does not match the expected pattern. Only data, status, and cmd are recognized as valid message types.
build_subscribe_pattern(type_name, message_type="+")¶
Build a subscription pattern with a + wildcard for device_id:
from django_devicehub.utils.topic import build_subscribe_pattern
pattern = build_subscribe_pattern("weatherstation")
# "myproject/weatherstation/+/+"
pattern = build_subscribe_pattern("weatherstation", "data")
# "myproject/weatherstation/+/data"
Generating Topics from DeviceType¶
The DeviceType class provides methods for topic generation:
get_topic(device_id, message_type="data")¶
Generate the full topic for a specific device:
topic = WeatherStation.get_topic("STATION-001", "data")
# "myproject/weatherstation/STATION-001/data"
topic = WeatherStation.get_topic("STATION-001", "cmd")
# "myproject/weatherstation/STATION-001/cmd"
get_subscribe_topics()¶
Get the MQTT topic patterns for subscribing to all devices:
topics = WeatherStation.get_subscribe_topics()
# ["myproject/weatherstation/+/data", "myproject/weatherstation/+/status"]
Custom Topic Templates¶
Override the topic template in the DeviceType Meta:
class LoRaNode(DeviceType):
class Meta:
topic_template = "lora/{type_name}/{device_id}/{message_type}"
This produces topics like:
Note that the {prefix} placeholder is still resolved from TOPIC_PREFIX, even if you do not include it in your template.
The template must contain {type_name}, {device_id}, and {message_type} placeholders. The {prefix} placeholder is optional.
ACL Rules¶
When using the built-in broker auth endpoints, the ACL (BrokerACLView) enforces these rules:
| Action | Allowed Topics |
|---|---|
Publish (pub) |
{prefix}/{type}/{device_id}/data, {prefix}/{type}/{device_id}/status |
Subscribe (sub) |
{prefix}/{type}/{device_id}/data, {prefix}/{type}/{device_id}/status, {prefix}/{type}/{device_id}/cmd |
A device can only access its own topics. It cannot publish to or subscribe to topics belonging to other devices or other device types.