This is a complete guide to using MQTT with Raspberry Pi Pico programmed with MicroPython. MQTT is a communication protocol widely used in Home Automation and IoT applications to connect multiple devices. In this tutorial, you’ll learn how to choose and set up an MQTT broker and how to publish and subscribe to MQTT messages with the Raspberry Pi Pico.
New to the Raspberry Pi Pico? Get started with the Raspberry Pi Pico here.
Table of Contents:
Throughout this guide we’ll cover the following topics:
- Introducing MQTT
- MQTT Basic Concepts
- Set Up the MQTT Broker
- Installing MQTT MicroPython Modules
- Creating a Configuration File
- Publishing MQTT Messages
- Subscribing to MQTT Topics
Prerequisites
Before proceeding, make sure you check the following prerequisites:
MicroPython Firmware
To follow this tutorial you need MicroPython firmware installed in your Raspberry Pi Pico board. You also need an IDE to write and upload the code to your board.
The recommended MicroPython IDE for the Raspberry Pi Pico is Thonny IDE. Follow the next tutorial to learn how to install Thonny IDE, flash MicroPython firmware, and upload code to the board.
Parts Required
To follow the examples in this tutorial, you need the following parts:
You can use the preceding links or go directly to MakerAdvisor.com/tools to find all the parts for your projects at the best price!
Introducing MQTT
Already familiar with MQTT? Jump to the next section.
MQTT stands for Message Queuing Telemetry Transport. MQTT is a simple messaging protocol designed for constrained devices with low bandwidth. So, it’s the perfect solution to exchange data between multiple IoT devices. MQTT communication works as a publish and subscribe system. Devices can publish messages on a specific topic. All devices that are subscribed to that topic receive the message.
Its main applications include sending messages to control outputs, reading and publishing data from sensor nodes, and much more.
MQTT Basic Concepts
In MQTT, there are a few basic concepts that you need to understand:
- Publish/Subscribe
- Messages
- Topics
- Broker
Publish/Subscribe
The first concept is the publish and subscribe system. In a publish and subscribe system, a device can publish a message on a topic or be subscribed to a particular topic to receive messages.
- For example, Device 1 publishes on a topic;
- Device 2 is subscribed to the same topic that Device 1 is publishing in;
- So, Device 2 receives the message.
MQTT Messages
Messages are the information that you want to exchange between your devices. It can be a message like a command to control an output or data like sensor readings.
Topics
Another important concept is the topics. Topics are the way you register interest in incoming messages or how you specify where you want to publish the message.
Topics are represented with strings separated by a forward slash. Each forward slash indicates a topic level. Here’s an example of how you would create a topic for a lamp in your home office:
Note: topics are case-sensitive, which makes the following topics different.
If you would like to turn on a lamp in your home office using MQTT you can imagine the following scenario:
- A device publishes on and off messages on the home/office/lamp topic.
- You have a device that controls a lamp (it can be your Raspberry Pi Pico, or any other board or device). The Pico, that controls your lamp, is subscribed to that same topic: home/office/lamp.
- So, when a new message is published on that topic, the Pico receives the on or off messages and turns the lamp on or off.
The device that is publishing the messages can be another microcontroller board, or a Home Automation controller platform with MQTT support like Node-RED, Home Assistant, Adafruit IO, Domoticz, or OpenHAB, for example.
Broker
Finally, another important concept is the broker.
The MQTT broker is responsible for receiving all messages, filtering the messages, deciding who is interested in them, and then publishing the message to all subscribed clients.
There are several brokers you can use. For example:
- Cloud MQTT Broker solutions: you can use commercial MQTT broker solutions like HiveMQ, for example. You don’t need to set up anything. You just need to create an account and you’re ready to go (this is the one we’ll use in this tutorial).
- Local MQTT broker: you can install an MQTT broker locally on your computer or on your Raspberry Pi. The Mosquitto MQTT broker hosted on a Raspberry Pi is widely used in many hobbyist projects and it’s also the solution we use more often.
- Cloud MQTT Broker: as an alternative to the previous solution, you can also install MQTT broker on your own cloud server.
In summary:
- MQTT is a communication protocol very useful in Internet of Things projects;
- In MQTT, devices can publish messages on specific topics and can be subscribed to topics to receive messages;
- You need a broker when using MQTT. It receives all the messages and sends them to the subscribed devices.
Set Up the MQTT Broker
To use MQTT, you need an MQTT broker. The broker receives all MQTT messages and sends them to all subscribed clients.
MQTT Broker Solutions
There are many MQTT broker solutions you can use. Here we’ll describe the ones we’re more familiar with:
- Mosquitto MQTT broker installed on a Raspberry Pi: this is an open-source MQTT broker that you can install locally on your Raspberry Pi (the Raspberry Pi computer, not the Pico board). We’ve been using this option a lot and it always worked well for us.
- Mosquitto MQTT broker installed on a cloud server: a great alternative if you want your broker to be accessible worldwide.
- HiveMQ Broker: this is a cloud MQTT broker service. You just need to create an account and choose a plan. They provide a free plan that is suitable for most IoT hobbyist projects.
For simplicity, in this guide we’ll use HiveMQ because you don’t need to install or configure anything like in the Mosquitto MQTT broker. You just need to create an account, set up a cluster and you’re ready to go. Alternatively, if you want to use Mosquitto broker or any other broker of your choice, don’t worry. The code will be compatible with any broker as long as you fill in the right broker details.
Regardless of the MQTT broker you use, you need to have the MQTT URL, username, and password before proceeding to the following sections.
Setting Up the HiveMQ MQTT Broker
In this section, we’ll show you how to set up your HiveMQ MQTT broker.
1) First, you need to create an account. Go to hivemq.com and click on Start free.
2) Choose the HiveMQ Cloud plan.
3) Login or create a new account and fill in the details to complete your profile.
4) You should have a new cluster created by default. Click on Manage Cluster.
5) Copy the Cluster URL to a safe place because you’ll need it later.
6) Click on the Access Management tab at the top.
7) Fill in the form with a username and password. You’ll need to remember these details later to connect to the MQTT broker. Set the permission to Publish and Subscribe.
8) Finally, click Create Credential.
If your credentials are successfully created, your MQTT broker is set up.
Make sure you have the following information before proceeding to the next section:
- MQTT Server:
- Cluster URL (for HiveMQ)
- MQTT broker IP address or URL (if you’re using a different MQTT Broker)
- MQTT username
- MQTT password
Installing MQTT MicroPython Modules
To write code in MicroPython to use the MQTT communication protocol, we’ll use two MQTT modules: umqtt.simply.py, and umqtt.robust.py.
Follow the next steps to upload the modules to your Raspberry Pi Pico.
With the Raspberry Pi Pico connected to your computer and with a connection established with Thonny IDE, go to View > Files.
A new sidebar will show up with all the files on the Raspberry Pi Pico filesystem.
Right-click on the Raspberry Pi Pico sidebar and click on New directory…
This new directory should be called umqtt. Click Ok.
The new directory will show up on the left sidebar.
Right-click on the umqtt folder and select New file…
That new file should be called simple.py.
Copy the simple.py code into that new file. The code can be found on the link below:
# forked from: https://github.com/micropython/micropython-lib/tree/master/micropython/umqtt.simple
import usocket as socket
import ustruct as struct
from ubinascii import hexlify
class MQTTException(Exception):
pass
class MQTTClient:
def __init__(
self,
client_id,
server,
port=0,
user=None,
password=None,
keepalive=0,
ssl=False,
ssl_params={},
):
if port == 0:
port = 8883 if ssl else 1883
self.client_id = client_id
self.sock = None
self.server = server
self.port = port
self.ssl = ssl
self.ssl_params = ssl_params
self.pid = 0
self.cb = None
self.user = user
self.pswd = password
self.keepalive = keepalive
self.lw_topic = None
self.lw_msg = None
self.lw_qos = 0
self.lw_retain = False
def _send_str(self, s):
self.sock.write(struct.pack("!H", len(s)))
self.sock.write(s)
def _recv_len(self):
n = 0
sh = 0
while 1:
b = self.sock.read(1)[0]
n |= (b & 0x7F) << sh
if not b & 0x80:
return n
sh += 7
def set_callback(self, f):
self.cb = f
def set_last_will(self, topic, msg, retain=False, qos=0):
assert 0 <= qos <= 2
assert topic
self.lw_topic = topic
self.lw_msg = msg
self.lw_qos = qos
self.lw_retain = retain
def connect(self, clean_session=True):
self.sock = socket.socket()
addr = socket.getaddrinfo(self.server, self.port)[0][-1]
self.sock.connect(addr)
if self.ssl:
import ssl
self.sock = ssl.wrap_socket(self.sock, **self.ssl_params)
premsg = bytearray(b"\x10\0\0\0\0\0")
msg = bytearray(b"\x04MQTT\x04\x02\0\0")
sz = 10 + 2 + len(self.client_id)
msg[6] = clean_session << 1
if self.user is not None:
sz += 2 + len(self.user) + 2 + len(self.pswd)
msg[6] |= 0xC0
if self.keepalive:
assert self.keepalive < 65536
msg[7] |= self.keepalive >> 8
msg[8] |= self.keepalive & 0x00FF
if self.lw_topic:
sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)
msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3
msg[6] |= self.lw_retain << 5
i = 1
while sz > 0x7F:
premsg[i] = (sz & 0x7F) | 0x80
sz >>= 7
i += 1
premsg[i] = sz
self.sock.write(premsg, i + 2)
self.sock.write(msg)
# print(hex(len(msg)), hexlify(msg, ":"))
self._send_str(self.client_id)
if self.lw_topic:
self._send_str(self.lw_topic)
self._send_str(self.lw_msg)
if self.user is not None:
self._send_str(self.user)
self._send_str(self.pswd)
resp = self.sock.read(4)
assert resp[0] == 0x20 and resp[1] == 0x02
if resp[3] != 0:
raise MQTTException(resp[3])
return resp[2] & 1
def disconnect(self):
self.sock.write(b"\xe0\0")
self.sock.close()
def ping(self):
self.sock.write(b"\xc0\0")
def publish(self, topic, msg, retain=False, qos=0):
pkt = bytearray(b"\x30\0\0\0")
pkt[0] |= qos << 1 | retain
sz = 2 + len(topic) + len(msg)
if qos > 0:
sz += 2
assert sz < 2097152
i = 1
while sz > 0x7F:
pkt[i] = (sz & 0x7F) | 0x80
sz >>= 7
i += 1
pkt[i] = sz
# print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt, i + 1)
self._send_str(topic)
if qos > 0:
self.pid += 1
pid = self.pid
struct.pack_into("!H", pkt, 0, pid)
self.sock.write(pkt, 2)
self.sock.write(msg)
if qos == 1:
while 1:
op = self.wait_msg()
if op == 0x40:
sz = self.sock.read(1)
assert sz == b"\x02"
rcv_pid = self.sock.read(2)
rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]
if pid == rcv_pid:
return
elif qos == 2:
assert 0
def subscribe(self, topic, qos=0):
assert self.cb is not None, "Subscribe callback is not set"
pkt = bytearray(b"\x82\0\0\0")
self.pid += 1
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
# print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt)
self._send_str(topic)
self.sock.write(qos.to_bytes(1, "little"))
while 1:
op = self.wait_msg()
if op == 0x90:
resp = self.sock.read(4)
# print(resp)
assert resp[1] == pkt[2] and resp[2] == pkt[3]
if resp[3] == 0x80:
raise MQTTException(resp[3])
return
# Wait for a single incoming MQTT message and process it.
# Subscribed messages are delivered to a callback previously
# set by .set_callback() method. Other (internal) MQTT
# messages processed internally.
def wait_msg(self):
res = self.sock.read(1)
self.sock.setblocking(True)
if res is None:
return None
if res == b"":
raise OSError(-1)
if res == b"\xd0": # PINGRESP
sz = self.sock.read(1)[0]
assert sz == 0
return None
op = res[0]
if op & 0xF0 != 0x30:
return op
sz = self._recv_len()
topic_len = self.sock.read(2)
topic_len = (topic_len[0] << 8) | topic_len[1]
topic = self.sock.read(topic_len)
sz -= topic_len + 2
if op & 6:
pid = self.sock.read(2)
pid = pid[0] << 8 | pid[1]
sz -= 2
msg = self.sock.read(sz)
self.cb(topic, msg)
if op & 6 == 2:
pkt = bytearray(b"\x40\x02\0\0")
struct.pack_into("!H", pkt, 2, pid)
self.sock.write(pkt)
elif op & 6 == 4:
assert 0
return op
# Checks whether a pending message from server is available.
# If not, returns immediately with None. Otherwise, does
# the same processing as wait_msg.
def check_msg(self):
self.sock.setblocking(False)
return self.wait_msg()
After copying the code to the simple.py file, save the code.
Now, if you expand the umqtt folder, you’ll see that the simple.py file is there.
Right-click again on the umqtt folder and create another file by clicking on New file…
This new file should be called robust.py.
Copy the robust.py code into that new file. The code can be found on the link below:
# forked from: https://github.com/micropython/micropython-lib/tree/master/micropython/umqtt.robust
import utime
from . import simple
class MQTTClient(simple.MQTTClient):
DELAY = 2
DEBUG = False
def delay(self, i):
utime.sleep(self.DELAY)
def log(self, in_reconnect, e):
if self.DEBUG:
if in_reconnect:
print("mqtt reconnect: %r" % e)
else:
print("mqtt: %r" % e)
def reconnect(self):
i = 0
while 1:
try:
return super().connect(False)
except OSError as e:
self.log(True, e)
i += 1
self.delay(i)
def publish(self, topic, msg, retain=False, qos=0):
while 1:
try:
return super().publish(topic, msg, retain, qos)
except OSError as e:
self.log(False, e)
self.reconnect()
def wait_msg(self):
while 1:
try:
return super().wait_msg()
except OSError as e:
self.log(False, e)
self.reconnect()
def check_msg(self, attempts=2):
while attempts:
self.sock.setblocking(False)
try:
return super().wait_msg()
except OSError as e:
self.log(False, e)
self.reconnect()
attempts -= 1
After copying the code to the robust.py file, save the code. At this moment, you should have the umqtt folder with the simple.py and robust.py files inside.
The modules required for MQTT were successfully uploaded to the Raspberry Pi Pico.
Creating a Configuration File
We’ll create a configuration file to save the SSID, password, and your MQTT broker details: URL, username, and password.
Create a new file called config.py on Thonny IDE and copy the following code:
wifi_ssid = 'REPLACE_WITH_YOUR_SSID'
wifi_password = 'REPLACE_WITH_YOUR_PASSWORD'
mqtt_server = b'MQTT_BROKER_URL'
mqtt_username = b'BROKER_USERNAME'
mqtt_password = b'BROKER_PASSWORD'
Replace the variables with your own details.
If you’re using a local Mosquitto MQTT broker, you should pass the broker IP address without the port. For example:
mqtt_server = b'192.168.1.79'
Then, go to File > Save as… and select Raspberry Pi Pico. Save the file as config.py (overwrite any existing files with the same name). This file should be saved on the root of the Raspberry Pi Pico and not inside the umqtt folder.
Publishing MQTT Messages
In this example, you’ll learn how to publish MQTT messages on a certain topic with your Raspberry Pi Pico. As an example, we’ll publish temperature, humidity, and pressure readings from a BME280 sensor. Alternatively, you can use any other sensor or random values to test the project and concepts.
Before proceeding, make sure that:
- You connect a BME280 sensor to the Raspberry Pi Pico. Use GPIO 4 (SDA) and GPIO 5 (SCL);
- You must upload the BME280.py module to control the BME280 with your Raspberry Pi Pico — check this tutorial and install the library as indicated there.
Related content: Raspberry Pi Pico: BME280 Get Temperature, Humidity, and Pressure (MicroPython)
The following code gets sensor data from the BME280 sensor and publishes the readings on different MQTT topics.
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-w-mqtt-micropython/
from machine import Pin, I2C
from time import sleep
import network
from umqtt.simple import MQTTClient
import config
import BME280
# Constants for MQTT Topics
MQTT_TOPIC_TEMPERATURE = 'pico/temperature'
MQTT_TOPIC_PRESSURE = 'pico/pressure'
MQTT_TOPIC_HUMIDITY = 'pico/humidity'
# MQTT Parameters
MQTT_SERVER = config.mqtt_server
MQTT_PORT = 0
MQTT_USER = config.mqtt_username
MQTT_PASSWORD = config.mqtt_password
MQTT_CLIENT_ID = b"raspberrypi_picow"
MQTT_KEEPALIVE = 7200
MQTT_SSL = True # set to False if using local Mosquitto MQTT broker
MQTT_SSL_PARAMS = {'server_hostname': MQTT_SERVER}
# Initialize I2C communication
i2c = I2C(id=0, scl=Pin(5), sda=Pin(4), freq=10000)
# Initialize BME280 sensor
bme = BME280.BME280(i2c=i2c, addr=0x76)
def get_sensor_readings():
temp = bme.temperature[:-1]
hum = bme.humidity[:-1]
pres = bme.pressure[:-3]
return temp, hum, pres
def initialize_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# Connect to the network
wlan.connect(ssid, password)
# Wait for Wi-Fi connection
connection_timeout = 10
while connection_timeout > 0:
if wlan.status() >= 3:
break
connection_timeout -= 1
print('Waiting for Wi-Fi connection...')
sleep(1)
# Check if connection is successful
if wlan.status() != 3:
return False
else:
print('Connection successful!')
network_info = wlan.ifconfig()
print('IP address:', network_info[0])
return True
def connect_mqtt():
try:
client = MQTTClient(client_id=MQTT_CLIENT_ID,
server=MQTT_SERVER,
port=MQTT_PORT,
user=MQTT_USER,
password=MQTT_PASSWORD,
keepalive=MQTT_KEEPALIVE,
ssl=MQTT_SSL,
ssl_params=MQTT_SSL_PARAMS)
client.connect()
return client
except Exception as e:
print('Error connecting to MQTT:', e)
raise # Re-raise the exception to see the full traceback
def publish_mqtt(topic, value):
client.publish(topic, value)
print(topic)
print(value)
print("Publish Done")
try:
if not initialize_wifi(config.wifi_ssid, config.wifi_password):
print('Error connecting to the network... exiting program')
else:
# Connect to MQTT broker, start MQTT client
client = connect_mqtt()
while True:
# Read sensor data
temperature, humidity, pressure = get_sensor_readings()
# Publish as MQTT payload
publish_mqtt(MQTT_TOPIC_TEMPERATURE, str(temperature))
publish_mqtt(MQTT_TOPIC_PRESSURE, str(pressure))
publish_mqtt(MQTT_TOPIC_HUMIDITY, str(humidity))
# Delay 10 seconds
sleep(10)
except Exception as e:
print('Error:', e)
How the Code Works
We use the following MQTT topics to publish data:
- For the temperature — pico/temperature
- For the humidity — pico/humidity
- For the pressure — pico/pressure
And the workflow to publish data is the following:
- Connect the Pico to the internet;
- Connect to the MQTT broker;
- After connecting to the broker, we can continuously publish MQTT messages.
Let’s take a look at how the code works.
Importing Libraries
First, we need to import the required libraries. We import the Pin and I2C from the machine module, and the BME280 to interface with the BME280 sensor. The network module to connect to Wi-Fi and the MQTTClient class from umqtt.simple to use MQTT functions.
from machine import Pin, I2C
from time import sleep
import network
from umqtt.simple import MQTTClient
import config
import BME280
MQTT Topics
On the following variables we save the topics where we want to publish our messages (sensor readings).
# Constants for MQTT Topics
MQTT_TOPIC_TEMPERATURE = 'pico/temperature'
MQTT_TOPIC_PRESSURE = 'pico/pressure'
MQTT_TOPIC_HUMIDITY = 'pico/humidity'
MQTT Details
In the following lines we set up the MQTT parameters to connect to our MQTT broker. We import the server URL, username, and password from the config.py file.
# MQTT Parameters
MQTT_SERVER = config.mqtt_server
MQTT_PORT = 0
MQTT_USER = config.mqtt_username
MQTT_PASSWORD = config.mqtt_password
MQTT_CLIENT_ID = b"raspberrypi_picow"
MQTT_KEEPALIVE = 7200
MQTT_SSL = True
MQTT_SSL_PARAMS = {'server_hostname': MQTT_SERVER}
The MQTT_CLIENT_ID should be a unique ID to identify the MQTT client. You can give it wherever name you want, but it needs to be unique among the MQTT clients connected to your broker. In our case, it’s raspberrypi_picow.
MQTT_CLIENT_ID = b"raspberrypi_picow"
If you’re using a local Mosquitto MQTT broker, you should set the MQTT_SSL parameter to False.
MQTT_SSL = False
BME280 Sensor
In the following lines, we initialize the BME280 sensor and create a function called get_sensor_readings() that gets data from the BME280 and returns the temperature, humidity, and pressure.
# Initialize I2C communication
i2c = I2C(id=0, scl=Pin(5), sda=Pin(4), freq=10000)
# Initialize BME280 sensor
bme = BME280.BME280(i2c=i2c, addr=0x76)
def get_sensor_readings():
temp = bme.temperature[:-1]
hum = bme.humidity[:-1]
pres = bme.pressure[:-3]
return temp, hum, pres
Initialize Wi-Fi
The initialize_wifi() function connects the Raspberry Pi Pico to a network. You need to initialize Wi-Fi to connect to the MQTT broker and exchange messages.
def initialize_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# Connect to the network
wlan.connect(ssid, password)
# Wait for Wi-Fi connection
connection_timeout = 10
while connection_timeout > 0:
if wlan.status() >= 3:
break
connection_timeout -= 1
print('Waiting for Wi-Fi connection...')
sleep(1)
# Check if connection is successful
if wlan.status() != 3:
return False
else:
print('Connection successful!')
network_info = wlan.ifconfig()
print('IP address:', network_info[0])
return True
You may also like: Raspberry Pi Pico: Web Server (MicroPython)
Connect to MQTT
The connect_mqtt() function connects to the MQTT broker using the details about the MQTT broker you’ve set up previously.
def connect_mqtt():
try:
client = MQTTClient(client_id=MQTT_CLIENT_ID,
server=MQTT_SERVER,
port=MQTT_PORT,
user=MQTT_USER,
password=MQTT_PASSWORD,
keepalive=MQTT_KEEPALIVE,
ssl=MQTT_SSL,
ssl_params=MQTT_SSL_PARAMS)
client.connect()
return client
except Exception as e:
print('Error connecting to MQTT:', e)
raise # Re-raise the exception to see the full traceback
Publish MQTT Messages
The publish_mqtt() function publishes a message on a topic. Pass as argument the topic and the message you want to send.
def publish_mqtt(topic, value):
client.publish(topic, value)
print(topic)
print(value)
print("Publish Done")
Publishing Sensor Readings
Now that we have all functions and variables defined, we can finally connect to the internet and to the broker to start publishing messages.
First, we try to connect to Wi-Fi using the SSID and password stored on the config.py file.
try:
if not initialize_wifi(config.wifi_ssid, config.wifi_password):
print('Error connecting to the network... exiting program')
If we succeed in connecting to Wi-Fi, we can connect to the MQTT broker.
else:
# Connect to MQTT broker, start MQTT client
client = connect_mqtt()
After connecting, we get new sensor data and save it on the temperature, humidity, and pressure variables.
# Read sensor data
temperature, humidity, pressure = get_sensor_readings()
Finally, we use the publish_mqtt() function to publish the readings on their specific topics. The message must be a string. So, we need to convert the sensor data using the str() function.
# Publish as MQTT payload
publish_mqtt(MQTT_TOPIC_TEMPERATURE, str(temperature))
publish_mqtt(MQTT_TOPIC_PRESSURE, str(pressure))
publish_mqtt(MQTT_TOPIC_HUMIDITY, str(humidity))
We publish new readings every 10 seconds.
sleep(10)
Testing the Code
Run the previous code on your Raspberry Pi Pico. It will connect to the internet and start publishing messages every 10 seconds.
Now, we can check if we can receive the messages on an MQTT Client subscribed to those topics. HiveMQ provides a Web Client interface that allows you to subscribe and publish to topics for testing purposes.
Go to your HiveMQ cluster, and click on the Web Client tab. Insert your MQTT broker username and password and click Connect Client.
Subscribe to the topics that the Raspberry Pi Pico is publishing to. Fill in pico/temperature and then click on +Subscribe.
Repeat the process for pico/humidity and pico/pressure.
After subscribing to those topics, scroll down to the bottom of the page. You should start receiving the Raspberry Pi Pico MQTT messages.
And that’s it. You successfully published MQTT messages with the Raspberry Pi Pico. Now, you can use any other MQTT Client to subscribe to those messages and receive the data. For example, having Node-RED nodes or Adafruit IO widgets subscribed to MQTT topics and displaying the data on charts and gauges.
You can also have any other microcontroller subscribed to those topics to receive the data—it can be another Raspberry Pi Pico, an ESP32, an ESP8266, or another board.
Subscribe to MQTT Topics
To show you how to subscribe to MQTT topics using the Raspberry Pi Pico we’ll create a simple example, in which the Pico is subscribed to the pico/led topic. Then, with the Web Client from HiveMQ, we’ll publish ON and OFF messages on that topic. The Pico will receive the messages and will control an LED accordingly.
Here’s the workflow to subscribe to MQTT topics.
- Connect the Raspberry Pi Pico to the internet;
- Connect to the MQTT broker;
- Subscribe to the MQTT topic;
- Create and assign a callback function that will run when a message is received;
- Create a loop that is constantly checking for new MQTT messages.
The following code subscribes to the pico/led topic and controls an LED according to the received message.
# Rui Santos & Sara Santos - Random Nerd Tutorials
# Complete project details at https://RandomNerdTutorials.com/raspberry-pi-pico-w-mqtt-micropython/
from machine import Pin
from time import sleep
import network
from umqtt.simple import MQTTClient
import config
# Define LED
led = Pin('LED', Pin.OUT)
# Constants for MQTT Topics
MQTT_TOPIC_LED = 'pico/led'
# MQTT Parameters
MQTT_SERVER = config.mqtt_server
MQTT_PORT = 0
MQTT_USER = config.mqtt_username
MQTT_PASSWORD = config.mqtt_password
MQTT_CLIENT_ID = b'raspberrypi_picow'
MQTT_KEEPALIVE = 7200
MQTT_SSL = True # set to False if using local Mosquitto MQTT broker
MQTT_SSL_PARAMS = {'server_hostname': MQTT_SERVER}
# Init Wi-Fi Interface
def initialize_wifi(ssid, password):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# Connect to the network
wlan.connect(ssid, password)
# Wait for Wi-Fi connection
connection_timeout = 10
while connection_timeout > 0:
if wlan.status() >= 3:
break
connection_timeout -= 1
print('Waiting for Wi-Fi connection...')
sleep(1)
# Check if connection is successful
if wlan.status() != 3:
return False
else:
print('Connection successful!')
network_info = wlan.ifconfig()
print('IP address:', network_info[0])
return True
# Connect to MQTT Broker
def connect_mqtt():
try:
client = MQTTClient(client_id=MQTT_CLIENT_ID,
server=MQTT_SERVER,
port=MQTT_PORT,
user=MQTT_USER,
password=MQTT_PASSWORD,
keepalive=MQTT_KEEPALIVE,
ssl=MQTT_SSL,
ssl_params=MQTT_SSL_PARAMS)
client.connect()
return client
except Exception as e:
print('Error connecting to MQTT:', e)
# Subcribe to MQTT topics
def subscribe(client, topic):
client.subscribe(topic)
print('Subscribe to topic:', topic)
# Callback function that runs when you receive a message on subscribed topic
def my_callback(topic, message):
# Perform desired actions based on the subscribed topic and response
print('Received message on topic:', topic)
print('Response:', message)
# Check the content of the received message
if message == b'ON':
print('Turning LED ON')
led.value(1) # Turn LED ON
elif message == b'OFF':
print('Turning LED OFF')
led.value(0) # Turn LED OFF
else:
print('Unknown command')
try:
# Initialize Wi-Fi
if not initialize_wifi(config.wifi_ssid, config.wifi_password):
print('Error connecting to the network... exiting program')
else:
# Connect to MQTT broker, start MQTT client
client = connect_mqtt()
client.set_callback(my_callback)
subscribe(client, MQTT_TOPIC_LED)
# Continuously checking for messages
while True:
sleep(5)
client.check_msg()
print('Loop running')
except Exception as e:
print('Error:', e)
Let’s take a quick look at the relevant sections of code for this example.
If you’re using a local Mosquitto MQTT broker, you should set the MQTT_SSL parameter to False.
MQTT_SSL = False
Subscribe to MQTT Topics
We create a function called subscribe() that accepts as arguments the MQTT client and the topic we want to subscribe to.
def subscribe(client, topic):
client.subscribe(topic)
print('Subscribe to topic:', topic)
Callback Function
We need to create a callback function that will run when a new message is received on a topic we are subscribed to. The topic and message arguments are automatically passed to the function when it is called.
def my_callback(topic, message):
# Perform desired actions based on the subscribed topic and response
print('Received message on topic:', topic)
print('Response:', message)
# Check the content of the received message
if message == b'ON':
print('Turning LED ON')
led.value(1) # Turn LED ON
elif message == b'OFF':
print('Turning LED OFF')
led.value(0) # Turn LED OFF
else:
print('Unknown command')
In this function, we check the content of the message. If it is ON, we’ll turn the Raspberry Pi Pico built-in LED ON.
if message == b'ON':
print('Turning LED ON')
led.value(1) # Turn LED ON
If the message is OFF, it will turn the LED off.
elif message == b'OFF':
print('Turning LED OFF')
led.value(0) # Turn LED OFF
If we receive any other messages, we print Unknown command.
else:
print('Unknown command')
Connecting to Wi-Fi, MQTT Broker and Checking Messages
To subscribe to the MQTT broker and constantly check for incoming messages, first we need to connect to the internet.
The following lines try to connect to the internet:
try:
# Initialize Wi-Fi
if not initialize_wifi(config.wifi_ssid, config.wifi_password):
print('Error connecting to the network... exiting program')
If we succeed, we also connect to the MQTT broker.
client = connect_mqtt()
Then, assign the callback function by using the set_callback() and passing as argument the callback function we created previously my_callback.
client.set_callback(my_callback)
Finally, we can subscribe to MQTT topics. In this case, we’re just subscribing to the MQTT_TOPIC_LED, but you can subscribe to multiple topics.
subscribe(client, MQTT_TOPIC_LED)
Then, create a while loop to constantly check for incoming messages using the check_msg() method.
while True:
sleep(5)
client.check_msg()
print('Loop running')
You can also add other tasks to the loop. We check for new messages every five seconds, but you can use a smaller or longer delay time depending on how often you’re expecting to receive messages.
Testing the Code
Run the previous code on your Raspberry Pi Pico. It will connect to the internet and subscribe to the MQTT topic.
Now, let’s publish some messages on the pico/led topic to control the LED using HiveMQ Web Client.
Go to your HiveMQ cluster Web Client. Insert your MQTT broker username and password and click Connect Client.
Scroll down the page to the Publish Message section.
Insert pico/led on the Topic Name field, and type ON in the Message field.
Finally, press the Publish button.
Your Raspberry Pi Pico will receive the message, and will turn the on-board LED on.
Go back to HiveMQ Client and send an OFF message.
The Raspberry Pi Pico will receive the message and turn off the LED.
And that’s it. You successfully subscribed to an MQTT topic and executed a different task according to the received message. Now, instead of HiveMQ Web Client, you can use any Home Automation or IoT platform with MQTT support that allows you to build a web interface with buttons or switches to send MQTT messages.
Wrapping Up
In this guide, you’ve learned all the essential concepts to start using MQTT with the Raspberry Pi Pico. We’ve set up an MQTT broker and published and subscribed to MQTT topics with the Pico.
We hope you’ve found this tutorial useful.
Learn more about the Raspberry Pi Pico with our eBook:
We have other guides that you may also like:
- Raspberry Pi Pico: Web Server (MicroPython)
- Raspberry Pi Pico: SSD1306 OLED Display (MicroPython)
- Raspberry Pi Pico and Pico W Pinout Guide: GPIOs Explained
- More Raspberry Pi Pico Tutorials and Guides
If you want to use MQTT with the ESP32 or ESP8266 you can follow the next tutorials:
- MicroPython – Getting Started with MQTT on ESP32/ESP8266
- MicroPython: MQTT – Publish BME280 Sensor Readings (ESP32/ESP8266)
- ESP32 MQTT – Publish and Subscribe with Arduino IDE
- ESP32 MQTT – Publish BME280 Sensor Readings (Arduino IDE)
- ESP8266 NodeMCU MQTT – Publish BME280 Sensor Readings (Arduino IDE)
Thanks for reading.
Hi,
If I may suggest to use mqtt_as. It’s a robust code and it’s well maintained.
github.com/peterhinch/micropython-mqtt/tree/master.
Best regards.
Hi.
Thanks for sharing.
I didn’t know this one.
Regards,
Sara
This is an excellent tutorial. I have used MQTT before to connect sensors and send data back to my Mosquito broker on a Raspberry pi, but used C++ code and ESP8266/32 devices. Using Python looks interesting as I want to learn Python as well. Great work!
That’s great.
I’m glad you find this useful.
Regards,
Sara
could you please guide me to connect this to node-red?
Thanks a lot, for all the explanations, really well done and easy to follow and to understand!
I appreciated your job (you took time to do it !) and I succeed my first test with MQTT
to be noticed : The ussl library doesn’t exist anymore but by changing “ussl” by “ssl” in simple.py file (2 times) that works !
Thanks again
Hi.
Thanks for pointing that out.
With the most recent version of MicroPython firmware, you need to use ssl instead of ussl.
We updated the files now.
Regards,
Sara