Sending data over MQTT

Sending data over MQTT#

MQTT (Message Queuing Telemetry Transport) is a protocol that is widely used to send messages from sensors to be logged. We will demonstrate how to connect a Pico to a MQTT broker.

Requirements

  1. A Pico

  2. A Wifi adapator (we are using a Pico W which has built in Wifi)

Set-up#

Since the Wifi module is built in - we don’t need to worry about wiring anything to the Pico W.

The only step we need to first take is to create a settings.toml file in the CIRCUITPY drive. This is a type of text file which will hold all our sensitive network information separate to the main code.py file.

The information that we will hold here is your WiFi’s SSID (its name) and password, as well as your Raspberry Pi’s IP address.

WIFI_SSID = "___"         # Fill in with your WiFi network's name 
WIFI_PASSWORD = "___"     # Fill in with your WiFi network's password 
IP_ADDRESS = "___"        # Fill in with your Raspberry Pi's password 
MQTT_PORT = ___              # Fill in the port you are connecting over
MQTT_USERNAME = ""          # User name for connecting to MQTT Broker
MQTT_KEY = ""               # Password to connect to MQTT Broker
BROKER = ""                 # URL to connect to MQTT Broker

Warning

Remember this information is stored in plain text and so can be read by anyone with access to the Pico

There may be other information you want to include here like the port or other URL extensions.

Note

Make sure to keep the speech marks when putting your own network details into the settings.toml. This ensures that CircuitPython recognises the variables as strings. The port number is best left as an integer

Code set-up#

Now we can program our Pico to connect to WiFi and send data to a MQTT broker

Below is an example for sending temperature and time data to a broker.

Importing libraries#

Several libraries are required

  1. adafruit_requests

  2. adafruit_connection_manager

  3. adafruit_minimqtt

  4. adafruit_ticks

all four are in the circuitpython library package

a fifth useful library is adafruit_logging which can be helpful to diagnose connection problems

import os
import microcontroller
import adafruit_connection_manager
import wifi
import adafruit_requests
import time
import adafruit_minimqtt.adafruit_minimqtt as MQTT
import adafruit_logging as logging
import json


#Retrieve variables from settings.toml
inatorname = os.getenv("INATORNAME")
ssid = os.getenv("WIFI_SSID")
password = os.getenv("WIFI_PASSWORD")
ip = os.getenv('IP_ADDRESS')
#port=os.getenv('PORT')

wifi_con = False

# Initalize Wifi, Socket Pool, Request Session
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
requests = adafruit_requests.Session(pool, ssl_context)

# Connect to the Wi-Fi network
print(f"\nConnecting to {ssid} network...")
try:
    wifi.radio.connect(ssid, password)
    wifi_con = True
except OSError as e:
    print(f"❌ OSError: {e}")
    wifi_con = False

if wifi_con:
    print("✅ Wifi!\n")
    print("IP-Adress is", wifi.radio.ipv4_address)

    # MQTT Topic to publish data from Pico to HiveMQ Cloud
    mqtt_topic = "/datalog/TEM1"

    # Define callback methods which are called when events occur
    def connect(mqtt_client, userdata, flags, rc):
        # This function will be called when the mqtt_client is connected
        # successfully to the broker.
        print("Connected to MQTT Broker!")
        print(f"Flags: {flags}\n RC: {rc}")

    def disconnect(mqtt_client, userdata, rc):
        # This method is called when the mqtt_client disconnects
        # from the broker.
        print("Disconnected from MQTT Broker!")

    def subscribe(mqtt_client, userdata, topic, granted_qos):
        # This method is called when the mqtt_client subscribes to a new feed.
        print(f"Subscribed to {topic} with QOS level {granted_qos}")

    def unsubscribe(mqtt_client, userdata, topic, pid):
        # This method is called when the mqtt_client unsubscribes from a feed.
        print(f"Unsubscribed from {topic} with PID {pid}")


    def publish(mqtt_client, userdata, topic, pid):
        # This method is called when the mqtt_client publishes data to a feed.
        print(f"Published to {topic} with PID {pid}")

    def message(client, topic, message):
        print(f"New message on topic {topic}: {message}")

    #Set up the MQTT client
    mqtt_client = MQTT.MQTT(
                broker=os.getenv('BROKER'),
                port=os.getenv('PORT'),
                username=os.getenv('MQTT_USERNAME'),
                password=os.getenv('MQTT_KEY'),
                socket_pool=pool,
                is_ssl = True,
                keep_alive = 3600,
                ssl_context = ssl_context
                )
    #Set up logging if having connection difficulties
    #mqtt_client.logger = logging.getLogger('test')
    #mqtt_client.logger.setLevel(logging.DEBUG)

    # Connect callback handlers to mqtt_client
    mqtt_client.on_connect = connect
    mqtt_client.on_disconnect = disconnect
    mqtt_client.on_subscribe = subscribe
    mqtt_client.on_unsubscribe = unsubscribe
    mqtt_client.on_publish = publish
    mqtt_client.on_message = message

    print(f"Attempting to connect to {mqtt_client.broker}:{mqtt_client.port}")
    mqtt_client.connect()

    while True:
        temp = microcontroller.cpu.temperature
        timetrial = time.monotonic()
        #Create dictionary
        json_dict = {"inator":inatorname,"cpu_temp":temp,"time":timetrial}  # Send data with JSON syntax
        json_data = json.dumps(json_dict)
        json_byte = ("{"+f"inator:{inatorname},cpu_temp:{temp},time:{timetrial}"+"}")
        print(f" | ✅ Sending JSON ('key':'value'): {json_data}")
        mqtt_client.publish(mqtt_topic,str(json_data))
        print(f"| ✅ Sent")
        time.sleep(60)