First, the code makes all of the required imports, this may seem like a lot, but most of them are just for making the connection to Adafruit IO.
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
First the code looks up your WIFI credentials and AIO username and tokenĀ from the settings.toml file using os.getenv(). If any of those values are missing the code raises an exception because they are all required.
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
ssid = getenv("CIRCUITPY_WIFI_SSID")
password = getenv("CIRCUITPY_WIFI_PASSWORD")
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
aio_key = getenv("ADAFRUIT_AIO_KEY")
if None in [ssid, password, aio_username, aio_key]:
raise RuntimeError(
"WiFi and Adafruit IO settings are kept in settings.toml, "
"please add them there. The settings file must contain "
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
)
Next, the navigation buttons are defined so they can be passed to the Dash Display library later.
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)
Now, the DisplayIO group that the NeoPixel setter will use is defined. It consists of 6 labels, 3 that are static and 3 that are changed by user input.
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)
Continuing what the code just did, the function that will use the DisplayIO group is defined. This function lets you input a hex value using the navigation buttons and then sends it to Adafruit IO.
# pylint: disable=unused-argument
def rgb(last):
""" Function for when the rgb screen is active """
display.root_group = displayio.CIRCUITPYTHON_TERMINAL
rgb_group[3].text = "00"
rgb_group[4].text = "00"
rgb_group[5].text = "00"
display.root_group = 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.root_group = displayio.CIRCUITPYTHON_TERMINAL
time.sleep(0.1)
The next two color callbacks are defined here. The first one just sets the text color to the value of the NeoPixel feed, which should always be an RGB hex string.
The second color callback sets the text color to red if the door is open and green if it is closed.
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)
Then, a callback for the door feed is defined. This callback sets the text to "Door: Open" if the value of the door feed is 'False' and thus open and "Door: Closed" if it is 'True' and thus closed.
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"
Next, the publish method for the lamp is defined. Basically it just publishes the opposite of whatever value was last sent from the lamp feed.
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)
After that, the code does all the Adafruit IO setup.
display = board.DISPLAY
print(f"Connecting to {ssid}")
wifi.radio.connect(ssid, password)
print(f"Connected to {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=aio_username,
password=aio_key,
socket_pool=pool,
ssl_context=ssl.create_default_context(),
)
# Initialize an Adafruit IO MQTT Client
io = IO_MQTT(mqtt_client)
The code now defines the Dash Display Hub object and passes it the display, the Adafruit IO object, and the navigation buttons.
iot = Hub(display=display, io=io, nav=(up, select, down, back, submit))
The code then adds all the devices to the Hub object so they will be displayed.
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()
Finally, the code calls theĀ Hub object's loop function which checks all the nav buttons and does things accordingly.
while True:
iot.loop()
time.sleep(0.01)
Page last edited March 25, 2025
Text editor powered by tinymce.