[{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/492/original/IMG_2521_2.jpeg?1736313830","metadata":{}},{"element_type":"text","content":"\n        \u003ch3\u003e\u003cem\u003eREMIX: AIO Throttling for the Win\u003c/em\u003e\u003c/h3\u003e\n\u003ch1\u003eProject Objective\u003c/h1\u003e\n\u003cp\u003eThe primary objective of this project is to refactor the \u003cstrong\u003eCircuitPython\u003c/strong\u003e 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.\u003c/p\u003e\n      ","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/437/original/Cedar_Grove_Weather_Architecture_v2.png?1733212098","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch1\u003eOverview\u003c/h1\u003e\n\u003cp\u003eThe initial version of the weather system architecture, known as the\u0026nbsp;\u003ca href=\"https://adafruit-playground.com/u/CGrover/pages/display-aio-local-weather-conditions-matrixweather-system\" target=\"_blank\"\u003eDisplay AIO Local Weather Conditions: MatrixWeather System\u003c/a\u003e, 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.\u003c/p\u003e\n\u003cp\u003eTo 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.\u003c/p\u003e\n\u003cp\u003eThe 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.\u003c/p\u003e\n\u003cp\u003eThe 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.\u003c/p\u003e\n\u003cp\u003eAn 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.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch1\u003e\u003cspan\u003eChoosing a Project MPU Board\u003c/span\u003e\u003c/h1\u003e\n\u003cp\u003eUpon 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.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch1\u003eAIO Transaction Throttling Code Examples\u003c/h1\u003e\n\u003cp\u003eTo 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.\u003c/p\u003e\n\u003cp\u003eFor 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.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"# AIO Throttle: Fetch Example for the Matrix Portal S3\n\nfrom adafruit_matrixportal.matrixportal import MatrixPortal\n\nmp = MatrixPortal(width=64, height=32, bit_depth=6, debug=False, rotation=90, status_neopixel=board.NEOPIXEL)\n\ndef get_last_value(feed_key):\n    \"\"\"Fetch the latest value of the AIO feed.\n    :param str feed_key: The AIO feed key.\"\"\"\n    try:\n        # print(f\"throttle limit: {mp.network.io_client.get_remaining_throttle_limit()}\")\n        while mp.network.io_client.get_remaining_throttle_limit() \u003c= 10:\n            time.sleep(1)  # Wait until throttle limit increases\n        last_value = mp.network.io_client.receive_data(feed_key)[\"value\"]\n        return last_value\n    except (KeyError, IndexError) as e:\n        print(f\"Error fetching data from feed {feed_key}: {e}\")","metadata":{"language":"python","linenums":false}},{"element_type":"code","content":"# AIO Throttle: Fetch Example for the PyPortal M4\n\nimport adafruit_pyportal\n\npyportal = adafruit_pyportal.PyPortal(status_neopixel=board.NEOPIXEL, default_bg=\"/pyportal_startup.bmp\")\n\ndef get_last_value(feed_key):\n    \"\"\"Fetch the latest value of the AIO feed.\n    :param str feed_key: The AIO feed key.\"\"\"\n    try:\n        # print(f\"throttle limit: {pyportal.network.io_client.get_remaining_throttle_limit()}\")\n        while pyportal.network.io_client.get_remaining_throttle_limit() \u003c= 10:\n            time.sleep(1)  # Wait until throttle limit increases\n        last_value = pyportal.network.io_client.receive_data(feed_key)[\"value\"]\n        return last_value\n    except (KeyError, IndexError) as e:\n        print(f\"Error fetching data from feed {feed_key}: {e}\")","metadata":{"language":"python","linenums":false}},{"element_type":"code","content":"# AIO Throttle: Publish Example for the ESP32-S3\n\nimport adafruit_connection_manager\nimport wifi\nimport adafruit_requests\nfrom adafruit_io.adafruit_io import IO_HTTP\n\npool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)\nrequests = adafruit_requests.Session(pool, ssl.create_default_context())\nio = IO_HTTP(os.getenv(\"AIO_USERNAME\"), os.getenv(\"AIO_KEY\"), requests)\n\ndef publish_to_aio(value, feed):\n    \"\"\"Publish a value to an AIO feed, while monitoring checking the throttle\n    transaction rate. A blocking method.\n    :param union(int, float, str) value: The value to publish.\n    :param str feed: The name of the AIO feed.\n    \"\"\"\n    try:\n        while io.get_remaining_throttle_limit() \u003c= 10:\n            time.sleep(1)  # Wait until throttle limit increases\n        io.send_data(feed, value)\n        print(f\"SEND '{value}' -\u003e {feed}\")\n    except Exception as aio_publish_error:\n        print(f\"FAIL: '{value}' -\u003e {feed}\")\n        print(f\"  {str(aio_publish_error)}\")","metadata":{"language":"python","linenums":false}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch1\u003eAIO Weather Dashboard\u003c/h1\u003e\n\u003cp\u003eAll 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.\u003c/p\u003e\n\u003cp\u003eThe dashboard’s comprehensive visual representation facilitates the analysis of relationships between internal and external conditions and their impact on workshop corrosion problems.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/480/original/AIO_Weather_Dashboard.png?1735314337","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch1\u003eSpecial Acknowledgements\u003c/h1\u003e\n\u003cp\u003eTyeth Gundry and Brent Rubell did some amazing work to create a simple schema for \u003cem\u003eAIO\u003c/em\u003e feed throttling (see \u003ca href=\"https://github.com/adafruit/Adafruit_CircuitPython_AdafruitIO/pull/127\" target=\"_blank\"\u003eAdd Current User Info Methods\u003c/a\u003e). The approach shows promise for supporting multiple autonomous objects that need to share \u003cem\u003eAIO\u003c/em\u003e feed data. Thank you!\u003c/p\u003e\n\u003cp\u003eTony 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.\u003c/p\u003e\n\u003cp\u003eBesides studying every Star Trek TNG episode, the initial experimentation for the LCARS display comes from Dave Astels' background graphics for the \u003ca href=\"https://learn.adafruit.com/pyportal-alarm-clock\" target=\"_blank\"\u003ePyPortal Alarm Clock\u003c/a\u003e and John Park's \u003ca href=\"https://learn.adafruit.com/star-trek-lcars-display\" target=\"_blank\"\u003eStar Trek LCARS Display\u003c/a\u003e project.\u003c/p\u003e\n\u003cp\u003eInspirational thanks go to DJ Devon for the overall look and functional feel of a\u0026nbsp;\u003ca href=\"https://adafruit-playground.com/u/DJDevon3/pages/esp32-s3-mqtt-feather-weather\" target=\"_blank\"\u003epractical yet attractive weather monitor design\u003c/a\u003e as well as \u003ca href=\"https://adafruit-playground.com/u/DJDevon3/pages/web-api-s-you\" target=\"_blank\"\u003edeep research into Web APIs\u003c/a\u003e, all with CircuitPython. Nicely done!\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch1\u003eWeather Displays and Devices\u003c/h1\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"alert","content":"\u003cp\u003eSome of the PyPortal and Matrix Portal project code utilizes undocumented library functions that are currently unexposed. While it is unlikely that these functions will remain hidden in the future, their future status cannot be guaranteed. An effort will be made to propose modifications to the library to ensure that these functions are integrated into the library’s documented user interface.\u003c/p\u003e","metadata":{"class":"element alert-element build-alert alert-info","markdown":"Some of the PyPortal and Matrix Portal project code utilizes undocumented library functions that are currently unexposed. While it is unlikely that these functions will remain hidden in the future, their future status cannot be guaranteed. An effort will be made to propose modifications to the library to ensure that these functions are integrated into the library’s documented user interface.","alert_type":"info"}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eThe settings.toml File\u003c/h3\u003e\n\u003cp\u003eAt a minimum, the \u003ccode\u003esettings.toml\u003c/code\u003e file needs to contain location, time zone, zone offset, \u003cem\u003eAIO\u003c/em\u003e account credentials, and the \u003cem\u003eAIO+\u003c/em\u003e weather topic key/description information:\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"LOCATION=\"Seattle, WA, US\"\nTIMEZONE=\"US/Pacific\"\nTIMEZONE_OFFSET = -8  # Hours From Greenwich Mean Time (GMT)\n\n# AIO Credentials\nAIO_USERNAME=\"username\"\nAIO_KEY=\"areallylong40characterkeysequence\"\n\n# AIO+ Weather Topic (created by AIO+)\nWEATHER_TOPIC_KEY = 1007  # Integer value\nWEATHER_TOPIC_DESC = \"Seattle, WA\"","metadata":{"language":"auto","linenums":false}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eWeather Source\u003c/h2\u003e\n\u003cp\u003eThe 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.\u003c/p\u003e\n\u003cp\u003eA new version of the Weather Source, the Nuevo Combined Weather Source device, will replace this version by late 2025.\u003c/p\u003e\n\u003cp\u003eCircuitPython code can be found in the \u003ccode\u003eWeather_Source/bundle\u003c/code\u003e folder of the \u003ca href=\"https://github.com/CedarGroveStudios/Weather_System\" target=\"_blank\"\u003eCedarGrove Weather System\u003c/a\u003e repository.\u003c/p\u003e\n      \n\n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/438/original/Weather_Source_v00.jpeg?1733284539","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n        \u003ch2\u003eWorkshop Corrosion Monitor LCARS Display\u003c/h2\u003e\n\u003cp\u003eThe 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.\u003c/p\u003e\n\u003cp\u003eCircuitPython code can be found in the\u0026nbsp;\u003ccode\u003ePyPortal_Corrosion_Display/bundle\u003c/code\u003e\u0026nbsp;folder of the \u003ca href=\"https://github.com/CedarGroveStudios/Weather_System\" target=\"_blank\"\u003eCedarGrove Weather System\u003c/a\u003e repository.\u003c/p\u003e\n      \n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/445/original/IMG_2478_2.jpeg?1733463665","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n        \u003ch2\u003eMatrix Weather Display\u003c/h2\u003e\n\u003cp\u003eThe Matrix Weather Display, situated in the living room, provides comprehensive weather and basic workstation conditions.\u003c/p\u003e\n\u003cp\u003eThe Matrix Weather Display utilizes a Matrix Portal S3 board, enabling the implementation of AIO feed throttling capabilities.\u003c/p\u003e\n\u003cp\u003eCircuitPython code can be found in the\u0026nbsp;\u003ccode\u003eMatrix_Portal_Weather_Display/bundle\u003c/code\u003e\u0026nbsp;folder of the \u003ca href=\"https://github.com/CedarGroveStudios/Weather_System\" target=\"_blank\"\u003eCedarGrove Weather System\u003c/a\u003e repository.\u003c/p\u003e\n      \n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/444/original/IMG_2477.jpeg?1733463637","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n        \u003ch2\u003eMikey Weather Display\u003c/h2\u003e\n\u003cp\u003eThe 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.\u003c/p\u003e\n\u003cp\u003eThe PyPortal’s /icons folder contains a collection of day and night weather icon bitmaps.\u003c/p\u003e\n\u003cp\u003eNote that the Sunrise and Sunset values are currently not stored in the AIO feeds for this version.\u003c/p\u003e\n\u003cp\u003eCircuitPython code can be found in the\u0026nbsp;\u003ccode\u003ePyPortal_Mikey_Weather_Display/bundle\u003c/code\u003e\u0026nbsp;folder of the \u003ca href=\"https://github.com/CedarGroveStudios/Weather_System\" target=\"_blank\"\u003eCedarGrove Weather System\u003c/a\u003e repository.\u003c/p\u003e\n      \n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/443/original/IMG_2478.jpeg?1733463585","metadata":{}},{"element_type":"text","content":"\n  \n  \n        \u003ch2\u003eThe Nuevo Combined Weather Source and Corrosion Display\u003c/h2\u003e\n\u003cp\u003eThis 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.\u003c/p\u003e\n\u003cp\u003eThe display employs \u003ca href=\"https://github.com/CedarGroveStudios/CircuitPython_PaletteFilter\" target=\"_blank\"\u003ecedargrove_palettefilter\u003c/a\u003e 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.\u003c/p\u003e\n\u003cp\u003eCircuitPython code can be found in the\u0026nbsp;\u003ccode\u003eWeather_Display_v027/bundle\u003c/code\u003e\u0026nbsp;folder of the \u003ca href=\"https://github.com/CedarGroveStudios/Weather_System\" target=\"_blank\"\u003eCedarGrove Weather System\u003c/a\u003e repository.\u003c/p\u003e\n\u003cp\u003eA similar Weather Source device is in progress and expected to be completed by late 2025.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://youtu.be/8OYAtysNkL0?si=HFLNB-xm02Ltn42P\" target=\"_blank\"\u003ePrototype Test -- YouTube\u003c/a\u003e\u003c/p\u003e\n      \n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/478/original/IMG_2512.jpeg?1735236351","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch1\u003eWish List (in progress)\u003c/h1\u003e\n\u003cul\u003e\n\u003cli\u003eMatrixPortal and PortalBase CircuitPython Libraries\n\u003cul\u003e\n\u003cli\u003eExpose the following functions and properties:\n\u003cul\u003e\n\u003cli\u003e\n\u003ccode\u003enetwork.io_client.get_remaining_throttle_limit( )\u003c/code\u003e\u0026nbsp; for throttle monitoring\u0026nbsp;\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003enetwork.io_client.receive_data( )\u003c/code\u003e\u0026nbsp; to reduce size of \u003cem\u003eAIO\u003c/em\u003e retrieval data set for M4 processor\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003egraphics._bg_sprite.pixel_shader\u003c/code\u003e\u0026nbsp; for software-based display brightness control\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003egraphics._bg_sprite.x\u003c/code\u003e \u0026nbsp;for software-based display brightness control\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003egraphics._bg_sprite.y\u003c/code\u003e \u0026nbsp;for software-based display brightness control\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e_text[index][\"color\"]\u003c/code\u003e\u0026nbsp; to change color of progress bar label (and any text label)\u003c/li\u003e\n\u003cli\u003e\n\u003ccode\u003e_text[index][\"position\"]\u003c/code\u003e to change position of progress bar label (and any text label)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eAdd new functions and properties:\n\u003cul\u003e\n\u003cli\u003eTo reduce the number of \u003cem\u003eAIO\u003c/em\u003e data point transactions, add a function to receive a json table of all of a client's last feed entries as a single \u003cem\u003eAIO\u003c/em\u003e 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.\u003c/li\u003e\n\u003cli\u003eIncorporate the feed failure detection scheme used in the current version of the PyPortal Corrosion Monitor in all display devices.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eAdafruit IO\n\u003cul\u003e\n\u003cli\u003eExpand the \u003cem\u003eAIO+ Weather Service\u003c/em\u003e to provide a collection of user-specified server-side feeds for a client's \u003cem\u003eAIO\u003c/em\u003e 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.\u003c/li\u003e\n\u003cli\u003eCreate a CircuitPython library of icon bitmap files to match \u003cem\u003eApple WeatherKit\u003c/em\u003e,\u0026nbsp;\u003cem\u003eopenweathermap.org,\u003c/em\u003e and/or \u003ca href=\"https://api.weather.gov/icons/land/night/few?size=large\" target=\"_blank\"\u003e\u003cem\u003eweather.gov\u003c/em\u003e\u003c/a\u003e conditions. Consider adding a function to resize the bitmap for a specified resolution or pixel size. Also consider providing the bitmaps directly from \u003cem\u003eAIO\u003c/em\u003e.\u003c/li\u003e\n\u003cli\u003eCreate an \u003cem\u003eAIO\u003c/em\u003e feed failure detection notification scheme.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n        \u003ch1\u003eThe Original Corrosion Monitor\u003c/h1\u003e\n\u003cp\u003eThis 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.\u003c/p\u003e\n\u003cp\u003eThe monitor’s ability to operate during power outages was facilitated by its integrated battery backup, eliminating the requirement for a WiFi router.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eWorkstation Display (Transmitter)\n\u003cul\u003e\n\u003cli\u003eFeather M0 RFM69HCW Packet Radio\u003c/li\u003e\n\u003cli\u003eDS3231 Precision RTC FeatherWing\u003c/li\u003e\n\u003cli\u003eStandard 20x4 Character LCD Display\u003c/li\u003e\n\u003cli\u003eSHT30 Temperature/Humidity sensor\u003c/li\u003e\n\u003cli\u003e500mAh LiPo Battery\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003cul\u003e\n\u003cli\u003eRemote Display (Receiver)\n\u003cul\u003e\n\u003cli\u003eFeather M0 RFM69HCW Packet Radio\u003c/li\u003e\n\u003cli\u003eOLED 128x32 Display FeatherWing\u003c/li\u003e\n\u003cli\u003e120mAh LiPo Battery\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n      \n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/475/original/DSC03504a_lores.jpg?1735192403","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/476/original/DSC03641a_lores.jpg?1735192423","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/5477","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/3315","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/3651","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/5872","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/4116","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/4745","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/5778","metadata":{}}]