Ensure your secrets.py file should at the very least have values for the fields ssid
, password
, timezone
, aio_username
, and aio_key
. Make sure to copy it over to CIRCUITPY as well.
To use with CircuitPython, you need to first install a few 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, open the directory FunHouse_IOT_Hub/iot_hub/ and then click on the directory that matches the version of CircuitPython you're using and copy the contents of that directory to your CIRCUITPY drive.
Your CIRCUITPY

# SPDX-FileCopyrightText: 2021 Eva Herrada for Adafruit Industries # SPDX-License-Identifier: MIT import time import ssl import displayio import board from digitalio import DigitalInOut, Direction, Pull from adafruit_display_text.label import Label import terminalio import touchio import socketpool import wifi import adafruit_minimqtt.adafruit_minimqtt as MQTT from adafruit_io.adafruit_io import IO_MQTT from adafruit_dash_display import Hub # Set up navigation buttons up = DigitalInOut(board.BUTTON_UP) up.direction = Direction.INPUT up.pull = Pull.DOWN select = DigitalInOut(board.BUTTON_SELECT) select.direction = Direction.INPUT select.pull = Pull.DOWN down = DigitalInOut(board.BUTTON_DOWN) down.direction = Direction.INPUT down.pull = Pull.DOWN back = touchio.TouchIn(board.CAP7) submit = touchio.TouchIn(board.CAP8) # Check for secrets.py. Note: for this project, your secrets.py needs an adafruit io api key as # well as the wifi information try: from secrets import secrets except ImportError: print("WiFi secrets are kept in secrets.py, please add them there!") raise # Make the rgb group for setting rgb hex values for NeoPixels rgb_group = displayio.Group() R_label = Label( terminalio.FONT, text=" +\nR:\n -", color=0xFFFFFF, anchor_point=(0, 0.5), anchored_position=(5, 120), scale=2, ) G_label = Label( terminalio.FONT, text=" +\nG:\n -", color=0xFFFFFF, anchor_point=(0, 0.5), anchored_position=(90, 120), scale=2, ) B_label = Label( terminalio.FONT, text=" +\nB:\n -", color=0xFFFFFF, anchor_point=(0, 0.5), anchored_position=(175, 120), scale=2, ) rgb_group.append(R_label) rgb_group.append(G_label) rgb_group.append(B_label) R = Label( terminalio.FONT, text="00", color=0xFFFFFF, anchor_point=(0, 0.5), anchored_position=(35, 120), scale=2, ) G = Label( terminalio.FONT, text="00", color=0xFFFFFF, anchor_point=(0, 0.5), anchored_position=(120, 120), scale=2, ) B = Label( terminalio.FONT, text="00", color=0xFFFFFF, anchor_point=(0, 0.5), anchored_position=(205, 120), scale=2, ) rgb_group.append(R) rgb_group.append(G) rgb_group.append(B) # Set up callbacks # pylint: disable=unused-argument def rgb(last): """ Function for when the rgb screen is active """ display.show(None) rgb_group[3].text = "00" rgb_group[4].text = "00" rgb_group[5].text = "00" display.show(rgb_group) time.sleep(0.2) index = 0 colors = [00, 00, 00] while True: if select.value: index += 1 if index == 3: index = 0 time.sleep(0.3) continue if up.value: colors[index] += 1 if colors[index] == 256: colors[index] = 0 rgb_group[index + 3].text = hex(colors[index])[2:] time.sleep(0.01) continue if down.value: colors[index] -= 1 if colors[index] == -1: colors[index] = 255 rgb_group[index + 3].text = hex(colors[index])[2:] time.sleep(0.01) continue if submit.value: color = ["{:02x}".format(colors[i]) for i in range(len(colors))] color = "#" + "".join(color) iot.publish("neopixel", color) break if back.value: break time.sleep(0.1) display.show(None) time.sleep(0.1) def rgb_set_color(message): """ Sets the color of the rgb label based on the value of the feed """ return int(message[1:], 16) def door_color(message): """ Sets the color of the door label based on the value of the feed """ door = bool(int(message)) if door: return int(0x00FF00) return int(0xFF0000) def on_door(client, feed_id, message): """ Sets the door text based on the value of the feed """ door = bool(int(message)) if door: return "Door: Closed" return "Door: Open" def pub_lamp(lamp): if isinstance(lamp, str): lamp = eval(lamp) # pylint: disable=eval-used iot.publish("lamp", str(not lamp)) # funhouse.set_text(f"Lamp: {not lamp}", 0) time.sleep(0.3) display = board.DISPLAY # Set your Adafruit IO Username and Key in secrets.py # (visit io.adafruit.com if you need to create an account, # or if you need your Adafruit IO key.) aio_username = secrets["aio_username"] aio_key = secrets["aio_key"] print("Connecting to %s" % secrets["ssid"]) wifi.radio.connect(secrets["ssid"], secrets["password"]) print("Connected to %s!" % secrets["ssid"]) # Create a socket pool pool = socketpool.SocketPool(wifi.radio) # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", username=secrets["aio_username"], password=secrets["aio_key"], socket_pool=pool, ssl_context=ssl.create_default_context(), ) # Initialize an Adafruit IO MQTT Client io = IO_MQTT(mqtt_client) iot = Hub(display=display, io=io, nav=(up, select, down, back, submit)) iot.add_device( feed_key="lamp", default_text="Lamp: ", formatted_text="Lamp: {}", pub_method=pub_lamp, ) iot.add_device( feed_key="temperature", default_text="Temperature: ", formatted_text="Temperature: {:.1f} C", ) iot.add_device( feed_key="humidity", default_text="Humidity: ", formatted_text="Humidity: {:.2f}%" ) iot.add_device( feed_key="neopixel", default_text="LED: ", formatted_text="LED: {}", color_callback=rgb_set_color, pub_method=rgb, ) iot.add_device( feed_key="battery", default_text="Battery: ", formatted_text="Battery: {}%", ) iot.add_device( feed_key="door", default_text="Door: ", formatted_text="Door: {}", color_callback=door_color, callback=on_door, ) iot.get() while True: iot.loop() time.sleep(0.01)
Customizing the Devices
Lines 204-236 in code.py are where I add all the devices. It's good to note that while I do call them devices, they're just Adafruit IO feeds with a few functions that make it easier to handle the data how we want to.
If you'd like to add your own device, it's good to know what the parameters are:
- feed_key - The key of the Adafruit IO feed you want to use. This can't be left blank.
- default_text - The text to set to the display before a value has been gotten. You can leave this blank and it should be fine.
- formatted_text - The text in a way that can be formatted using curly braces (ex. "Lamp: {}". If you want a specific number of decimal points to be displayed put :.1f in the curly braces, replacing 1 with the precision you want. If you leave this blank it won't display any text unless you have a custom callback function that returns the formatted text you want.
- color_callback - The function you want to be called whenever the device gets a new value to set the color of the text for that device. You can see two examples of this on line 150 and 154 of code.py. You can leave this blank.
- callback - The callback you want to run after the device gets a new message. This can do a number of things like turn on the FunHouse's built in dotstars or play a sound. There's a function on line 161 that shows how you could use a callback to set the text in a slightly more complicated way. If left blank, this defaults to a built-in callback that just uses formatted_text to set the text.
- pub_method - The function you want to call when the select button is pressed. Only 2 devices in code.py have one of these. If you look at line 168 you can see an example of a simple one that just toggles the lamp, but if you look at line 102 you can see a much more complicated one that displays a whole new screen and ui.
Code Behavior
The code should show 6 lines with the various feeds. To navigate use the three buttons left of the display. The upper button moves the cursor up, the middle button will let you publish a new value to the feed if that is enabled (in my example it's only enabled for the lamp and neopixel feed).
If you wanted to turn the lamp on, you'd press the middle button and it will turn on pretty quickly.
If you want to change the color of the NeoPixels, navigate down to it with the third button then select it with the middle button. From there it will take you to a screen where you can edit the hex values for the red, green, and blue components of the NeoPixels. Use the up and down button to increase or decrease them and use the select button to switch between the colors. When you're done, you can submit it with the Capacitive Touch 8 button on the upper right of the screen. If you decide that you don't want to submit it, press the Capacitive Touch 7 button on the upper left of the screen and it will take you back to the home screen without submitting the value you set.