HiveMQ Cloud, part 3 - Sending sensor data from Raspberry Pi Pico to HiveMQ Cloud

This post has been written on request of HiveMQ and was originally published on the HiveMQ Blog.

In the previous two posts in this series, we used Java on the Raspberry Pi mini-computer to send sensor data to HiveMQ Cloud, and visualize it on a dashboard.

Now we are going to add some more data to our messaging system with another member of the Raspberry Pi family: the Pico.

About the Raspberry Pi Pico

In January 2021 the Raspberry Pi Pico was introduced. This is a complete new type of board as it’snot a full Linux PC, but a microcontroller chip (RP2040) developed by Raspberry Pi itself, on a small and versatile board. This RP2040 features a dual-core Arm Cortex-M0+ processor with 264KB internal RAM and support for up to 16MB of off-chip Flash, combined with a wide range of GPIOs (supporting I2C, SPI, and Programmable I/O (PIO)). So it’s comparable to an Arduino or similar microcontroller board. But the biggest surprise of this Pico: the price of only 4$!

The Raspberry Pi Foundation made sure a very extensive documentation site was available when the board was launched. Programming can be done with a C/C++ and MicroPython SDK.

The Pico provides a lof of GPIOs which are grouped very nicely by separating them with a ground connection. These grounds even have a different shape on the board (no rounded corners), to make it easier to find the correct pin you want to use.

Raspberry Pi Pico pinout diagram

Pico project

For this post we will extend the Pico with a WiFi module and one distance sensor, as an example how you can easily send sensor data to HiveMQ Cloud from this inexpensive board. To achieve this very low price, the Pico doesn’t contain wireless functions. Luckily there are different possibilities to add WiFi to the Pico, of which the Adafruit AirLift ESP32 WiFi Co-Processor Breakout Board is probably the easiest and cheapest at 9.95$. An extra advantage of the Adafruit products is the big amount of documentation they provide on their website. Most of these examples use a different “flavor” of MicroPython, called CircuitPython, which is based on the same Python implementation, but more focused on beginners, education, and getting started tutorials.

The project in this post is a combination of different examples from Adafruit:

Prepare the Pico for CircuitPython

Let’s start with preparing our Pico for this tutorial. We need to connect the components, flash CircuitPython on the Pico, add libraries, and upload our code.


Take a breadboard and some wires to create this small test setup.

Breadboard wiring with Raspberry Pi Pico, Adafruit AirLift and distance sensor

Adafruit AirLift WiFi

The AirLift is the WiFi module which will handle all the communication between the Pico and HiveMQ Cloud. We need 8 breadboard wires to make the connection between both components. By using the pins 10 till 15 we group all the GPIO connections on one side.

Important remark on the Adafruit website: You MUST use the Pico’s VSYS pin for powering the AirLift Breakout.

Pico AirLift
GP13 (SPI1 CSn) CS

Distance sensor

The third component on the breadboard is a HC-SR04 distance sensor, similar to the one in the CrowPi. Here we need 4 wires and for the GPIOs we use the other side of the Pico.

Pico HC-SR04

CircuitPython on the Pico

For our Pico to support this example CircuitPython project, we need to load the correct firmware and add some libraries.


Download the firmware which needs to be installed on the Pico to be able to use it as a CircuitPython device. This .uf2-file for the Raspberry Pi Pico can be downloaded from

Use a USB cable (which is not charge-only), press and hold the BOOTSEL button on the Pico, and connect the cable between the Pico and computer. Wait until you see a new USB drive “RPI-RP2” appearing on your PC to release the BOOTSEL button.

Drag or copy the downloaded .uf2-file to the “RPI-RP2”-drive. When done, this drive will disappear as the Pico reboots, and reappear as a drive called “CIRCUITPY”. Now your Pico is ready to program with CircuitPython.


To simplify the use of components, a whole set of libraries is available as one download on Download the ZIP-file, extract it on your PC and copy the directories or files from the following list to a directory “libs” on the “CIRCUITPY”-drive.

Libraries and files on the Pico for this example application


The code-files can be written directly to the Pico with any text editor or IDE. Adafruit advises to use the Mu editor as this allows to both write the code and see the application output in one tool. You can download this tool

Install the application on your PC, run it and select Mode > CircuitPython.

Mu editor with a view for both code and output of the board


The sources of this application are available on GitHub in the same repository where you can find the sources of the previous two posts.


To separate the generic code from your specific WiFi and HiveMQ Cloud credentials, a separate file is used. Create a file and save it to the Pico with following content, using your login, password, etc.

secrets = {
   'ssid' : 'WIFI_NETWORK_NAME',
   'password' : 'WIFI_PASSWORD',
   'timezone' : 'Europe/Brussels',
   'mqtt_username' : 'HIVEMQ_USERNAME',
   'mqtt_key' : 'HIVEMQ_PASSWORD',
   'broker' : '',
   'port' : 8883

Main code

Below you find the full code for this project. I tried to explain every step by adding comments and prints. Create a new file in Mu, copy this code and save it to the Pico as

import time
import board
import busio
import adafruit_hcsr04
import adafruit_requests as requests
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
import adafruit_minimqtt.adafruit_minimqtt as MQTT

from digitalio import DigitalInOut
from adafruit_esp32spi import adafruit_esp32spi

# Load the WiFi and HiveMQ Cloud credentials from
    from secrets import secrets
except ImportError:
    print("Error, secrets could not be read")

# MQTT Topic to publish data from Pico to HiveMQ Cloud
topic_name = "pico/distance"

# Initialize the Pico pins, WiFi module and distance sensor
esp32_cs = DigitalInOut(board.GP13)
esp32_ready = DigitalInOut(board.GP14)
esp32_reset = DigitalInOut(board.GP15)
spi = busio.SPI(board.GP10, board.GP11, board.GP12)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
hcsr04 = adafruit_hcsr04.HCSR04(trigger_pin=board.GP17, echo_pin=board.GP16)

# Handle HTTP requests
requests.set_socket(socket, esp)

# Check ESP32 status
print("Checking ESP32")
if esp.status == adafruit_esp32spi.WL_IDLE_STATUS:
    print("\tESP32 found and in idle mode")
print("\tFirmware version: ", esp.firmware_version)
print("\tMAC address: ", [hex(i) for i in esp.MAC_address])

# List the detected WiFi networks
print("Discovered WiFi networks:")
for ap in esp.scan_networks():
    print("\t", (str(ap["ssid"], "utf-8")), "\t\tRSSI: ", ap["rssi"])

# Connect to the configured WiFi network
print("Connecting to WiFi: ", secrets["ssid"])
while not esp.is_connected:
        esp.connect_AP(secrets["ssid"], secrets["password"])
    except RuntimeError as e:
        print("\tCould not connect to WiFi: ", e)
print("\tConnected to ", str(esp.ssid, "utf-8"), "\t\tRSSI:", esp.rssi)
print("\tIP address of this board: ", esp.pretty_ip(esp.ip_address))
print("\tPing " + str("")) + "ms")

# Configure MQTT to use the ESP32 interface
MQTT.set_socket(socket, esp)

# Configure MQTT client (uses secure connection by default)
mqtt_client = MQTT.MQTT(

# Define callback methods and assign them to the MQTT events
def connected(client, userdata, flags, rc):
    print("\tConnected to MQTT broker: ",

def disconnected(client, userdata, rc):
    print("\tDisconnected from MQTT broker!")

def publish(mqtt_client, userdata, topic, pid):
    print("\tPublished a message to: ", topic)

mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_publish = publish

# Connect to the MQTT broker
print("Connecting to MQTT broker...")
except Exception as e:
    print("\tMQTT connect failed: ", e)

# Continuously measure the distance and send the value to HiveMQ
print("Starting the distance measurement")
killed = False
while not killed:
    # Measure distance
    distance = 0
        distance = hcsr04.distance
    except Exception as e:
        print("Distance measurement failure\n", e)

    # Send to HiveMQ Cloud
        json = "{\"value\": " + str(distance) + "}"
        print("\tMessage for queue: " + json)
        mqtt_client.publish(topic_name, json)
    except Exception as e:
        print("\tMQTT publish Failed, retrying\n", e)
        killed = True

    # Sleep a second

Because is the default filename for the main code, this file will be executed directly, or you can soft-reset the board with CTRL+D in the terminal of Mu.

Program output

In the terminal of Mu, the print-output is shown.

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable. output:
Checking ESP32
	ESP32 found and in idle mode
	Firmware version:  bytearray(b'1.2.2\x00')
	MAC address:  ['0x50', '0x18', '0x49', '0x95', '0xab', '0x34']
Discovered WiFi networks:
	 *****1 		RSSI:  -73
	 *****2 		RSSI:  -79
Connecting to WiFi:  *****1
	Connected to  *****1 		RSSI: -71
	IP address of this board:
	Ping 20ms
Connecting to MQTT broker...
	Connected to MQTT broker:  ***
Starting the distance measurement
	Message for queue: {"value": 106.777}
	Published a message to:  pico/distance
	Message for queue: {"value": 106.352}
	Published a message to:  pico/distance
	Message for queue: {"value": 107.202}

Adding the data to our JavaFX dashboard

With a few small changes, we can now add the data of the Pico messages to our JavaFX application we created in the previous post. The only file which needs to be modified is

Code changes

First we add a new variable:

private final Tile gaucheDistancePico;

Inside the constructor we initialize the tile similar to the existing ones, and define a subscription to the topic where the Pico publishes its distance measurements.

gaucheDistancePico = TileBuilder.create()
    .title("Distance Pico")


One last additional method is needed to parse the received data and update the tile:

public void handlePicoData(Mqtt5Publish message) {
    var sensorData = new String(message.getPayloadAsBytes());"Pico distance data: {}", sensorData);
    try {
        var sensor = mapper.readValue(sensorData, DoubleValue.class);
    } catch (JsonProcessingException ex) {
        logger.error("Could not parse the data to JSON: {}", ex.getMessage());

Extended layout

With these small modifications, we now will see the data of both the CrowPi and the Pico in one dashboard.

Screenshot with additional gauche tile


The Raspberry Pi Pico is a very versatile device for a very low price. With the additional Adafruit WiFi module you can easily add wireless communication. In the meantime, already many new boards based on this same RP2040 microcontroller are available and some of them even have WiFi on-board. A nice overview can be found on

HiveMQ Cloud is a great (and free up till 100 devices!) way to experiment with messaging. When combining this with Java, Raspberry Pi, and electronic components, exchanging data between different applications and devices becomes very easy.

I hope these three posts can help you to get started to create your own project!