This guide was created on behalf of the Arm Software Developers team, follow us on Twitter: @ArmSoftwareDev and YouTube: Arm Software Developers for more resources!
IntroductionThis guide will cover how to use AWS IoT Core's message broker feature to securely transmit and receive messages to and from a Raspberry Pi Pico W board running MicroPython. AWS IoT Core enables devices to connect to the cloud securely and easily.
The Pico W board will use the MQTT protocol to connect to AWS IoT Core. MQTT is a message based publish-subscribe protocol, think of it as social media for IoT devices. Each device can subscribe to topics of interest to them, for example picow/button
, and then receive messages when another device publishes a message to a subscribed topic.
The example application in this guide will:
- Send the status of the button to the
picow/button
topic, when a button is pressed or released - Subscribe to the
picow/led
topic, messages received on this topic will control the Pico W's on-board LED (on, off, toggle)
The application is kept simple to illustrate the basics and can be used as a starting point to develop more complex applications.
HardwareThe Raspberry Pi Pico W board is based on the Raspberry Pi RP2040 microcontroller (MCU), which contains a dual-core Arm Cortex-M0+ processor. The board is also equipped with an Infineon CYW43439 chip that is used for 2.4 GHz Wi-Fi communications and contains a Arm Cortex-M3 processor.
Attach a button between the GND
pin and GP3
. Alternatively, if you are comfortable soldering, you can solder headers onto the Pico W board and use a breadboard for a more robust setup.
This section will walk through how to create a new "Thing" on AWS IoT Core that will represent the Raspberry Pi Pico W board.
1. Log into the AWS Console. If needed, create a new AWS account.
2. Search for "IoT Core" and then click on the IoT Core
entry in the services area:
3. In the AWS IoT console, click the Security
menu item on the left-hand side, followed by the Policy
sub-menu item. AWS IoT Core policies allow you to control access to what parts of AWS IoT your device can access.
4. Next click the Create policy
button to create a new policy for the Pico W board:
5. Enter a policy name, for example "picow-policy", and then add Allow
entries for the following policy actions as individual statements:
iot:Connect
iot:Publish
iot:Receive
iot:Subscribe
and a policy resource of *
.
Click the Create
button to create the policy.
Note: This policy will allow the Pico W board to connect to AWS IoT Core and publish and subscribe to messages on any topic. Please see the "AWS IoT Core policies" documentation to learn how to restrict which topics the board can access.
6. Click the All devices
menu item on the left hand side, followed by the Things
menu item. Then click the Create things
button to create a new thing to represent the board.
7. Enter a thing name, for example "picow", and then click the Next
button.
8. Select the Auto-generate a new certificate
option and then click the Next
button. AWS IoT will then generate a new certificate that the Pico W board will use for authentication when connecting to AWS IoT Core.
9. Select the policy you created earlier and then click the Create thing
button to create the new AWS IoT Core thing.
10. Download the device's generated certificate, public key, and private key, along with the Amazon Root CA 1
. These files will be transferred to the Pico W board in a later step. Click the Done
button once the files have been downloaded.
11. Click the Settings
menu item on the left-hand side, then take note of the Endpoint
value, this will be needed in a later step to configure that the MQTT endpoint the Pico W connects to.
This section covers how to set up MicroPython on the Pico W board, followed by how to download and install the Thonny IDE on your PC, which will be used to upload and run applications on the board.
Download and install MicroPython on the board
Download the Pico W MicroPython UF2 image from the MicroPython website: https://micropython.org/download/rp2-pico-w/ - at the time of writing the nightly builds were based on v1.9.1
.
While holding the white boot
button on the Pico W board, plug in a Micro USB B cable to the board and then plug the other end of the cable to your computer. If done correctly, a new RPI-RP2
boot volume will appear on your computer:
Next, copy the .uf2
MicroPython UF2 file you downloaded earlier to the RPI-RP2
boot volume. The board will then reset and start running MicroPython.
Download and install Thonny
The Thonny IDE will be used to upload code to the Raspberry Pico W board. Download and install the operating system (OS) specific version of Thonny from the Thonny home page for your computer. At the time of writing this guide Thonny 4.0.0
was the latest release.
Setup Thonny
Next, open the Thonny application and click the Local Python 3 ...
label on the bottom right-hand side of the window:
Then select MicroPython (Raspberry Pi Pico) ...
from the menu:
For more details on how to use Thonny and MicroPython with your Raspberry Pi Pico board, please see the Chapter 2 of the "Get Started with MicroPython on Raspberry Pi Pico" book from HackSpace.
Deploying the MicroPython applicationThis section will walk-through how-to setup the MicroPython application that will run on the Pico W board.
Install the MQTT client library using mip
The MicroPython firmware for the Pico W includes a copy of the mip
module which can be used to install MicroPython libraries when the board is connected to an internet connection via Wi-Fi.
Create a new file in Thonny with the following code:
import network
import mip
import time
# update with your Wi-Fi network's configuration
WIFI_SSID = "ssid"
WIFI_PASSWORD = "password"
wlan = network.WLAN(network.STA_IF)
print(f"Connecting to Wi-Fi SSID: {WIFI_SSID}")
wlan.active(True)
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
while not wlan.isconnected():
time.sleep(0.5)
print(f"Connected to Wi-Fi SSID: {WIFI_SSID}")
mip.install("https://raw.githubusercontent.com/micropython/micropython-lib/master/micropython/umqtt.simple/umqtt/simple.py")
The code above connects to the Wi-Fi network using the MicroPython network
module and WLAN class. Then it uses mip
to install the MicroPython umqtt.simple
module on the board's internal file system. This module contains an MQTT client, which will allow the board to connect to an MQTT broker.
Update the WIFI_SSID
and WIFI_PASSWORD
values to match your Wi-Fi configuration. Then click the Run current script
button in the Thonny IDE to run the code. If successful, the shell output section of the IDE will look like:
Uploading AWS IoT Core device key and certificate
Next, we can upload the AWS IoT Core device key and certificate files that were downloaded from the AWS Console in an earlier step.
In the Thonny IDE, click on View -> Files
- then in the top left section navigate to the folder where you previously saved the AWS IoT Core device key and certificate files. Select the files and right click Upload to /
menu item.
Now that the files are transferred over, the MicroPython application can access them via the internal filesystem. The information in the files will used when connecting to the AWS IoT Core MQTT endpoint using Transport Layer Security (TLS).
Configure and run the application code
Copy the code from the code section of this guide and paste it into a new tab in the Thonny IDE.
Update the Wi-Fi related values with your Wi-Fi network settings:
WIFI_SSID = "ssid"
WIFI_PASSWORD = "password"
Similarly, update MQTT client key and certificate values with the file names that were transferred to the board in an earlier step.
MQTT_CLIENT_KEY = "private.pem.key"
MQTT_CLIENT_CERT = "certificate.pem.crt"
Then update the, MQTT broker value with the AWS IoT Core endpoint from the settings section.
MQTT_BROKER = "xxxxxxxxxxxxxx-ats.iot.yy-yyyy-y.amazonaws.com"
TestingPress the Run current script
button in the Thonny IDE to run the MicroPython code. The board will then connect to your Wi-Fi network, sync time via NTP, and connect to AWS IoT Core using MQTT.
Go back to the AWS IoT section of the AWS Console and click the MQTT test client
menu item on the left-hand side. Enter "picow/button" in the topic filter, then expand the Additional configuration
section and select Display payloads as strings ...
in the MQTT payload display
section. Then click on the Subscribe
button.
Your web browser is now subscribed MQTT messages on the picow/button
topic. To test, press and release the button attached to the Pico W board. The Pico W will detect when the button state changes and then publish a message to the topic which can be seen in your browser:
The AWS IoT MQTT test client can also be used to publish messages to a specified MQTT topic. Click on the Publish to topic
tab and then enter "picow/led" as the Topic name
and "toggle" as the message payload
. When you click the Publish
button the Pico W board will receive the message and toggle the on-board LED.
You can also use "on" and "off" message payload
values to control the on-board LED.
Once the application is successfully running, you can use the Thonny IDE to save it to the board with a filename of main.py
. The MicroPython firmware on the Pico W will automatically run the code in main.py
when the device is powered on.
This section will highlight a few key areas of the MicroPython application.
Reading the private key and public certificate values
The private key and certificate files stored on the Pico W's internal filesystem are stored in Privacy-Enhanced Mail (PEM) format. A new function named read_pem(file)
is created at the start of the application. This function reads data from a PEM file and decodes the Base64 encoded data in the PEM file to a byte array using the MicroPython ubinascii.a2b_base64(data)
API.
This function will be used to read the data in the private key, public certificate, and root CA files:
key = read_pem(MQTT_CLIENT_KEY)
cert = read_pem(MQTT_CLIENT_CERT)
ca = read_pem(MQTT_BROKER_CA)
Connecting to the Wi-Fi network
The WLAN
class in the MicroPython network
module can be used to connect the board to the Wi-Fi network. To use it you must import the module:
import network
Then create a new WLAN
instance for the Wi-Fi station (STA) interface:
wlan = network.WLAN(network.STA_IF)
The interface can then be activated and connected to a given Wi-Fi SSID with a specified password:
wlan.active(True)
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
After the connection process has started, the wlan.isconnected()
API can be used to query if the network has connected successfully:
while not wlan.isconnected():
time.sleep(0.5)
Syncing time via NTP
The time on the board needs to be up-to-date for the board to validate the MQTT broker's TLS certificate. The MicroPython ntptime
module provides an easy mechanism to synchronize the time on the board using Network Protocol Time (NTP).
To use the module, add the following import
at the start of the application:
import ntptime
and then after the board has connected to the Wi-Fi network, call the ntptime.settime()
API:
ntptime.settime()
Connecting to the MQTT broker
The MQTTClient
class in the umqtt.simple
module will be used to connect to the AWS IoT Core MQTT broker.
It can be used by importing the module:
from simple import MQTTClient
and then creating an instance of the MQTTClient
with a specified client id and broker. As well as an optional keep alive interval and TLS/SSL parameters.
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_context.verify_mode = ssl.CERT_REQUIRED
ssl_context.load_cert_chain(cert, key)
ssl_context.load_verify_locations(cadata=ca)
mqtt_client = MQTTClient(
MQTT_CLIENT_ID,
MQTT_BROKER,
keepalive=60,
ssl=ssl_context,
)
The MQTTClient
class uses MicroPython's ssl
module for connections when ssl=ssl_context
is passed in as an argument. The ssl_context
was configured with the following:
key
- which contains the device's private key datacert
- which contains the device's public certificate dataverify_mode
- set tossl.CERT_REQUIRED
and enables validation of the server's TLS certificatecadata
- which contains the server's TLS Certificate Authority (CA) data
Finally, the mqtt_client.connect()
method is used to initiate the connection to the MQTT broker:
mqtt_client.connect()
Note: MicroPython's ssl
module implementation is backed by Arm's Mbed TLS library on the Pico W. The code is available on GitHub, if you are interested in learning more about the implementation.
Publishing messages
The example application monitors changes in button state on GP3
, to do so a machine.Pin(...) instance is created:
from machine import Pin
button = Pin(3, Pin.IN, Pin.PULL_UP)
Then the button.irq(...)
method is used to attach handler (function) to call when the pin changes state: 1 to 0 (falling) or 0 to 1 (rising):
button.irq(publish_mqtt_button_msg, Pin.IRQ_FALLING | Pin.IRQ_RISING)
The handler function, named publish_mqtt_button_msg(...)
will query the pin's current value using the button.value()
method and publish the associated string ("released" or "pressed") to the MQTT broker on the appropriate MQTT topic:
def publish_mqtt_button_msg(t):
msg_str = "released" if button.value() else "pressed"
mqtt_client.publish(MQTT_BUTTON_TOPIC, msg_str)
Subscribing and receiving messages
Before subscribing and monitoring messages, the example application creates a machine.Pin(...)
instance to control the on-board LED:
from machine import Pin
led = Pin("LED", Pin.OUT)
led.on()
Prior to connecting to the MQTT broker, a callback function named on_mqtt_msg(...)
is registered to handle incoming MQTT messages:
mqtt_client.set_callback(on_mqtt_msg)
Once connected, the mqtt_client.subscribe(...)
method is called with the MQTT topic name to subscribe to messages to.
mqtt_client.connect()
mqtt_client.subscribe(MQTT_LED_TOPIC)
The main application loop calls mqtt_client.check_msg()
which will process incoming MQTT messages:
while True:
mqtt_client.check_msg()
When an MQTT message is received on a subscribed topic, the callback function registered earlier is called. The callback function will convert the topic
and msg
arguments from bytes into strings, and then handles the message contents.
- The LED will be turned on if "on" is received
- The LED will be turned off if "off" is received
- The LED will be toggled if "toggle" is received
def on_mqtt_msg(topic, msg):
topic_str = topic.decode()
msg_str = msg.decode()
if topic_str is MQTT_LED_TOPIC:
if msg_str is "on":
led.on()
elif msg_str is "off":
led.off()
elif msg_str is "toggle":
led.toggle()
Keep-alive messages
Since the mqtt_client
was created with a keep-alive value, the application needs to routinely send MQTT ping messages to the broker.
A MicroPython machine.Timer instance is created to periodically call a function named send_mqtt_ping(...)
at a specified interval:
from machine import Timer
mqtt_ping_timer = Timer(
mode=Timer.PERIODIC,
period=mqtt_client.keepalive * 1000,
callback=send_mqtt_ping
)
The function is quite simple and calls mqtt_client.ping()
:
def send_mqtt_ping(t):
mqtt_client.ping()
ConclusionThis guide provided an introduction on how to connect the Arm Cortex-M0+ based Raspberry Pi Pico W board to AWS IoT Core using MicroPython and MQTT. It demonstrated how the board can:
1) Publish messages to a MQTT topic when a button is pressed or released.
2) Subscribe to messages on a specific MQTT topic, and process messages on the topic to control an on-board LED.
Arm's Mbed TLS library is used by MicroPython on the Pico W to securely connect to AWS IoT core.
You can extend the starter application in many ways including:
- Periodically sending up sensor data from the RP2040's internal temperature sensor or an external sensor
- Process messages in the cloud using Python in a Arm-based AWS Graviton 2 powered AWS Lambda function
Grab a Raspberry Pi Pico W board and try it out!
Additional Raspberry Pi RP2040 resourcesFor more tutorials using the Raspberry Pi RP2040, check out these projects below:
- Give a plant a personality using the Raspberry Pi Pico W
- Create a USB Microphone with the Raspberry Pi Pico
- See Sound in Real-Time Using Your Raspberry Pi Pico
- End-to-end tinyML audio classification with the Raspberry Pi RP2040
- Connect your Adafruit Feather RP2040 to The Things Network V3 using LoRaWAN
Join live workshops, on-demand masterclasses and lightening talks on the IoT at Arm DevSummit. Share your ideas and connect with Arm’s global technology community to optimize the performance, scalability and speed of your projects.
Comments