MQTT is the protocol that powers most IoT deployments. Today you'll master it — broker setup, pub/sub, QoS levels, retained messages, and last-will topics.
MQTT broker routes messages between publishers and subscribers. Topic: hierarchical string like home/living-room/temperature. Subscribe with wildcards: home/+/temperature (single level) or home/# (all below). QoS levels: 0 = fire and forget, 1 = at least once (ACK), 2 = exactly once (4-way handshake). QoS 1 is the sweet spot for sensor data.
Retained message: broker stores the last message on a topic. New subscribers immediately receive the latest value — useful for device state. Last Will and Testament (LWT): when a device disconnects unexpectedly, the broker publishes a predefined message to a specified topic. Use this to detect device offline events: subscribe to home/sensor-01/status and get 'offline' when the device loses power.
Mosquitto is the most widely-used open-source MQTT broker. Install: apt install mosquitto mosquitto-clients. Configure authentication: create a password file with mosquitto_passwd -c /etc/mosquitto/passwd username. Enable TLS by pointing Mosquitto to your certificates. Public test broker: broker.hivemq.com:1883 (no auth, for testing only — never production data).
# MQTT publisher and subscriber with paho-mqtt
# pip install paho-mqtt
import json, time, threading
import paho.mqtt.client as mqtt
BROKER = "broker.hivemq.com" # free public broker for testing
PORT = 1883
TOPIC_DATA = "precisionai/demo/sensors"
TOPIC_STATUS = "precisionai/demo/status"
CLIENT_ID = "demo-sensor-01"
# ── Subscriber (runs in background) ─────────────────────────
def on_connect(client, userdata, flags, rc):
print(f"Subscriber connected: {rc}")
client.subscribe(TOPIC_DATA, qos=1)
client.subscribe(TOPIC_STATUS, qos=1)
def on_message(client, userdata, msg):
try:
payload = json.loads(msg.payload.decode())
print(f" [{msg.topic}] temp={payload.get('temp')}°C")
except:
print(f" [{msg.topic}] {msg.payload.decode()}")
sub = mqtt.Client(client_id="demo-subscriber")
sub.on_connect = on_connect
sub.on_message = on_message
sub.connect(BROKER, PORT, keepalive=60)
sub.loop_start()
time.sleep(1)
# ── Publisher ────────────────────────────────────────────────
import random
pub = mqtt.Client(client_id=CLIENT_ID)
# Last Will: auto-publish 'offline' if we disconnect unexpectedly
pub.will_set(TOPIC_STATUS, payload=json.dumps({"status":"offline","id":CLIENT_ID}), qos=1, retain=True)
pub.connect(BROKER, PORT, keepalive=60)
pub.loop_start()
# Announce online (retained so new subscribers see current state)
pub.publish(TOPIC_STATUS, json.dumps({"status":"online","id":CLIENT_ID}), qos=1, retain=True)
print(f"Publishing to {BROKER}:{PORT}/{TOPIC_DATA}")
for i in range(5):
payload = json.dumps({
"device": CLIENT_ID,
"temp": round(22 + random.gauss(0, 1), 1),
"hum": round(50 + random.gauss(0, 5), 1),
"seq": i,
})
result = pub.publish(TOPIC_DATA, payload, qos=1)
result.wait_for_publish()
print(f"Published #{i}: {payload}")
time.sleep(2)
pub.loop_stop()
sub.loop_stop()
print("Done.")
org/location/device/sensor. Never use spaces or special characters except /. Keep topics consistent — automated tools parse them. A common convention: company/site/device-id/metric.sudo apt install mosquitto mosquitto-clients.mosquitto_sub -h localhost -t '#' -v.device/commands, parse JSON like {"led":"on"}, and print the command.--cafile option.Implement MQTT topic ACL (Access Control List). Create two users: 'sensor' that can only publish to 'home/sensors/#', and 'dashboard' that can only subscribe to 'home/#'. Test that sensor user cannot subscribe, and dashboard user cannot publish. Document the mosquitto.conf settings required.