Overview
Have you ever looked at your various Apple HomeKit devices and thought "if only I could monitor and control my devices in Adafruit IO"? Now you can with the help of the itsaSNAP app. You can use Apple Shortcuts with itsaSNAP to integrate your Apple HomeKit devices with Adafruit IO. You can go even further and use CircuitPython to display and control your devices with your Adafruit IO feeds.
You can setup a Shortcut to log your data from your sensor to Adafruit IO. This Shortcut can be paired with Automations to log the data over time.
After you create Scenes for your devices, you can use a Shortcut to change Scenes based on the value of an Adafruit IO feed with itsaSNAP.
For bonus points, you can use CircuitPython to display the sensor values and control your device Scenes with the press of a button.
Page last edited October 02, 2024
Text editor powered by tinymce.
Get Started with Adafruit IO
Adafruit IO is integrated with your adafruit.com account so you don't need to create yet another online account! You need an Adafruit account to use Adafruit IO because we want to make sure the data you upload is available to only you (unless you decide to publish your data).
I have an Adafruit.com Account already
If you already have an Adafruit account, then you already have access to Adafruit IO. It doesn't matter how you signed up, your account will make all three available.
To access Adafruit IO, simply visit https://io.adafruit.com to start streaming, logging, and interacting with your data.
Create an Adafruit Account (for Adafruit IO)
An Adafruit account makes Adafruit content and services available to you in one place. Your account provides access to the Adafruit shop, the Adafruit Learning System, and Adafruit IO. This means only one account, one username, and one password are necessary to engage with the content and services that Adafruit offers.
If you do not have an Adafruit account, signing up for a new Adafruit account only takes a couple of steps.
Begin by visiting https://accounts.adafruit.com.
Click the Sign Up button under the "Need An Adafruit Account?" title, below the Sign In section.
This will take you to the Sign Up page.
Fill in the requested information, and click the Create Account button.
This takes you to your Adafruit Account home page. From here, you can access all the features of your account.
You can also access the Adafruit content and services right from this page. Along the top of the page, you'll see a series of links beginning with "Shop". To access any of these, simply click the link.
For example, to begin working with Adafruit IO, click the IO link to the right of the rest of the links. This is the same for the other links as well.
That's all there is to creating a new Adafruit account, and navigating to Adafruit IO.
Page last edited October 02, 2024
Text editor powered by tinymce.
Download the ItsaSnap by Adafruit App
This section will guide you through downloading and installing the ItsaSnap by Adafruit app.
Download and Install ItsaSnap
To install and download ItsaSnap for your iOS device,
- Open the App Store.
- Tap on the "Search" icon at the bottom of the screen.
- Type "ItsaSnap by Adafruit" or "ItsaSnap" in the search bar and tap "Search".
- Locate the ItsaSnap app in the search results and tap on it
5. Tap the "Get" button to download and install the app on your device.
You may be prompted to enter your Apple ID password or use Face ID/Touch ID to confirm the installation
After you have downloaded and installed ItsaSnap, open the app.
You will need to enter your Adafruit username and Adafruit IO Key (which is different from your Adafruit account password).
Your Adafruit IO key is a long string of letters and numbers. To make it easier to add to the app, we've also included a QR code scanner that allows you to easily copy the Adafruit IO Key from the Adafruit IO website to the app.
On the ItaSnap app, the QR code scanner is located below the Adafruit IO Key and above the login button. To access it, press the 'Scan QR code for IO Key' button. This will open the QR code scanner.
To find the QR code for your Adafruit IO account, navigate go to the overview page. Once there, click the yellow button with a key in the center (it's next to the "New Device" button) to reveal your Adafruit IO Key.
After clicking it, a window with your information will appear. Then, find the QR code and scan it, and log in.
Page last edited October 02, 2024
Text editor powered by tinymce.
Logging Sensors to Adafruit IO with itsaSNAP
Once your sensors are setup in Apple HomeKit, you can use Shortcuts to send the data to Adafruit IO. The two sensors that will be used to demo this are the Eve Temperature and Humidity Sensor and the Eve Light and Occupancy Sensor. Both of these sensors are Matter sensors so they are easy to setup. You should be able to adapt these Shortcuts for whatever sensors you are using though.
To send data from a HomeKit sensor to itsaSNAP, you'll start with the Get the state of My Home action. You'll select your sensor to pass to the action. You'll use the itsaSNAP Send Value action to send the data to your feed.
Format the Data
Some sensor values include extraneous labels, like °C. As a result, the data sent to your Adafruit IO feed would be, for example, 23.57°C. You probably don't want those labels included if your goal is to log the value of a sensor. You can edit the value in the Shortcut to remove the label.
Start with a Get the state of My Home action and select your sensor. Next, use a Replace Text action. In the replace area, type in the text that you want to remove from the data. In this case, it was °C from the temperature reading. Don't include any text in the second part of the action and pass the result from the Get the state of My Home action as the text to modify. In the itsaSNAP Send Value action, you'll send the Updated Text to your feed.
Here is another example of removing a value label. In this Shortcut, the light level from a light sensor has the lx label removed to only send the numerical value to Adafruit IO.
Match and Replace Data
Another scenario may be that you want to send a specific value to a feed if a sensor returns a certain value. You can do this by using the Match Text action.
Start with the Get the state of My Home action and select your sensor. Next, use a Match Text action. Insert the value that you want to match from the returned value from the sensor. Then, you can use an If action to check if there was a match. The syntax for this in actions is if the result has any value. If you wanted to check that a match wasn't made, you would select does not have any value. Inside the If action, you'll use the itsaSNAP Send Value action to send your manual value to your feed.
In this example, the occupancy sensor being used returns Yes or No as a value. This response does not work well with an Adafruit IO dashboard for monitoring a true/false state. To change this value to a numerical value, a 2 is sent if a No is found, otherwise a 1 is sent for Yes. This allows an Indicator block to be used on a Dashboard for the feed from the sensor.
Adafruit IO Dashboard
Speaking of Dashboards, you can take all of this data and create a Dashboard to view the sensor values over time. You can use Automations to automate running the Shortcuts to log the data to Adafruit IO. If you want to log the data consistently throughout the day, you can follow the directions in this Playground Note to create a looping Shortcut with alarms.
Page last edited October 02, 2024
Text editor powered by tinymce.
Controlling Scenes with Adafruit IO and itsaSNAP
When you setup an output device in Apple HomeKit (lights, motorized blinds, etc) you can create Scenes that act as presets for the device. For example, you can have a scene that changes your RGB lights to green. When you create these Scenes, you can access them in Shortcuts and use itsaSNAP to access an Adafruit IO feed to select a Scene based on a value in the feed.
The device used for this demo is a Nanoleaf RGB lightstrip, but you should be able to adapt these Shortcuts for different devices.
When you view a Room in the Apple Home app, you'll see a section called Scenes where all of your preset Scenes are. If you aren't sure how to use Scenes, you can reference Apple's documentation for them.
For this Shortcut, you'll be receiving data from itsaSNAP rather than sending data to it. You'll start with the itsaSNAP Fetch Feed action to read the most recent data from your feed.
You'll use the Match Text action to check for a value from the incoming feed. Use an If action to check if the values match. If they do match, a Control My Home action is used to run a scene. In the demo, values of 0, 1 and 2 are used to set three different scenes for the RGB lightstrip.
Dashboard Control
You can use a Slider block on an Adafruit IO Dashboard to control the Scene control feed.
Point the block at the feed and set the minimum value to 0 and the maximum value to 2. Set the step size to 1. This gives you a 3 position switch to control your Scenes.
You will notice this is a little clunky though. You need to set the slider to a position on the Dashboard and then run the Shortcut on your iOS device to actually set the Scene. There is a way to automate this process though using Adafruit IO Actions and Shortcut Automations.
Hack the Automations
To add some automation to this process, you'll use Adafruit IO Actions. Actions let you create tasks similar to the Shortcuts you've been using in iOS to have feeds trigger a series of events. In this case, you'll send an SMS message anytime a new value is added to the feed you're monitoring.
The SMS messaging Action is only available for IO+ users. However, if you do not have an IO+ account you can setup the Action to use email instead.
Create an Action that uses a Reactive trigger. For the Feed, select your lightstrip feed. For Operator, select any. Leave the Feed or Value section blank. This alerts for any new value on the feed. For the Action select SMS (or Email). You can leave the body as the default entry. For ...using select the same lightstrip feed.
You can test this Action by going to your Dashboard and moving the Slider block. When you change the Slider value, you should receive a text.
If you don't want to be notified every time a text comes in, you can toggle Hide Alerts. This lets the process run in the background.
Now comes the hack! Head over to the Shortcuts app and create a new Automation. Select a Message automation if you have an SMS action setup. If you setup an email action, select Email.
Under Sender select the Adafruit IO number. Under Message Contains, enter the name of your feed since it will be in every text from the Action. Check off Run Immediately.
Now when you change the value on the Slider, the feed updates and sends a text to your iOS device. When the text is received, the Shortcut runs and you'll see your device change to the chosen Scene.
Page last edited October 02, 2024
Text editor powered by tinymce.
Install CircuitPython
CircuitPython is a derivative of MicroPython designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the CIRCUITPY drive to iterate.
CircuitPython Quickstart
Follow this step-by-step to quickly get CircuitPython running on your board.
Click the link above to download the latest CircuitPython UF2 file.
Save it wherever is convenient for you.
Plug your board into your computer, using a known-good data-sync cable, directly, or via an adapter if needed.
Double-click the reset button (highlighted in red above), and you will see the RGB status LED(s) turn green (highlighted in green above). If you see red, try another port, or if you're using an adapter or hub, try without the hub, or different adapter or hub.
For this board, tap reset and wait for the LED to turn purple, and as soon as it turns purple, tap reset again. The second tap needs to happen while the LED is still purple.
If double-clicking doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!
A lot of people end up using charge-only USB cables and it is very frustrating! Make sure you have a USB cable you know is good for data sync.
You will see a new disk drive appear called FTHRS3BOOT.
Drag the adafruit_circuitpython_etc.uf2 file to FTHRS3BOOT.
Page last edited October 02, 2024
Text editor powered by tinymce.
Create Your settings.toml File
CircuitPython works with WiFi-capable boards to enable you to make projects that have network connectivity. This means working with various passwords and API keys. As of CircuitPython 8, there is support for a settings.toml file. This is a file that is stored on your CIRCUITPY drive, that contains all of your secret network information, such as your SSID, SSID password and any API keys for IoT services. It is designed to separate your sensitive information from your code.py file so you are able to share your code without sharing your credentials.
CircuitPython previously used a secrets.py file for this purpose. The settings.toml file is quite similar.
CircuitPython settings.toml File
This section will provide a couple of examples of what your settings.toml file should look like, specifically for CircuitPython WiFi projects in general.
The most minimal settings.toml file must contain your WiFi SSID and password, as that is the minimum required to connect to WiFi. Copy this example, paste it into your settings.toml, and update:
your_wifi_ssidyour_wifi_password
CIRCUITPY_WIFI_SSID = "your_wifi_ssid" CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
Many CircuitPython network-connected projects on the Adafruit Learn System involve using Adafruit IO. For these projects, you must also include your Adafruit IO username and key. Copy the following example, paste it into your settings.toml file, and update:
your_wifi_ssidyour_wifi_passwordyour_aio_usernameyour_aio_key
CIRCUITPY_WIFI_SSID = "your_wifi_ssid" CIRCUITPY_WIFI_PASSWORD = "your_wifi_password" ADAFRUIT_AIO_USERNAME = "your_aio_username" ADAFRUIT_AIO_KEY = "your_aio_key"
Some projects use different variable names for the entries in the settings.toml file. For example, a project might use ADAFRUIT_AIO_ID in the place of ADAFRUIT_AIO_USERNAME. If you run into connectivity issues, one of the first things to check is that the names in the settings.toml file match the names in the code.
Here is an example settings.toml file.
# Comments are supported CIRCUITPY_WIFI_SSID = "guest wifi" CIRCUITPY_WIFI_PASSWORD = "guessable" CIRCUITPY_WEB_API_PORT = 80 CIRCUITPY_WEB_API_PASSWORD = "passw0rd" test_variable = "this is a test" thumbs_up = "\U0001f44d"
In a settings.toml file, it's important to keep these factors in mind:
- Strings are wrapped in double quotes; ex:
"your-string-here" - Integers are not quoted and may be written in decimal with optional sign (
+1,-1,1000) or hexadecimal (0xabcd).- Floats (decimal numbers), octal (
0o567) and binary (0b11011) are not supported.
- Floats (decimal numbers), octal (
- Use
\uescapes for weird characters,\xand\oooescapes are not available in .toml files- Example:
\U0001f44dfor 👍 (thumbs up emoji) and\u20acfor € (EUR sign)
- Example:
- Unicode emoji, and non-ASCII characters, stand for themselves as long as you're careful to save in "UTF-8 without BOM" format
When your settings.toml file is ready, you can save it in your text editor with the .toml extension.
In your code.py file, you'll need to import the os library to access the settings.toml file. Your settings are accessed with the os.getenv() function. You'll pass your settings entry to the function to import it into the code.py file.
import os
print(os.getenv("test_variable"))
In the upcoming CircuitPython WiFi examples, you'll see how the settings.toml file is used for connecting to your SSID and accessing your API keys.
Page last edited October 02, 2024
Text editor powered by tinymce.
Display with CircuitPython
You've setup Shortcuts to log your HomeKit sensors to Adafruit IO. You've setup a Shortcut to have an Adafruit IO feed switch between Scenes. You even setup a hack to use Adafruit IO Actions and Shortcut Automations to seamlessly control your Scenes from Adafruit IO. Surely its time to call it a day?
Before you go off and take a nap, there's one more skateboard trick for you to show off with. With all of this backend work, you can use a Feather ESP32-S3 Reverse TFT running CircuitPython to display the sensor data and switch between Scenes with the press of a physical button.
Once you've finished setting up your Feather with CircuitPython, you can access the code and necessary libraries by downloading the Project Bundle.
To do this, click on the Download Project Bundle button in the window below. It will download to your computer as a zipped folder.
# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import os
import ssl
import wifi
import socketpool
import microcontroller
import board
import digitalio
import displayio
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text import bitmap_label
from adafruit_display_shapes.circle import Circle
from adafruit_display_shapes.roundrect import RoundRect
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
import adafruit_minimqtt.adafruit_minimqtt as MQTT
aio_username = os.getenv("ADAFRUIT_AIO_USERNAME")
aio_key = os.getenv("ADAFRUIT_AIO_KEY")
# feeds!
temp_feed = aio_username + "/feeds/eve-temp" # temperature sensor
humid_feed = aio_username + "/feeds/eve-humid" # humidity sensor
lux_feed = aio_username + "/feeds/eve-light" # lux sensor
occupy_feed = aio_username + "/feeds/eve-occupy" # occupation sensor
light_feed = aio_username + "/feeds/nanoleaf" # lightstrip
# buttons
button0 = digitalio.DigitalInOut(board.D0)
button0.direction = digitalio.Direction.INPUT
button0.pull = digitalio.Pull.UP
button0_state = False
button1 = digitalio.DigitalInOut(board.D1)
button1.direction = digitalio.Direction.INPUT
button1.pull = digitalio.Pull.DOWN
button1_state = False
button2 = digitalio.DigitalInOut(board.D2)
button2.direction = digitalio.Direction.INPUT
button2.pull = digitalio.Pull.DOWN
button2_state = False
display = board.DISPLAY
group = displayio.Group()
display.root_group = group
# load background bitmap
bitmap = displayio.OnDiskBitmap("/tft_bg.bmp")
tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)
group = displayio.Group()
group.append(tile_grid)
# bitmap font
font_file = "/roundedHeavy-26.bdf"
font = bitmap_font.load_font(font_file)
# text elements
temp_text = bitmap_label.Label(font, text="00.0°C", x=55, y=70, color=0xFFFFFF)
group.append(temp_text)
humid_text = bitmap_label.Label(font, text="00.0%", x=120, y=70, color=0xFFFFFF)
group.append(humid_text)
lux_text = bitmap_label.Label(font, text="00 lx", x=190, y=70, color=0xFFFFFF)
group.append(lux_text)
occupy_text = bitmap_label.Label(font, text="Occupied?", x=128,
y=display.height - 12, color=0xFFFFFF)
group.append(occupy_text)
onOff_circ = Circle(display.width - 12, display.height - 12, 10, fill=0xcc0000)
group.append(onOff_circ)
scene_select = RoundRect(0, 0, 42, 40, 8, fill=None, outline=0xcccc00, stroke=6)
scene_y = [0, int(display.height / 2) - int(scene_select.height / 2),
display.height - scene_select.height - 1]
group.append(scene_select)
display.root_group = group
print()
print("Connecting to WiFi...")
# connect to your SSID
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
print("Connected to WiFi!")
# pylint: disable=unused-argument
# Define callback methods which are called when events occur
def connected(client, userdata, flags, rc): # pylint: disable=unused-argument
# This function will be called when the client is connected
# successfully to the broker.
print("Connected to Adafruit IO!")
# Subscribe to all changes on feeds
client.subscribe(temp_feed)
client.subscribe(humid_feed)
client.subscribe(lux_feed)
client.subscribe(occupy_feed)
client.subscribe(light_feed)
def disconnected(client, userdata, rc): # pylint: disable=unused-argument
# This method is called when the client is disconnected
print("Disconnected from Adafruit IO!")
def on_message(client, topic, msg): # pylint: disable=unused-argument
# This method is called when a topic the client is subscribed to
# has a new message.
print(f"New message on topic {topic}")
def on_temp_msg(client, topic, msg):
print(f"temp feed data: {msg}°C")
temp_text.text = f"{float(msg):.01f}°C"
def on_humid_msg(client, topic, msg):
print(f"humid feed data: {msg}%")
humid_text.text = f"{float(msg):.01f}%"
def on_lux_msg(client, topic, msg):
print(f"lux feed data: {msg} lx")
lux_text.text = f"{float(msg):.00f} lx"
def on_occupy_msg(client, topic, msg):
print(f"occupation feed data: {msg}")
if msg == "1":
onOff_circ.fill = 0x00cc00
else:
onOff_circ.fill = 0xcc0000
def on_light_msg(client, topic, msg):
print(f"light scene selected: {msg}")
scene_select.y = scene_y[int(msg)]
pool = socketpool.SocketPool(wifi.radio)
ssl_context = ssl.create_default_context()
# Initialize an Adafruit IO HTTP API object
mqtt_client = MQTT.MQTT(
broker="io.adafruit.com",
port=1883,
username=aio_username,
password=aio_key,
socket_pool=pool,
ssl_context=ssl_context,
)
# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = on_message
mqtt_client.add_topic_callback(temp_feed, on_temp_msg)
mqtt_client.add_topic_callback(humid_feed, on_humid_msg)
mqtt_client.add_topic_callback(lux_feed, on_lux_msg)
mqtt_client.add_topic_callback(occupy_feed, on_occupy_msg)
mqtt_client.add_topic_callback(light_feed, on_light_msg)
# Connect the client to the MQTT broker.
print("Connecting to Adafruit IO...")
mqtt_client.connect()
clock_clock = ticks_ms()
clock_timer = 5 * 1000
while True:
try:
if ticks_diff(ticks_ms(), clock_clock) >= clock_timer:
mqtt_client.loop(timeout=1)
clock_clock = ticks_add(clock_clock, clock_timer)
# reset button state on release
if button0.value and button0_state:
button0_state = False
if not button1.value and button1_state:
button1_state = False
if not button2.value and button2_state:
button2_state = False
# buttons change light scenes
if not button0.value and not button0_state:
mqtt_client.publish(light_feed, 0)
scene_select.y = scene_y[0]
button0_state = True
if button1.value and not button1_state:
mqtt_client.publish(light_feed, 1)
scene_select.y = scene_y[1]
button1_state = True
if button2.value and not button2_state:
mqtt_client.publish(light_feed, 2)
scene_select.y = scene_y[2]
button2_state = True
except Exception as error: # pylint: disable=broad-except
print(error)
mqtt_client.disconnect()
time.sleep(5)
microcontroller.reset()
Upload the Code and Libraries to the Feather
After downloading the Project Bundle, plug your Feather into the computer's USB port with a known good USB data+power cable. You should see a new flash drive appear in the computer's File Explorer or Finder (depending on your operating system) called CIRCUITPY. Unzip the folder and copy the following items to the Feather's CIRCUITPY drive.
- lib folder
- code.py
- roundedHeavy-26.bdf
- tft_bg.bmp
Your Feather CIRCUITPY drive should look like this after copying the lib folder, bitmap graphic, font file the code.py file.
Add Your settings.toml File
As of CircuitPython 8.0.0, there is support for Environment Variables. Environment variables are stored in a settings.toml file. Similar to secrets.py, the settings.toml file separates your sensitive information from your main code.py file. Add your settings.toml file as described in the Create Your settings.toml File page earlier in this guide. You'll need to include your ADAFRUIT_AIO_USERNAME, ADAFRUIT_AIO_KEY, CIRCUITPY_WIFI_SSID and CIRCUITPY_WIFI_PASSWORD.
CIRCUITPY_WIFI_SSID = "your-ssid-here" CIRCUITPY_WIFI_PASSWORD = "your-ssid-password-here" ADAFRUIT_AIO_USERNAME = "your-username-here" ADAFRUIT_AIO_KEY = "your-key-here"
How the CircuitPython Code Works
At the top of the code, you'll add your feed names that you'll be monitoring over MQTT.
aio_username = os.getenv("ADAFRUIT_AIO_USERNAME")
aio_key = os.getenv("ADAFRUIT_AIO_KEY")
# feeds!
temp_feed = aio_username + "/feeds/eve-temp" # temperature sensor
humid_feed = aio_username + "/feeds/eve-humid" # humidity sensor
lux_feed = aio_username + "/feeds/eve-light" # lux sensor
occupy_feed = aio_username + "/feeds/eve-occupy" # occupation sensor
light_feed = aio_username + "/feeds/nanoleaf" # lightstrip
Buttons
The Feather ESP32-S3 Reverse TFT has three buttons that you can use for user input. These are setup as digitalio inputs.
# buttons button0 = digitalio.DigitalInOut(board.D0) button0.direction = digitalio.Direction.INPUT button0.pull = digitalio.Pull.UP button0_state = False button1 = digitalio.DigitalInOut(board.D1) button1.direction = digitalio.Direction.INPUT button1.pull = digitalio.Pull.DOWN button1_state = False button2 = digitalio.DigitalInOut(board.D2) button2.direction = digitalio.Direction.INPUT button2.pull = digitalio.Pull.DOWN button2_state = False
Graphics
The tft_bg.bmp graphic is shown on the display as a Bitmap. This graphic has icons for the sensors and buttons. There are a few text objects for the data that will be shown from the feeds. Two shapes are also used to display data. A circle is used to show occupancy by changing color from red (unoccupied) to green (occupied). A rounded rectangle is used to outline the button labels to show which Scene is selected.
display = board.DISPLAY
group = displayio.Group()
display.root_group = group
# load background bitmap
bitmap = displayio.OnDiskBitmap("/tft_bg.bmp")
tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)
group = displayio.Group()
group.append(tile_grid)
# bitmap font
font_file = "/roundedHeavy-26.bdf"
font = bitmap_font.load_font(font_file)
# text elements
temp_text = bitmap_label.Label(font, text="00.0°C", x=55, y=70, color=0xFFFFFF)
group.append(temp_text)
humid_text = bitmap_label.Label(font, text="00.0%", x=120, y=70, color=0xFFFFFF)
group.append(humid_text)
lux_text = bitmap_label.Label(font, text="00 lx", x=190, y=70, color=0xFFFFFF)
group.append(lux_text)
occupy_text = bitmap_label.Label(font, text="Occupied?", x=128,
y=display.height - 12, color=0xFFFFFF)
group.append(occupy_text)
onOff_circ = Circle(display.width - 12, display.height - 12, 10, fill=0xcc0000)
group.append(onOff_circ)
scene_select = RoundRect(0, 0, 42, 40, 8, fill=None, outline=0xcccc00, stroke=6)
scene_y = [0, int(display.height / 2) - int(scene_select.height / 2),
display.height - scene_select.height - 1]
group.append(scene_select)
display.root_group = group
MQTT Methods
MQTT is used to connect to Adafruit IO. The first method connected() subscribes to the five feeds defined at the top of the code.
def connected(client, userdata, flags, rc): # pylint: disable=unused-argument
# This function will be called when the client is connected
# successfully to the broker.
print("Connected to Adafruit IO!")
# Subscribe to all changes on feeds
client.subscribe(temp_feed)
client.subscribe(humid_feed)
client.subscribe(lux_feed)
client.subscribe(occupy_feed)
client.subscribe(light_feed)
Five custom methods are defined for each feed. The methods for the temperature, humidity and lux feeds update the text with the new value when there is new data available on the feed. The occupancy sensor method changes the color of the circle depending on the value. The lightstrip method changes the y coordinate of the rounded rectangle to outline the selected Scene.
def on_temp_msg(client, topic, msg):
print(f"temp feed data: {msg}°C")
temp_text.text = f"{float(msg):.01f}°C"
def on_humid_msg(client, topic, msg):
print(f"humid feed data: {msg}%")
humid_text.text = f"{float(msg):.01f}%"
def on_lux_msg(client, topic, msg):
print(f"lux feed data: {msg} lx")
lux_text.text = f"{float(msg):.00f} lx"
def on_occupy_msg(client, topic, msg):
print(f"occupation feed data: {msg}")
if msg == "1":
onOff_circ.fill = 0x00cc00
else:
onOff_circ.fill = 0xcc0000
def on_light_msg(client, topic, msg):
print(f"light scene selected: {msg}")
scene_select.y = scene_y[int(msg)]
The callback methods are setup and then a connection is established.
pool = socketpool.SocketPool(wifi.radio)
ssl_context = ssl.create_default_context()
# Initialize an Adafruit IO HTTP API object
mqtt_client = MQTT.MQTT(
broker="io.adafruit.com",
port=1883,
username=aio_username,
password=aio_key,
socket_pool=pool,
ssl_context=ssl_context,
)
# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = on_message
mqtt_client.add_topic_callback(temp_feed, on_temp_msg)
mqtt_client.add_topic_callback(humid_feed, on_humid_msg)
mqtt_client.add_topic_callback(lux_feed, on_lux_msg)
mqtt_client.add_topic_callback(occupy_feed, on_occupy_msg)
mqtt_client.add_topic_callback(light_feed, on_light_msg)
# Connect the client to the MQTT broker.
print("Connecting to Adafruit IO...")
mqtt_client.connect()
The Loop
In the loop, ticks are used for non-blocking timekeeping. Every 5 seconds, the MQTT client loops to check for any new messages on the feeds. If a new message is detected, the callback methods will run, automatically updating the values on the TFT.
Each of the three buttons sends a different value to the lightstrip feed using the publish() function. These values correspond with the values defined in the Shortcut for setting the light Scenes (0-2).
while True:
try:
if ticks_diff(ticks_ms(), clock_clock) >= clock_timer:
mqtt_client.loop(timeout=1)
clock_clock = ticks_add(clock_clock, clock_timer)
# reset button state on release
if button0.value and button0_state:
button0_state = False
if not button1.value and button1_state:
button1_state = False
if not button2.value and button2_state:
button2_state = False
# buttons change light scenes
if not button0.value and not button0_state:
mqtt_client.publish(light_feed, 0)
scene_select.y = scene_y[0]
button0_state = True
if button1.value and not button1_state:
mqtt_client.publish(light_feed, 1)
scene_select.y = scene_y[1]
button1_state = True
if button2.value and not button2_state:
mqtt_client.publish(light_feed, 2)
scene_select.y = scene_y[2]
button2_state = True
except Exception as error: # pylint: disable=broad-except
print(error)
mqtt_client.disconnect()
time.sleep(5)
microcontroller.reset()
Page last edited October 02, 2024
Text editor powered by tinymce.