MQTT is a lightweight messaging protocol for IoT devices and unreliable connections.
When we want to connect a device to the internet, our first instinct is often to use HTTP requests (GET/POST), as we saw in the previous chapter.
But HTTP is a “heavy” and “verbose” protocol. It is designed for large documents. For a sensor that just wants to say “I’m at 25°C”, HTTP is like sending a registered letter in an armored truck just to say “Hello”.
For the Internet of Things (IoT), one of the most commonly used options is MQTT (Message Queuing Telemetry Transport).
Its advantages are clear:
- Lightweight: Tiny headers (2 bytes).
- Fast: Near-instant latency.
- Pub/Sub Model: Decouples the sender from the receiver.
Architecture: Broker and Publish/Subscribe
In MQTT, devices do not connect directly to each other. There is no direct connection between your temperature sensor and your mobile phone.
Instead, there is a central figure called the Broker.
- The Broker: It’s the “mail server” or “bulletin board”. Its only job is to receive messages and distribute them to whoever is interested. (Examples: Mosquitto, HiveMQ, EMQX).
- Publish: A device sends a message to a Topic. E.g., “The sensor publishes
25on the topichouse/livingroom/temperature”. - Subscribe: A device tells the Broker: “Notify me whenever something arrives on the topic
house/livingroom/temperature”.
The sensor publishes, the Broker receives the message and forwards it immediately to your mobile phone (which was subscribed). The sensor doesn’t know or care who is listening.
The umqtt.simple Library
The official micropython-lib repository offers a lightweight implementation called umqtt.simple. Not all firmwares include it, so it’s worth checking before importing the module.
If it’s not installed, you can add it using mip from a board with network access or using mpremote from your computer:
import mip
mip.install("umqtt.simple")
mpremote mip install umqtt.simplePublishing Data
Let’s configure our microcontroller to send a data point every 5 seconds.
For this example, we will use a free public broker (broker.hivemq.com or test.mosquitto.org), so you don’t need to install anything on your PC.
import network
import time
from machine import unique_id
from ubinascii import hexlify
from umqtt.simple import MQTTClient
# 1. Network Configuration (Assuming you are already connected to WiFi)
# ... (WiFi connection code from previous chapters) ...
# 2. MQTT Configuration
mqtt_server = "broker.hivemq.com"
client_id = hexlify(unique_id()) # Generate a unique ID based on the MAC
topic_pub = b"luisllamas/curso/temp"
def connect_mqtt():
try:
print(f"Connecting to Broker {mqtt_server}...")
client = MQTTClient(client_id, mqtt_server)
client.connect()
print("Connected!")
return client
except OSError as e:
print("Connection error. Rebooting...")
time.sleep(5)
machine.reset()
# 3. Main Program
client = connect_mqtt()
while True:
try:
# Simulate a sensor reading
message = b"25.4"
print(f"Publishing {message} on {topic_pub}")
# Publish the message
client.publish(topic_pub, message)
time.sleep(5)
except OSError as e:
print("Error in loop, attempting to reconnect...")
client = connect_mqtt()
To test it, you can use a client like MQTT Explorer on your PC and subscribe to the topic luisllamas/curso/temp. The data will arrive instantly.
Subscribing to Commands
Now we want the opposite: control an LED remotely. Our board will subscribe to the topic luisllamas/curso/luz.
Here, the logic changes a bit. We need a Callback function. This function will execute automatically when a message arrives.
from machine import Pin
from umqtt.simple import MQTTClient
import ubinascii
import machine
import time
# LED on pin 2
led = Pin(2, Pin.OUT)
mqtt_server = "broker.hivemq.com"
client_id = ubinascii.hexlify(machine.unique_id())
topic_sub = b"luisllamas/curso/luz"
# --- The Callback Function ---
# This function is called when a message arrives
def sub_cb(topic, msg):
print(f"Message received on {topic}: {msg}")
if msg == b"ON":
led.value(1)
print("LED On")
elif msg == b"OFF":
led.value(0)
print("LED Off")
def connect_and_subscribe():
client = MQTTClient(client_id, mqtt_server)
# IMPORTANT: Assign the callback before connecting
client.set_callback(sub_cb)
client.connect()
client.subscribe(topic_sub)
print(f"Subscribed to: {topic_sub}")
return client
# --- Main Loop ---
client = connect_and_subscribe()
while True:
try:
# check_msg() checks if there are new messages in the buffer
# If there are, it automatically calls sub_cb()
# It is NON-BLOCKING (if nothing is there, it continues quickly)
client.check_msg()
# We can do other things while listening here...
time.sleep(0.1)
except OSError:
print("Disconnection detected. Reconnecting...")
client = connect_and_subscribe()
check_msg() vs wait_msg()
This is a critical point where many get stuck:
client.wait_msg(): It is blocking. The program stops there and does NOTHING ELSE until a message arrives. Useful if you are only waiting for commands.client.check_msg(): It is non-blocking. It checks if there is something; if not, it continues. This is what you should use if you want to blink an LED or read sensors while waiting for MQTT commands.
QoS: Quality of Service
MQTT allows you to define the reliability with which you want to deliver the message. In umqtt.simple we can specify this, although the Broker must also support it.
- QoS 0 (At most once): Fire and forget. If it’s lost, it’s lost. This is the fastest.
- QoS 1 (At least once): Guarantees delivery, but it might arrive duplicated. Requires acknowledgment (ACK).
# Publish with QoS 1
client.publish(topic, message, qos=1)
Retained Messages
Imagine a sensor publishes the temperature every hour. If you connect your mobile phone five minutes after the publication, do you have to wait another 55 minutes to know the temperature?
Not if you use the Retain flag.
If you publish with retain=True, the Broker saves the last message for that topic. Any new device that subscribes will receive immediately that last stored value.
# In umqtt.simple, publish(topic, msg, retain=False, qos=0)
client.publish(topic_pub, b"ON", retain=True)
With MQTT, we no longer have isolated devices, but an ecosystem connected in real-time. It is the foundation for creating dashboards in Home Assistant, Node-RED, or your own application.