[{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/885/original/IMG_2790.jpeg?1751431246","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        \u003cp\u003e\u003cstrong\u003e\u003cem\u003eAn Adafruit IO - connected, CircuitPython remote thermal camera.\u003c/em\u003e\u003c/strong\u003e\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","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n        \u003ch2\u003eProject Objective\u003c/h2\u003e\n\u003cp\u003eI have an Adafruit IO (AIO)-connected \u003ca href=\"https://adafruit-playground.com/u/CGrover/pages/cedar-grove-weather-architecture-v2-0#the-nuevo-combined-weather-source-and-corrosion-display-3189490\" target=\"_blank\"\u003ecorrosion monitoring system\u003c/a\u003e in my remote laboratory (the workshop bench in the garage) to keep an eye on the temperature and humidity inside and outside the lab. It uses \u003cstrong\u003eCircuitPython\u003c/strong\u003e to monitor the temperature and humidity, and it also uses AIO Plus to connect it to the weather outside. But here’s the thing: the temperature and humidity sensor can’t tell if a door or window is left open. It takes way too long to notice the change. I wish it could “see” if a small area inside the workshop has a different temperature than the rest of the space. It would also be great if it could detect human motion in the workshop or if the soldering iron was left on.\u003c/p\u003e\n\u003ch3\u003eRequirements\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003ePeriodically capture and upload a thermal image of a critical portion of the workshop.\u003c/li\u003e\n\u003cli\u003eMonitor for temperature extremes and upload an image when exceeded.\u003c/li\u003e\n\u003cli\u003eDetect human motion and upload an image.\u003c/li\u003e\n\u003cli\u003eProvide a local color display with automatic brightness control.\u003c/li\u003e\n\u003cli\u003eContinuously update the local display image at least twice a second to quickly detect motion and respond to thermal events.\u003c/li\u003e\n\u003cli\u003eUpload the captured thermal image on a remotely accessible AIO dashboard page via the local WiFi network.\u003c/li\u003e\n\u003cli\u003eUpload bitmap image payload to AIO in less than 10 seconds.\u003c/li\u003e\n\u003cli\u003ePower from a USB 5-volt wall wart.\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3\u003eFuture and Nice-to-Have\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003eBlank the screen when motion has not been detected for a preset amount of time (screen saver).\u003c/li\u003e\n\u003cli\u003eSD Card storage of images and temperature statistics with historical view UI.\u003c/li\u003e\n\u003cli\u003eTrigger AIO notification events related to motion or alarm settings.\u003c/li\u003e\n\u003cli\u003eUpload minimum, average, maximum temperature values with image; display on dashboard.\u003c/li\u003e\n\u003cli\u003eInterface to Apple HomeKit.\u003c/li\u003e\n\u003cli\u003eCapture local audio.\u003c/li\u003e\n\u003cli\u003eLive MEMENTO photo overlay.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eTo speed up prototyping and algorithm development, \u003cstrong\u003eCircuitPython\u003c/strong\u003e was the choice for the software side of things. Besides, the code needed for creating images with a \u003ca href=\"https://learn.adafruit.com/improved-amg8833-pygamer-thermal-camera\" target=\"_blank\"\u003ethermal camera\u003c/a\u003e and for \u003ca href=\"https://adafruit-playground.com/u/CGrover/pages/cedar-grove-weather-architecture-v2-0\" target=\"_blank\"\u003ereliable communication with AIO\u003c/a\u003e already exists in other projects that I've recently developed.\u003c/p\u003e\n      \n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/887/original/Screenshot_2025-06-24_at_2.35.42%E2%80%AFPM.png?1750832032","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        \u003ch2\u003eAcknowledgments\u003c/h2\u003e\n\u003cp\u003eThanks to Dave Astels and Matt Land for working out the details for bitmap file header and data formatting example for the \u003cem\u003eAdafruit_CircuitPython_BitmapSaver\u003c/em\u003e helper library. The code inspired the approach used for this project.\u003c/p\u003e\n\u003cp\u003eBrent Rubell's \u003cem\u003eDIY IoT Doorbell Camera with MEMENTO\u003c/em\u003e learning guide made it easy to experiment with bitmap image uploads to an AIO feed. Very comprehensive and helpful. Thank you!\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;\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","metadata":{}},{"element_type":"alert","content":"\u003cp\u003eCAUTION: The AMG8833 sensor used in this project is not accurate or stable enough to be used for health or safety purposes.\u003c/p\u003e","metadata":{"class":"element alert-element build-alert alert-warning","markdown":"CAUTION: The AMG8833 sensor used in this project is not accurate or stable enough to be used for health or safety purposes.","alert_type":"warning"}},{"element_type":"text","content":"\n  \n        \u003ch2\u003eCoding the Thermal Camera in CircuitPython\u003c/h2\u003e\n\u003cp\u003e\u003cspan\u003eThe thermal camera component of the code was derived from the\u0026nbsp;\u003c/span\u003e\u003cem\u003eImproved AMG8833 PyGamer Thermal Camera\u003c/em\u003e\u003cspan\u003e project, drawing upon its sensor capture and linear interpolation techniques. For a comprehensive exploration of this approach, please refer to the \u003c/span\u003e\u003ca href=\"https://learn.adafruit.com/improved-amg8833-pygamer-thermal-camera\" target=\"_blank\"\u003ethermal camera\u003c/a\u003e\u003cspan\u003e learning guide.\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003eThis project introduces a thermal image “screen capture” capability and establishes a connection to an AIO graphic image feed, enabling the transfer of the thermal image to the workshop’s AIO dashboard. Instead of transmitting a substantial bitmap of the screen image, only the interpolated 15x15 pixel image is sent to the AIO image feed as a compact\u0026nbsp;\u003ccode\u003e\u003cspan\u003e.bmp\u003c/span\u003e\u003c/code\u003e stream, encoded as \u003ccode\u003e\u003cspan\u003ebase64\u003c/span\u003e\u003c/code\u003e text. The AIO image object is subsequently enlarged on the server side to accommodate the dimensions required for the dashboard.\u003c/p\u003e\n\u003cp\u003eIn addition to standard CircuitPython libraries, a fonts folder, and the settings.toml file, the Workshop Thermal Camera (WTC) code comprises three primary modules and one helper module:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ecode.py: This module serves as the primary process, listing adjustable operational parameters, attaching peripheral devices (excluding the display), implementing methods for working with internet resources, and executing the routine that captures the thermal image display grid and uploads the bitmap image to an AIO feed. It also detects motion and monitors whether the maximum temperature exceeds the alarm limit.\u003c/li\u003e\n\u003cli\u003ewtc_display: This class object module abstracts the TFT FeatherWing to emulate a displayio display object. It establishes the image grid using displayio shapes, positions the statistical elements on the display, and provides a text alert reporting feature. Its properties include those of typical displays (width, height, brightness), along with additional attributes specific to the thermal camera.\u003c/li\u003e\n\u003cli\u003ecamera_amg88xx.py: This driver-like class object instantiates and abstracts the AMG8833 thermal sensor module. If selected, it offers auto-focusing and linear interpolation from 8x8 sensor elements to 15x15 pixels. Its properties include a method for acquiring sensor data.\u003c/li\u003e\n\u003cli\u003eindex_to_rgb_iron.py: This helper function returns an RGB color value based on the iron heat spectrum, which linearly correlates with a 0.0 to 1.0 index input value.\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/904/original/Screenshot_2025-07-01_at_2.40.38%E2%80%AFPM.png?1751406165","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        \u003ch2\u003e\u003cspan\u003eProject Code Repository\u003c/span\u003e\u003c/h2\u003e\n\u003cp\u003e\u003cspan\u003eThe project's CircuitPython code, helpers, fonts, and libraries can be found in the\u0026nbsp;\u003c/span\u003e\u003ccode\u003eWorkshop_Thermal_Camera/bundle\u003c/code\u003e\u003cspan\u003e folder of the\u003c/span\u003e\u003cspan\u003e\u0026nbsp;\u003ca href=\"https://github.com/CedarGroveStudios/Workshop_Thermal_Camera/tree/main/bundle\"\u003eWorkshop Thermal Camera\u003c/a\u003e repository.\u003c/span\u003e\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","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eThe \u003cem\u003esettings.toml\u003c/em\u003e File\u003c/h3\u003e\n\u003cp\u003e\u003cspan\u003eRemember, at a minimum, the\u0026nbsp;\u003c/span\u003e\u003ccode\u003esettings.toml\u003c/code\u003e\u003cspan\u003e file needs to contain your WiFi router and \u003c/span\u003e\u003cem\u003eAIO\u003c/em\u003e\u003cspan\u003e account credentials\u003c/span\u003e\u003cspan\u003e:\u003c/span\u003e\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"CIRCUITPY_WIFI_SSID = \"MyRouterSSID\"\nCIRCUITPY_WIFI_PASSWORD = \"a-very-secure-password\"\n\n# AIO Credentials\nAIO_USERNAME=\"username\"\nAIO_KEY=\"a-very-long-40-character-key-string-1234\"","metadata":{"language":"auto","linenums":false}},{"element_type":"text","content":"\n        \u003ch2\u003eSystem Components\u003c/h2\u003e\n\u003cp\u003eThe thermal camera components consist of:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eESP32-S3 4Mb/2Mb Feather.\u003c/li\u003e\n\u003cli\u003e2.4\" TFT FeatherWing (optionally wired for display brightness control and an ambient light sensor).\u003c/li\u003e\n\u003cli\u003eAMG8833 Thermal Camera Breakout, connected to the ESP32 Feather with a 100mm STEMMA-QT cable.\u003c/li\u003e\n\u003cli\u003eAn optional ALS-PT19 Analog Light Sensor Breakout connected to the TFT FeatherWing's +3V, GND, and A3 pads. The light sensor is used to automatically control display brightness in proportion to the ambient light level.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIf display brightness control is needed, the TFT FeatherWing will require a short jumper wire soldered to connect the \u003ccode\u003eTX\u003c/code\u003e pin and \u003ccode\u003eLITE\u003c/code\u003e pads to allow PWM control of the display backlight brightness. (See photo.)\u003c/p\u003e\n\u003cp\u003eFor automatic display brightness control, connect the ALS-PT19 light sensor output to the \u003ccode\u003eA3\u003c/code\u003e GPIO pin pad. Also connect the sensor's power and ground to the FeatherWing's \u003ccode\u003e3V\u003c/code\u003e and \u003ccode\u003eGND\u003c/code\u003e pads. For the prototype, three Dupont Cable 20cm Soft Silicon wires were cut in half and with the wire end soldered to the sensor breakout and the Dupont pin end inserted into the outer row of the Feather socket as shown in the wiring photos.\u003c/p\u003e\n      ","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/906/original/wtc_display_brightness_lorez.png?1751430114","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/3538","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/4210","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/2748","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/4482","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/907/original/wtc_AIO_image_feed.png?1751431209","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/909/original/wtc_thermal_photo_overlay.png?1751479773","metadata":{}}]