Adafruit IO gives you the option to disconnect your microcontroller from your computer and run it off of USB power or a battery, and still be able to see the data. It also allows you to send data to your microcontroller, such as NeoPixel colors. This example shows how to both send data to and receive data from Adafruit IO. It pulls from a "random" number generator and sends the "random" number to Adafruit IO, while simultaneously listening for NeoPixel color data from Adafruit IO.
The NeoPixel LED (highlighted in red), labeled Neo on the silk, is located in the center of the board, to the left of the ESP32-S3 processor.
Adafruit IO Feeds and Dashboard
The first thing you'll need to do, is head over to Adafruit IO and make sure your account is set up.
Then, you need to create two feeds called neopixel and random. These are case sensitive!
Next, you'll create a dashboard for the NeoPixel Color Picker. You can name the dashboard whatever you like.
Once the dashboard is created, you'll want to add a color picker block. The color picker block is highlighted by a red arrow in the image below.
Once you choose the color picker block, you'll need to connect a feed to it. Check the box next to neopixel.
Finally, a Block Settings page will come up. You can add an optional block title here. Then you press Create Block.
The dashboard should look something like the following.
Now that things are set up on the Adafruit IO end, you can continue on to the code on your microcontroller!
Adafruit IO settings.toml
This example requires you to provide your Wi-Fi credentials, and your Adafruit IO username and key. To do this, you'll want to create a settings.toml file on your CIRCUITPY drive.
To obtain your Adafruit IO key, follow the initial steps on this page.
Your settings.toml file should be structured in a certain way, and contain all the necessary information. Follow these instructions to create your settings.toml file.
Adafruit IO Example Code
To run this example, you need to first install the NeoPixel, Adafruit IO, and Adafruit MiniMQTT libraries into the lib folder on your CIRCUITPY drive. Then you need to update code.py with the example script.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the entire lib folder and the code.py file to your CIRCUITPY drive.
# SPDX-FileCopyrightText: 2021 Ladyada for Adafruit Industries # SPDX-FileCopyrightText: 2022 Kattni Rembor for Adafruit Industries # SPDX-License-Identifier: MIT import time import ssl import os from random import randint import microcontroller import socketpool import wifi import board import neopixel import adafruit_minimqtt.adafruit_minimqtt as MQTT from adafruit_io.adafruit_io import IO_MQTT # WiFi try: print("Connecting to %s" % os.getenv("CIRCUITPY_WIFI_SSID")) wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")) print("Connected to %s!" % os.getenv("CIRCUITPY_WIFI_SSID")) # Wi-Fi connectivity fails with error messages, not specific errors, so this except is broad. except Exception as e: # pylint: disable=broad-except print("Failed to connect to WiFi. Error:", e, "\nBoard will hard reset in 30 seconds.") time.sleep(30) microcontroller.reset() # Initialise NeoPixel pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.3) # Define callback functions which will be called when certain events happen. def connected(client): print("Connected to Adafruit IO! Listening for NeoPixel changes...") # Subscribe to Adafruit IO feed called "neopixel" client.subscribe("neopixel") def message(client, feed_id, payload): # pylint: disable=unused-argument print("Feed {0} received new value: {1}".format(feed_id, payload)) if feed_id == "neopixel": pixel.fill(int(payload[1:], 16)) # Create a socket pool pool = socketpool.SocketPool(wifi.radio) # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", username=os.getenv("ADAFRUIT_AIO_USERNAME"), password=os.getenv("ADAFRUIT_AIO_KEY"), socket_pool=pool, ssl_context=ssl.create_default_context(), ) # Initialize Adafruit IO MQTT "helper" io = IO_MQTT(mqtt_client) # Set up the callback methods above io.on_connect = connected io.on_message = message timestamp = 0 while True: try: # If Adafruit IO is not connected... if not io.is_connected: # Connect the client to the MQTT broker. print("Connecting to Adafruit IO...") io.connect() # Explicitly pump the message loop. io.loop() # Obtain the "random" value, print it and publish it to Adafruit IO every 10 seconds. if (time.monotonic() - timestamp) >= 10: random_number = "{}".format(randint(0, 255)) print("Current 'random' number: {}".format(random_number)) io.publish("random", random_number) timestamp = time.monotonic() # Adafruit IO fails with internal error types and WiFi fails with specific messages. # This except is broad to handle any possible failure. except Exception as e: # pylint: disable=broad-except print("Failed to get or send data, or connect. Error:", e, "\nBoard will hard reset in 30 seconds.") time.sleep(30) microcontroller.reset()
Your CIRCUITPY/lib folder should contain at least the following folders and files:
- adafruit_io/
- adafrruit_minimqtt/
- neopixel.mpy
If you like, you can connect to the serial console to see the connection info and current readings printed out.
NeoPixel Color Change
To change the color of the NeoPixel, go to the NeoPixel Adafruit IO dashboard you created at the beginning, and click on the colored circle in the ColorPicker block. It will bring up the following.
You can move the dot in the box around, and the slider line across the gradient to choose the perfect color. Choose a new color and click SAVE.
The NeoPixel color will update, and you will see the new value printed to the serial console, as shown below.
Code Walkthrough
This example contains three try
/except
blocks. These are included where the code is likely to fail due to WiFi or Adafruit IO connection failures. WiFi can be finicky, and without these code blocks, if the connection was lost, the code would crash. Instead, it is designed to reset the board and start the code over again to reestablish the connection, regardless of the cause. This ensures your code will continue running. The details of these blocks are explained below.
First you import all of the necessary modules and libraries.
import time import ssl import os from random import randint import socketpool import wifi import board import neopixel import adafruit_minimqtt.adafruit_minimqtt as MQTT from adafruit_io.adafruit_io import IO_MQTT
The WiFi attempts to connect, and prints the status to the serial console. If it connects successfully, the code continues onto the NeoPixel set up.
try: print("Connecting to %s" % os.getenv("CIRCUITPY_WIFI_SSID")) wifi.radio.connect(os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")) print("Connected to %s!" % os.getenv("CIRCUITPY_WIFI_SSID"))
If the WiFi connection is not successful, the error will be printed to the serial console, and the board will hard reset after 30 seconds.
except Exception as e: # pylint: disable=broad-except print("Failed to connect to WiFi. Error:", e, "\nBoard will hard reset in 30 seconds.") time.sleep(30) microcontroller.reset()
Once the WiFi successfully connects, the NeoPixel object is initiated.
pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.3)
Following that are two callback methods. For more details, check out this guide. The connected
method subscribes to the neopixel feed on Adafruit IO. The message
callback checks for updates to the neopixel feed, and turns the pixel the color from the feed.
def connected(client): print("Connected to Adafruit IO! Listening for NeoPixel changes...") # Subscribe to Adafruit IO feed called "neopixel" client.subscribe("neopixel") # pylint: disable=unused-argument def message(client, feed_id, payload): print("Feed {0} received new value: {1}".format(feed_id, payload)) if feed_id == "neopixel": pixel.fill(int(payload[1:], 16))
You create a socket pool, use that to initialise the new MQTT Client object, and use that to initialise the Adafruit IO MQTT "helper".
pool = socketpool.SocketPool(wifi.radio) mqtt_client = MQTT.MQTT( broker="io.adafruit.com", username=os.getenv("ADAFRUIT_AIO_USERNAME"), password=os.getenv("ADAFRUIT_AIO_KEY"), socket_pool=pool, ssl_context=ssl.create_default_context(), ) io = IO_MQTT(mqtt_client)
You set up the callback methods mentioned above.
io.on_connect = connected io.on_message = message
Next, you attempt to connect the client to the MQTT broker. If connection is successful, the code continues on to the timestamp
.
try: io.connect()
If the MQTT broker connection is not successful, the error is printed to the serial console, and the board will hard reset after 30 seconds.
except Exception as e: print("Failed to connect to Adafruit IO. Error:", e, "\nBoard will hard reset in 30 seconds.") time.sleep(30) microcontroller.reset()
Once the broker is connected, you set the timestamp
to 0
immediately before the loop.
timestamp = 0
Inside the loop, you attempt to do two things. You first explicitly poll the message loop. Check out this guide for more details on that.
while True: try: io.loop()
Second, you have a block of code that runs every 10 seconds. Inside, you obtain a "random" value between 0-255 inclusive, print it to the serial console, and publish it to an Adafruit IO feed. Finally, you reset timestamp so the block of code knows when another 10 seconds has passed, and runs again.
[...] if (time.monotonic() - timestamp) >= 10: random_number = "{}".format(randint(0, 255)) print("Current 'random' number: {}".format(random_number)) io.publish("random", random_number) timestamp = time.monotonic()
If at any time WiFi or Adafruit IO disconnects, the code will print the error to the serial console, and the board will hard reset after 30 seconds.
[...] except Exception as e: print("Failed to get or send data, or connect. Error:", e, "\nBoard will hard reset in 30 seconds.") time.sleep(30) microcontroller.reset()
That's all there is to using CircuitPython and Adafruit IO to send data to Adafruit IO, and receive data from it!
Text editor powered by tinymce.