REMIX: AIO Throttling for the Win
Project Objective
The primary objective of this project is to refactor the CircuitPython code embedded within the existing weather monitoring and source devices to enable AIO transaction throttling. Additionally, the Workshop Corrosion Monitor and Matrix Weather Display will transform into display-only devices. Ultimately, the goal is to consolidate these functionalities into a single device.
Overview
The initial version of the weather system architecture, known as the Display AIO Local Weather Conditions: MatrixWeather System, exhibited satisfactory performance. However, its reliability was compromised when multiple transmitter and receiver devices competed for access to the Adafruit IO (AIO) feeds. To mitigate access collisions, each independent device was meticulously designed to transmit or receive data at predetermined rates, which remained well below the AIO+ subscription rate limit of 60 data point transactions per minute. Nevertheless, due to the autonomous operation of each device, instances arose where two transactions would heterodyne, straining the limit and resulting in feed failures.
To address the reliability issue, the new architecture design transitioned from utilizing MQTT to the HTTP protocol. While MQTT facilitates relatively straightforward “subscription” to AIO feeds, HTTP offers greater control granularity, including a recently introduced feature enabling independent devices to monitor feed access activity. Collisions can be mitigated by monitoring the number of data point transactions remaining and waiting until a sufficient number are available for the queued transaction event.
The primary architectural modification was the incorporation of throttling. A secondary objective was to reduce the number of devices in the system by combining the existing Corrosion Monitor sensor with the REPEATER device, resulting in the creation of the novel Weather SOURCE device. The Weather SOURCE extracts local weather conditions from AIO+ Weather and integrates them with the local sensor’s temperature, humidity, dew point, and corrosion detection data. Subsequently, the Weather SOURCE publishes this information to a collection of standard AIO feeds.
The other devices within the system comprise displays that extract data from the AIO feeds. One display replaces the previously existing Workshop Corrosion LCARS Monitor (PyPortal M4), which was situated in the workshop, and is now designated as the Workshop Corrosion Monitor Display. The second display is the Living Room MatrixWeather Display (upgraded from a Matrix Portal M4 to the S3 version). Given that AIO feed access rates are monitored, it will be feasible to create additional task-specific displays, potentially for the studio or kitchen.
An advantage of the new architecture is that certain display devices will not require substantial PSRAM for retaining the extensive JSON file provided by AIO+ Weather, with the exception of a Matrix Portal. The singular Source device, equipped with a large PSRAM, extracts solely the essential information required by the displays and stores the extraction within the AIO feeds.
Choosing a Project MPU Board
Upon utilizing the PyPortal M4 family and the Matrix Portal M4 for display devices, I encountered memory capacity limitations. The PortalBase library occupies a substantial amount of memory, leaving insufficient space for projects that necessitate accessing multiple feeds or those featuring intricate displayio graphic elements, such as labels, shapes, buttons, and bitmaps. Memory capacity constraints are particularly pronounced when employing M4 devices. Consequently, the plan is to commence utilizing higher-capacity ESP32-S3 Feathers attached to TFT FeatherWings for future projects. In the meantime, the PyPortal and Matrix Portal M4 inventory will be repurposed for non-wireless projects that do not necessitate PortalBase for connectivity.
AIO Transaction Throttling Code Examples
To meet service level expectations for all AIO users, the maximum number of client data feed transactions per minute is restricted. The free subscription limits transaction activity to 30 per minute, while the premium service’s limit is 60 per minute.
For the Weather System project, two techniques were employed to monitor the instantaneous number of remaining transactions. When the number of remaining transactions during a running minute reaches 0, the AIO server ceases responding to transaction requests for a period of time. Weather System devices monitor the number of available transactions each time a transaction is pending. If less than 10 are remaining, the device waits for 1 second before rechecking. When the available transactions value increases, the device initiates the transaction.
# AIO Throttle: Fetch Example for the Matrix Portal S3
from adafruit_matrixportal.matrixportal import MatrixPortal
mp = MatrixPortal(width=64, height=32, bit_depth=6, debug=False, rotation=90, status_neopixel=board.NEOPIXEL)
def get_last_value(feed_key):
"""Fetch the latest value of the AIO feed.
:param str feed_key: The AIO feed key."""
try:
# print(f"throttle limit: {mp.network.io_client.get_remaining_throttle_limit()}")
while mp.network.io_client.get_remaining_throttle_limit() <= 10:
time.sleep(1) # Wait until throttle limit increases
last_value = mp.network.io_client.receive_data(feed_key)["value"]
return last_value
except (KeyError, IndexError) as e:
print(f"Error fetching data from feed {feed_key}: {e}")
# AIO Throttle: Fetch Example for the PyPortal M4
import adafruit_pyportal
pyportal = adafruit_pyportal.PyPortal(status_neopixel=board.NEOPIXEL, default_bg="/pyportal_startup.bmp")
def get_last_value(feed_key):
"""Fetch the latest value of the AIO feed.
:param str feed_key: The AIO feed key."""
try:
# print(f"throttle limit: {pyportal.network.io_client.get_remaining_throttle_limit()}")
while pyportal.network.io_client.get_remaining_throttle_limit() <= 10:
time.sleep(1) # Wait until throttle limit increases
last_value = pyportal.network.io_client.receive_data(feed_key)["value"]
return last_value
except (KeyError, IndexError) as e:
print(f"Error fetching data from feed {feed_key}: {e}")
# AIO Throttle: Publish Example for the ESP32-S3
import adafruit_connection_manager
import wifi
import adafruit_requests
from adafruit_io.adafruit_io import IO_HTTP
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
io = IO_HTTP(os.getenv("AIO_USERNAME"), os.getenv("AIO_KEY"), requests)
def publish_to_aio(value, feed):
"""Publish a value to an AIO feed, while monitoring checking the throttle
transaction rate. A blocking method.
:param union(int, float, str) value: The value to publish.
:param str feed: The name of the AIO feed.
"""
try:
while io.get_remaining_throttle_limit() <= 10:
time.sleep(1) # Wait until throttle limit increases
io.send_data(feed, value)
print(f"SEND '{value}' -> {feed}")
except Exception as aio_publish_error:
print(f"FAIL: '{value}' -> {feed}")
print(f" {str(aio_publish_error)}")
AIO Weather Dashboard
All weather and local sensor conditions are collected in AIO feeds. The primary feed trends are displayed on the AIO browser-based dashboard, as shown below.
The dashboard’s comprehensive visual representation facilitates the analysis of relationships between internal and external conditions and their impact on workshop corrosion problems.
Special Acknowledgements
Tyeth Gundry and Brent Rubell did some amazing work to create a simple schema for AIO feed throttling (see Add Current User Info Methods). The approach shows promise for supporting multiple autonomous objects that need to share AIO feed data. Thank you!
Tony DiCola's innovative introduction of MicroPython for M0 Feathers made it possible to build the first Workshop Corrosion Monitor. And a huge thanks goes to Jerry Needell for working through the extremely complex issues to make the first CircuitPython driver for the RFM-69 radio.
Besides studying every Star Trek TNG episode, the initial experimentation for the LCARS display comes from Dave Astels' background graphics for the PyPortal Alarm Clock and John Park's Star Trek LCARS Display project.
Inspirational thanks go to DJ Devon for the overall look and functional feel of a practical yet attractive weather monitor design as well as deep research into Web APIs, all with CircuitPython. Nicely done!
The settings.toml File
At a minimum, the settings.toml file needs to contain location, time zone, zone offset, AIO account credentials, and the AIO+ weather topic key/description information:
LOCATION="Seattle, WA, US" TIMEZONE="US/Pacific" TIMEZONE_OFFSET = -8 # Hours From Greenwich Mean Time (GMT) # AIO Credentials AIO_USERNAME="username" AIO_KEY="areallylong40characterkeysequence" # AIO+ Weather Topic (created by AIO+) WEATHER_TOPIC_KEY = 1007 Â # Integer value WEATHER_TOPIC_DESC = "Seattle, WA"
Weather Source
The primary source of AIO+ Weather and the local workstation temperature/humidity sensor employed for corrosion detection are the primary sources of data. These sensors transmit weather and local workstation conditions to AIO feeds in the client’s account, which are subsequently retrieved by display devices.
A new version of the Weather Source, the Nuevo Combined Weather Source device, will replace this version by late 2025.
CircuitPython code can be found in the Weather_Source/bundle folder of the CedarGrove Weather System repository.
Workshop Corrosion Monitor LCARS Display
The workshop-based display for monitoring local workshop corrosion conditions stored in AIO feeds. To respond to a corrosion event, the display checks the feeds every two minutes. Additionally, the code can detect if the source device providing feed data has stalled or failed; this is particularly useful when the source device is mounted on the wall of the detached workshop.
CircuitPython code can be found in the PyPortal_Corrosion_Display/bundle folder of the CedarGrove Weather System repository.
Matrix Weather Display
The Matrix Weather Display, situated in the living room, provides comprehensive weather and basic workstation conditions.
The Matrix Weather Display utilizes a Matrix Portal S3 board, enabling the implementation of AIO feed throttling capabilities.
CircuitPython code can be found in the Matrix_Portal_Weather_Display/bundle folder of the CedarGrove Weather System repository.
Mikey Weather Display
The kitchen-based weather display, named after an esteemed local television meteorologist, features a startup sequence that reproduces a brief audio sample of Mike preparing to discuss the weather forecast.
The PyPortal’s /icons folder contains a collection of day and night weather icon bitmaps.
Note that the Sunrise and Sunset values are currently not stored in the AIO feeds for this version.
CircuitPython code can be found in the PyPortal_Mikey_Weather_Display/bundle folder of the CedarGrove Weather System repository.
The Nuevo Combined Weather Source and Corrosion Display
This all-in-one LCARS-like display for the Adafruit ESP32-S3 4Mb/2Mb Feather and 3.5-inch TFT FeatherWing offers a comprehensive display of weather and corrosion conditions. All weather and local conditions are sourced from AIO feeds populated by the Weather Source device.
The display employs cedargrove_palettefilter from the Community Bundle to automatically adjust the background graphic image palette based on day and night. The night palette predominantly features blue, while the day palette closely resembles the yellow-gold hue of typical TNG LCARS panels. PaletteFilter enables the modification of a range of colors within the original palette to a specified color or achieve transparency, akin to a video “green screen” effect. In this project, the LCARS light blue color (and closely associated blue colors within a tolerance band) are modified to yellow-gold for the daytime palette.
CircuitPython code can be found in the Weather_Display_v027/bundle folder of the CedarGrove Weather System repository.
A similar Weather Source device is in progress and expected to be completed by late 2025.
Wish List (in progress)
- MatrixPortal and PortalBase CircuitPython Libraries
- Expose the following functions and properties:
-
network.io_client.get_remaining_throttle_limit( )for throttle monitoring -
network.io_client.receive_data( )to reduce size of AIO retrieval data set for M4 processor -
graphics._bg_sprite.pixel_shaderfor software-based display brightness control -
graphics._bg_sprite.xfor software-based display brightness control -
graphics._bg_sprite.yfor software-based display brightness control -
_text[index]["color"]to change color of progress bar label (and any text label) -
_text[index]["position"]to change position of progress bar label (and any text label)
-
- Add new functions and properties:
- To reduce the number of AIO data point transactions, add a function to receive a json table of all of a client's last feed entries as a single AIO query, rather than having to extract them one-at-a-time. For most clients, the downloaded data set would likely be small enough to retrieve into a PyPortal M4's memory.
- Incorporate the feed failure detection scheme used in the current version of the PyPortal Corrosion Monitor in all display devices.
- Expose the following functions and properties:
- Adafruit IO
- Expand the AIO+ Weather Service to provide a collection of user-specified server-side feeds for a client's AIO account with the latest weather observations for a particular location or latitude/longitude. Would be a welcome feature that could create a storm of new project innovation. Including forecast information would be a plus.
- Create a CircuitPython library of icon bitmap files to match Apple WeatherKit, openweathermap.org, and/or weather.gov conditions. Consider adding a function to resize the bitmap for a specified resolution or pixel size. Also consider providing the bitmaps directly from AIO.
- Create an AIO feed failure detection notification scheme.
The Original Corrosion Monitor
This was the inaugural workshop corrosion display, circa 2017. Initially implemented using Micropython, it gained significant traction upon the advent of CircuitPython. Employing two packet radio modules, the monitor and its diminutive remote continuously updated conditions values every four minutes. Upon double-clicking, the remote receiver’s select button transmitted a message to the transmitter, enabling limited remote control, such as silencing an audible alarm.
The monitor’s ability to operate during power outages was facilitated by its integrated battery backup, eliminating the requirement for a WiFi router.
- Workstation Display (Transmitter)
- Feather M0 RFM69HCW Packet Radio
- DS3231 Precision RTC FeatherWing
- Standard 20x4 Character LCD Display
- SHT30 Temperature/Humidity sensor
- 500mAh LiPo Battery
- Remote Display (Receiver)
- Feather M0 RFM69HCW Packet Radio
- OLED 128x32 Display FeatherWing
- 120mAh LiPo Battery
This page (Cedar Grove Weather Architecture v2.0) was last updated on August 16, 2025.