Getting Started
Adafruit Playground is a wonderful and safe place to share your interests with Adafruit's vibrant community of makers and doers. Have a cool project you are working on? Have a bit of code that you think others will find useful? Want to show off your electronics workbench? You have come to the right place.
The goal of Adafruit Playground is to make it as simple as possible to share your work. On the Adafruit Playground users can create Notes. A note is a single-page space where you can document your topic using Adafruit's easy-to-use editor. Notes are like Guides on the Adafruit Learning System but guides are high-fidelity content curated and maintained by Adafuit. Notes are whatever you want them to be. Have fun and be kind.
Click here to learn more about Adafruit Playground and how to get started.
-
LiPo Storage Voltage Conditioner
This is a simple project to discharge Adafruit LiPo packs to 3.8 volts for storage. First you use a computer to set up the ESP32-S3 TFT Feather, then you disconnect the computer and plug in the LiPo. The battery voltage shows on the display until it reaches 3.8 volts. Once the battery discharges to the storage voltage threshold, the Feather goes into deep sleep. When you see the display turn off, you can unplug and store the battery.
Overview
-
Fruit Jam Code Practice Oscillator
This is a Morse code practice oscillator for Fruit Jam with super clean sine wave tones and a 3d-printable straight key. The key uses a Kailh Cherry MX compatible keyswitch for reliable switching and flexures to make a precision hinge that works well when printed in PLA. Set screw adjustment lets you shorten the keyswitch travel. The audio output chain uses an
audiofilter.Filterto bandpass filter the output of asynthio.Synthesizerfor smooth note attacks and releases without keyclick.[Update: You can now use Button #3 to generate tones if you'd rather not build the 3d printed mx straight key (2026-01-07)]
Overview
-
NeoKey TOTP Token
This is a two factor authentication token to generate TOTP login codes for up to four accounts. You can select which account by pressing a key on the 4-key NeoKey keypad. The design is intended for desktop use in a safe location (wall power + no worries of physical tampering) but where you do want to prevent secrets from leaking over the network due to mis-configured cloud-sync backup features or whatever.
Design Goals and Features:
- Make the codes really easy to read and type, even in low light, by using a dimmable backlit TFT display with a relatively large font.
- Support 4 TOTP account slots (one for each key of a 4-key NeoKey keypad).
- The NeoPixel under the key for the currently selected account slot lights up. Pressing a different key switches the selected account. Pressing the selected key a second time puts the token in standby mode (backlight and NeoPixels off).
- Store secrets in an I2C EEPROM rather than in the CLUE board's flash. This makes it so the secrets aren't trivially accessible to a connected computer as USB mass storage files. This way, they won't get accidentally sucked into backups, and malware would have to work harder to access them.
- Set DS3231 RTC time from the USB serial console by opening the REPL, importing the
utilmodule, then callingutil.set_time(). - Add and manage TOTP accounts in the EEPROM's database of account slots by using similar REPL functions (
import utilthenutil.menu()). - Use the token fully airgapped after initial setup by powering it from a phone charger and reading codes off the TFT display.
Overview
-
CircuitPython Core Dev & Debug Tricks
This is an evolving collection of tips and tricks about working on the CircuitPython core and related libraries. Topics include code analysis and debugging, working with git and GitHub, maintaining documentation, and install/config for dev tools. Mostly these are notes to future-me, but perhaps they will also help other people who want to improve CircuitPython.
Control Flow Graphs
When you're getting started working on a new-to-you module of complex code, it can be pretty hard to build a picture in your head of how the code works just from reading the text. Fortunately, there are tools which can analyze source code and build actual pictures for you with directed graphs of which functions call which other functions.
Below are some examples of how I've been generating graphs of control flow between the various functions in CircuitPython's usb module and TinyUSB library dependency. To make the graphs, I use Debian with the
cflowcode analysis tool to generate agraphviz(.dot) graph file, then turn that into a PNG image to view with themirageimage viewer. Formirageto work, you need to run the last command in a terminal in X (vnc or physical display will work, but not ssh).shared-bindings/usb/*
-
IRC Display Bot
A CircuitPython IRC bot for Metro ESP32-S3 to show status notifications on a small dedicated screen.
This uses a 2.8" TFT display shield to show the topic of an IRC channel in large text. Combined with a local Raspberry Pi hosted IRC server, you can use this to make a wireless status notification system for environmental sensors or whatever. Once you put the wifi and IRC server details in your settings.toml, the display will connect automatically. Then you can use any IRC bot or client you like to set the channel topic to whatever should be shown on the display. For example, I built this to work with my serial-sensor-hub project which forwards USB serial sensor reports from my lora-greenhouse-monitor sensors.
Overview
-
3D-Printed Enclosure for IRC Display Bot
This is an enclosure I designed for an angled desktop notification display with a Metro ESP32-S3 and a 2.8" TFT display shield. I'm using this as an IRC client to run my irc-display-bot code for LoRa temperature monitoring, but the same hardware build would easily work for other CircuitPython IoT projects where you want a little desktop status display.
I designed this in Blender using geometry nodes to build up a model of the negative space for the Metro, display shield, and cutouts for the viewable screen area and cable ports. The only mildly tricky thing about it was that it's important to use the "Mesh Boolean" node with the "Exact" algorithm to join objects. If you use the Geometry Join node, or a different algorithm, the resulting geometry will be messed up and not usable as a cutting tool with the boolean difference modifier.
To learn about the code I'm running for the IRC display bot, check out my IRC Display Bot Playground guide.
Overview
-
LoRa Wireless Greenhouse Monitor
This project uses 900 MHz RFM95W LoRa FeatherWing modules to transmit temperature measurements from greenhouses and receive them at a base station about half a kilometer away. The base station hardware outputs sensor reports over USB serial, an optional 2x16 Character LCD, and an optional ESP-NOW gateway.
The LoRa radio settings are tuned for extended battery life at a range of up to 500m in suburban or rural conditions (non line of sight with limited obstructions). With a fully charged 400 mAh LiPo battery and a 9 minute reporting interval, typical sensor runtime should be about 4 weeks (~22µA deep sleep current, ~2667ms of time per wake cycle, ~0.222 coulombs of charge per wake cycle).
To optimize the transmitter for running on a small LiPo cell, I used a Nordic nRF-PPK2 power analyzer to tune the firmware. Some of the power saving tricks I used include reducing the cpu frequency, putting the RFM95W radio in sleep mode, putting the MAX17048 fuel gauge in hibernate mode, and using ESP32-S3 deep sleep. To compare the impact of different changes, I took extensive measurements using Nordic's Power Profiler app with the PPK2 connected to the Feather board's battery jack and GPIO outputs.
Transparency note: Adafruit provided some of the parts I used for this guide (Thanks Adafruit!).
Related Projects
For logging, charting, and IRC status notifications, check out my related projects:
Overview
-
Exploring the Arduino App Lab Binary
Overview
To understand what the new Arduino UNO Q is about, I've been looking at the new the Arduino App Lab coding tool. The App Lab download page links to the source code at https://downloads.arduino.cc/app-lab-release/source-app-lab.zip, but the source seems incomplete. Among other differences, there aren't any build instructions or scripts in the source archive. So, I've been poking around trying to understand how the source works and how it differs from the binaries.
Highlights of what I found: You need a UNO Q board to get past the first screen. The app is written with Wails which uses Go for the backend and a web app for the frontend (similar to Electron, but using a native web view rather than embedding a browser). The binaries include embedded markdown for examples that don't appear in the source. The app may be using Hotjar telemetry for analytics.
Download Checksums
When I downloaded the macOS dmg, Linux tar.gz, and source-app-lab.zip files on October 16, 2025, these are the checksums I got:
-
Fruit Jam Portable MIDI Synth
[Update 2025-10-13: revised for CircuitPython 10.0.1, including a fix for the stuck notes issue]
This is a minimalist polyphonic square wave synth for Fruit Jam that's intended for portable use with a USB power bank. The only output is audio to the board's headphone jack. The only input is from a USB MIDI controller connected to the board's USB host port. To set the volume, you can edit the code.
The main interesting thing about this project is that it demonstrates how to make a CircuitPython synth with MIDI events coming from the USB host interface rather than a USB device interface or UART MIDI. Also, this works as a good stress test of the CircuitPython USB host stack in combination with audio output using I2S and synthio.
This code was developed and tested on CircuitPython 10.0.0-beta.0 with a pre-release rev B Fruit Jam prototype which uses a different I2S pinout from the current rev D boards. Keep in mind that what's written here may be out of date by the time CircuitPython 10.0.0 is released and the production revision of the Fruit Jam board becomes available in the shop.
Related guides: Fruit Jam USB Host MIDI Tester, Fruit Jam Gamepad Tester
Transparency note: Adafruit provided the Fruit Jam rev B prototype board I used for this guide (Thanks Adafruit!).
Overview
-
Pasting in Hard Mode with VNC and SSH
My main computer is a Mac, but I run third party dev tools on a separate Debian box so they can't mess up my main computer. To control the Debian box from the Mac, I use SSH and VNC over Ethernet. The VNC session runs an Xfce desktop environment.
Mostly the remote control setup works great, but it's a pain to copy from macOS and paste to apps running in Xfce (macOS Screen Sharing VNC client app doesn't do clipboard sync). For example, suppose I want to copy text from Chrome on the Mac and paste it into VS Code on Debian. Since I can't paste directly into the VNC client, I must go through an SSH shell where pasting works fine.
In the past, I've used SSH to paste into
vimand make a temporary file. But, today I figured out a better way where I can send text directly to the Xfce clipboard from my SSH shell:Notes:
- If you don't already have
xclipinstalled, you'll need tosudo apt install xclip - The
cat <<'EOF'stuff is using bash's heredoc string syntax. Note that in this case the single quotes around EOF are telling bash not to do its normal variable substitution. This is useful if you want to copy and paste code that includes bash variable syntax, perhaps as part of a Makefile. In this case,${WHATEVER}will get passed through toxcliprather than being evaluated as a variable substitution by bash. - I have TigerVNC server configured to set
DISPLAYto:1. Since the instance of bash that's running in my SSH shell is is not part of an X session, it doesn't know about TigerVNC's display. I have to tellxclipwhichDISPLAYto use, otherwise it would get mad and complain with an error message.
- If you don't already have
-
Fruit Jam Two Gamepad Demo
This is my third iteration of a CircuitPython USB host gamepad tester, now with support for two controllers. The main loop in code.py uses asyncio to improve code readability. There's a new boot keyboard to gamepad mapper. For hot-swapping controllers, I devised an unplug detection heuristic to work around limitations in the current CircuitPython USB host implementation. Player numbers get assigned according to Fruit Jam top plate silkscreen port numbers. Player 1 gets USB 1, and Player 2 gets USB 2.
This demo project is meant to help folks who want to make Fruit Jam libraries for writing games. I don't plan to make a library on my own, but I wrote this code with library-making in mind in case somebody else wants to. Note that some of the performance and stability workarounds included here may become unnecessary once USB host implementation bugs get fixed.
The code here was written and tested with CircuitPython 10.0.0-beta.2 on a rev D Fruit Jam that I bought from the first production batch that went up in the shop.
Related work:
- Fruit Jam Gamepad Tester guide (my previous gamepad tester)
- Fruit Jam Fruitris (Tetris) game guide by @relic-se
- Feather TFT Gamepad Tester with Sprites guide (my original gamepad tester)
Overview
-
Fruit Jam USB Host MIDI Tester
This is a CircuitPython-in-the-middle MIDI filter and visualizer project for Fruit Jam. When you plug a USB MIDI controller into the Fruit Jam, MIDI input events will be shown on the DVI visualizer display and echoed on the usb_midi output port to the Fruit Jam's host computer. You could use this as the starting point for a USB MIDI filtering project.
The note visualizer has a grid of channels and notes to cover the range of a full size piano (midi notes 21 to 108). Dots indicate a note that hasn't played yet. Note-On messages turn the dot into a white rectangle. Note-Off messages turn the rectangle black. It works like a 1-bit heat map showing which notes and channels are active. Pitch bend, CC, aftertouch, etc. get shown as text in the bottom left of the visualizer and echoed to the serial console. USB host port connection status gets shown in the bottom right of the visualizer.
This code was developed and tested on CircuitPython 10.0.0-beta.0 with a pre-release revision B Fruit Jam prototype. Keep in mind that things may change by the time CircuitPython 10.0.0 is released.
Related guide: Fruit Jam Gamepad Tester
Transparency note: Adafruit provided the Fruit Jam rev B prototype board I used for this guide (Thanks Adafruit!).
Overview
-
Fruit Jam Lines Screensaver
This is a twisty-lines CircuitPython graphics toy inspired by screensavers from the 1990's (Macintosh After Dark 2 NightLines, Windows 95 Mystify, etc). To make the trail of lines, the code keeps track of two bouncing-ball style points and draws a line between them. Each new line gets added to a list, and the oldest line gets dropped off the end. The line colors cycle through a color swirl palette generated from a gradient using the LCh color space. This is meant for picodvi video output on RP2350 boards including Metro RP2350 and Fruit Jam.
To learn more about how I generated the rainbow swirl color palette, check out my Fruit Jam Color Gradient Generator Playground guide from last week.
This code was developed and tested on CircuitPython 10.0.0-alpha.7 with a Metro RP2350 (no PSRAM version) and a pre-release revision B Fruit Jam prototype. Keep in mind that things may change by the time CircuitPython 10.0.0 is released.
Transparency note: Adafruit provided the Fruit Jam rev B prototype board I used for this guide (Thanks Adafruit!).
Video Demo
-
Fruit Jam Color Gradient Generator
This generates rainbow swirl color palettes in the LCh color space for picodvi displays on RP2350 boards. You can use the WASD keys on the serial console to adjust the Lightness and Chroma, but hue angle is generated automatically. The point of this is to make palettes for Metro RP2350 or Fruit Jam that will look good for making color swirl animations.
The default picodvi video mode is hardcoded to 320x240 16-bit, using an 8-bit bitmap and a palette of 256 colors selected from the 65536 possible RGB565 colors. On boards with PSRAM (Fruit Jam), you can edit the code to use 320x240 32-bit for smoother gradients.
This code was developed and tested on CircuitPython 10.0.0-alpha.7 with a Metro RP2350 (no PSRAM version) and a pre-release revision B Fruit Jam prototype. Keep in mind that things may change by the time CircuitPython 10.0.0 is released.
Transparency note: Adafruit provided the Fruit Jam rev B prototype board I used for this guide (Thanks Adafruit!).
Overview
-
Fruit Jam Hypotrochoid Spiral Maker
This draws hypotrochoid spirals (like Spirograph) for a picodvi display on Fruit Jam or Metro RP2350. I tested this on a Fruit Jam rev B prototype and a Metro RP2350 (no PSRAM version). The 320x480 8-bit video mode works on both, but 640x480 8-bit seems to need a board that has a PSRAM chip. The curves get plotted as individual pixels using a color ramp that cycles through the entire 8-bit RGB332 palette. This might be useful to people looking for sample code showing how to configure picodvi displays for RP2350 boards.
For more details on the math for Hypotrochoid curves, you can check out the Wikipedia or Wolfram MathWorld Hypotrochoid pages.
Transparency note: Adafruit provided the Fruit Jam rev B prototype board I used for this guide (Thanks Adafruit!).
Overview