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.
-
Weather Display Using Open-Meteo's API The OM Weather Display periodically updates and displays the following local weather conditions:
- Day, date, and time (AM/PM)
- Tomorrow's sunrise and sunset times
- Temperature
- Relative Humidity
- Wind speed and direction
- Wind gust speed
- Condition description and graphic icon
Location, time zone, and measurement units settings are stored in the
settings.toml
file. Either "METRIC" or "IMPERIAL" measurement units can be specified.Weather condition query and internet clock refresh interval rates are set by parameters in the
code.py
module. The default interval for updating weather conditions is 5 minutes. The local time is updated from the Adafruit Network Time Protocol (NTP) server hourly.The CircuitPython code runs on an ESP32-S3 4MB/2MB Feather attached to a 2.4-inch TFT FeatherWing. An optional ALS-PT19 ambient light sensor can be used to automatically adjust display brightness.
CircuitPython Code
The Weather Display's CIRCUITPY root directory contains the following files and folders.
- files:
- settings.toml -- Wi-Fi and location parameters
- om_query.py -- OM API URL query string builder
- who_to_map_icon.py -- parses the WMO weather code for descriptions and icons
- code.py -- the primary code module
- folders:
- fonts -- contains the font files
- icons_160x160 -- the weather icon bitmap graphics files
- lib -- the CircuitPython library modules
- sd -- a placeholder for the unused SD storage drive
A downloadable bundle of code files and folders can be found in the OM Weather Display GitHub repository.
-
Guide: Build a 'MiniMarquee' WiFi Text Scroller Materials
The following parts are used to build the MiniMarquee:
- QT Py ESP32-S2
- IS31FL3741 13x9 PWM RGB LED Matrix
- 50mm Stemma QT cable
- Black LED acrylic, 2-3 mm thick, cut to 41mm x 29mm
- 4 M2x12 nylon screws and nuts
- Little rubber feet
- Nitto double-sided adhesive tape (or other tape with similar adhesive strength)
- 2 1-ounce wheel weights (optional)
Installing Firmware
The MiniMarquee's firmware is written for Arduino in PlatformIO. There are two ways to install the firmware onto the QT Py ESP32-S2:
- Drag-and-drop UF2 installation
- Build source code and install onto device
The UF2 method is recommended, as it is very simple and does not require downloading any additional software or dealing with any code at all. However, if you wish to customize your MiniMarquee's firmware, you'll need to go for option 2 and build it from source.
-
Circuit Playground: Galaxy Explorer Galaxy Explorer
Here's a project that combines ideas from my one-dimensional arcade game and orrery project. Think "1930's pulp science fiction" and you'll get the idea: The Circuit Playground lets you navigate a galaxy defined in a 100 element array with around 60 stars. You can stop at any one of the solar systems and observe an orrery-like display of the movement of the planets.
For me, the fun here is creating a UI with the CPX controls:
The program has three states:
travel - move through the galaxy
stop - choose a star displayed on the ten neopixels
explore - goes into orrery mode showing the planets in the chosen star-systemWhen in travel state, the A and B buttons increase the speed of the movement of the stars. A: clockwise, B: counter-clockwise. Multiple clicks increase the speed.
When in stop state, the A and B buttons move a blinking white pixel to select a star. A:move counter-clockwise, and B:clockwise. (yes, the opposite of travel mode).
Change state by pressing A+B - state cycles from travel to stop to explore and back to travel. In stop mode, you cannot move to explore unless the blinking pixel is on one of the stars.
At any point, shifting the switch to the left, turns off all the neopixels and switches the system to travel mode.
When the switch is shifted to the left, shaking the CPX will show all neopixels in green and generate a new galaxy.
Both versions, CircuitPython or Makecode work the same.
The generation of the galaxy creates two 100 element arrays. One defines the stars, and the other the "type" of solar system. When in explore mode, the defined colors and speed of the planets is set based on an algorithm.
Files
- explore.js - or makecode version: https://makecode.com/_Wt9P3udHMKjR
- explore.py - copy to code.py on a Circuit Playground with CircuitPython
1940 "Planet" Pulp SF magazine cover -
CNC Rotary Encoder Internals I was working with one of Adafruit's CNC Rotary Encoders and made a mistake wiring. Well, long story short, I killed it. I am not sure exactly what I did, but I suspect I accidentally drove its outputs with an improper voltage.
To prevent the experience from being a total loss, I took the time to partially disassemble it.
The plastic cover around the screw terminals can easily be removed, exposing a PCB. 3 pins hold this PCB onto the rest of the assembly. After desoldering them, the component side of the board can be seen.
The board features a "7550" voltage regulator. The incoming supply is regulated down from whatever it is to 5V for the internal circuitry. C2 is the input smoothing capacitor, and C1 is the output smoothing capacitor.
D1 and D2 are light emitting diodes in series (likely IR) which are positioned under matching sensors in the upper part of the assembly. A "331" (330Ω) resistor limits the current through the LEDs.
The 3 soldered positions are a supply and 2 returns from the sensor package in the upper part of the assembly. Resistors R2 & R3 are pull ups, while caps C3 and C4 smooth out any spurious transitions of the signals. It seems most likely that the sensor assembly consists of two phototransistors, which can pull the pins of the "HC14", a schmitt-trigger inverter. This creates the signals A and B at a dependable logic level, and also the inverted A/ and B/ signals.
Diode D3 is a reverse current protection diode; in case VCC and GND are swapped, no current can flow. Interestingly it's on the GND side, while I thought it was more common to see on the VCC side.
If I cared to determine which component(s) I damaged, this is totally a board that could be reworked by hand. However, I don't plan to spend the time and instead will just pick up a fresh encoder from the store—and double check my wiring next time.
-
Zephyr Quest: Troubleshooting a Pi Pico2 build error As part of a series on Zephyr with Adafruit hardware, this guide documents the process I used to diagnose a problem with building Zephyr's hello_world sample app for Raspberry Pi Pico 2. By the time you read this, there's a good chance the Zephyr folks may have already fixed the problem that tripped me up. But, perhaps my troubleshooting process will be a useful reference.
TLDR: Use
west build ... -- -DCONFIG_PICOLIBC_USE_MODULE=y
to build picolibc from source, or delete the~/.cache/zephyr
cache directory.The Linker Error
Working towards the goal of writing a new board definition for the Adafruit Feather RP2350, I've been looking at how the device tree setup for the existing Raspberry Pi Pico 2 board definition works. When I got around to trying to build the hello world sample app for the Pico 2, which also uses the RP2350, I got stuck on a linker error.
Below, I've included a console log which is a bit long. But, it shows some interesting details. The main error messages come in pairs that follow this pattern:
...arm-zephyr-eabi/lib/./libc.a(strcmp.S.o): conflicting CPU architectures 17/2
...ld: failed to merge target specific data of file ... /libc.a(strcmp.S.o)
After the console log, I'll explain how I tracked this down and found a workaround.
-
Greenhouse Temperature Logger This guide shows how to build cheap data loggers to help keep plants happy in greenhouses or other indoor growing spaces. I developed this design to help a community garden group control temperatures in greenhouses for starting new plants in winter. By charting the temperatures, we were able to identify and fix problems with air sealing and heater thermostat settings. This logger design uses manual data collection over USB serial because there is no WiFi at the greenhouses.
Wiring
If you are unfamiliar with soldering stacking headers, you might want to read:
Fritzing Diagram
This diagram shows the core circuit for the temperature logger, omitting the pin header and perma-proto stuff, and using a toggle switch to represent the jumper:
-
7" Sunton ESP32S3 8048S070 Circuit Python Very basic primer to get your 7" Sunton ESP32S3 8048S070 display up and running on Circuit Python with displayio.
Installation
Since this board only comes with a .bin from CircuitPython.org the easiest way to install Circuit Python is to have a full Python/PIP/ESPTool environment on your PC. Then you can run esptool.py. I have a section in my personal repository on the steps to flash an ESP device on a Windows PC once you have Python and PIP installed. The other method is to use the web installer on CircuitPython.org with a Google Chrome browser.
WCH (CH340) USB Serial
Unlike most Circuit Python boards the 8048S070 does not have native usb... there is no USB drive. It's more like a classic ESP32 where you have to communicate with it via serial only. If you miss the good old days of FTDI cables and serial (no one misses those days) then you'll feel right at home.
Device Manager CH340 Driver
After installing Circuit Python and getting the board recognized in device manager it should automatically install the CH340 driver. It's a good idea to double check the serial communication speed.
-
Adventure Engine: Mapping a World in a NeoTrinkey This project is my first draft of being able to squeeze an adventure world into the NeoTrinkey. Here's a link to the project repository. The code lets you build a map in a text file that defines a space to navigate. NOTE: the initial load of the repository had the wrong version of intput.py - the correct version is now in the repository.
Adventure-Engine
NeoTrinkey code for simple adventure gaming
- intput.py - pass a string "choices" to intpt(choices) and return one of the letters to calling routine. eg intpt("nsew") and you'll get back n,s,e,or w. This can be navigation.
- wise.py - choose a line from a text file. This file will be a linear list of an AxA array. Program will be used for description of current location
- advent.py - (code.py when running). Tracks user location in AxA array, calls wise.py to find and print location, then offers chance to move to N,S,E,W direction and retrieves choice from intpt(), calculates new location and prints it.
- prt.py - allows printing to REPL or via HID as typed output.
- ship.adv - sample map for a 3x3 ship
- magic.adv - sample map for a 5x5 magical realm. WRAP should be set to True, and radius to 5.
Code is a framework for having the NeoTrinkey navigate a space - dungeon, forest, spaceship.
Set map=[file name] of list of room descriptions
set radius=X where X is the size of the matrix. 3x3 or 5x5 for example
set px and py to starting room. eg. for a 3x3 map px=1 py=1 will set the start in the center of the map
set WRAP = True for the map being a torus, and False for the map having edges you can't go beyond.
sample map "ship.adv" defines a 3x3 map:communications bay|e cockpit|wse computer and navigation bay|w sleeping quarters|e wardroom galley|w storage|e engines|new power resources|w
Note some lines end with a "|" plus directions that can be followed from the room. If the room ends with "|e" for example, you can only leave to the East. If the line ends with no |+direction(s) the default is you can leave NSEW. (for example, the wardroom in this case).
The map below shows the rooms for ship.adv, and the gaps in the walls show which directions you can go. Only the wardroom allows passage in all four directions, NSEW.
When running, you are given "Current location:" and then offered the directions you can go. Touching pad #1 toggles between choices, touching pad #2 chooses the current one.
For example:Current location: wardroom Next action? nsew? n! Current location: cockpit Next action? wse ? w! s! Current location: wardroom Next action? nsew? n! s! Current location: engines Next action? new ? n! e! Current location: power resources Next action? w ? w!
# Magic Adventure Map
Here's another map, that is defined in the repository file "magic.adv"
-
Circuit Python Matrix Portal S3 NTP Clock Make a highly accurate Circuit Python Matrix Panel clock quick and easy with a Matrix Portal S3 microcontroller and a 64x32 Matrix Panel.
Skill Level: Beginner
Fonts and code updates can be found in my Github Repository.
-
Forward IO data to google sheets, using google forms (via 3rd party) 1. Create a new form at https://docs.google.com/forms/
2. Add some questions on the Questions tab, which use the Short Answer (simple values) or paragraph type (multi-line support).
3. On the Responses tab click the Link to Sheet button/link to set the responses to goto a sheet, create a new one or choose existing
-
Make Logic Analyzer Connector Blocks Do you have a logic analyzer like Saleae, or even one of those rp2040-based ones?
Do you hate plugging up all the signals when you want to use your logic analyzer on a multi-channel problem?
While working on RGB matrix support on the Pi 5, I sure did! But then I remembered that Adafruit has the parts I need to make some cables that are quick to connect & disconnect from my logic analyzer.
In my case, I'm plugging into a Rigol MSO1074, but I might also want to use my Saleae in the future, so I made up two 2x4 blocks. This way, I can use the connectors on either device.
It's quick and easy and best of all you don't have to crimp any connectors because the pre-crimped jumper wires are right there in the Adafruit store.
Start by grabbing the parts you need. Get a packet of housings for the "project end" and the "logic analyzer" end, as well as the correct jumper wires (male/male, male/female, or female/female) for the connectors.
For instance, I was connecting the 2 row male header of my logic analyzer to the 2 row male header on the Adafruit RGB Matrix Bonnet, so I used Female/Female jumper wires, a pair of 2x4 housings from the small dual row wire housing pack, and a single 2x10 housing from the large dual row wire housing pack. (there are actually 2x8 pins, but the 2x10 housing fits the space of the keyed connector better, reducing the chance of plug mistakes. A keyed housing would be better, but then I'd be off to digikey to look for one)
Now, tear off some wires from the set of jumper wires. I worked in groups of 5, so that each 2x4 housing for the logic analyzer end had 4 signal wires & 1 GND wire.
I connected 8 different signals, somewhat arbitarily: 4 RGB data lines, 1 address line, and 3 control lines.
Double check the position of each signal & GND, and make sure you have at least one GND signal (but more ground wires are better for signal integrity! The ideal is to have one GND between each signal)
Once you're satisfied you've got the correct wire at the correct position, insert the wire into the housing until it clicks firmly into place. The orientation of the crimped pin is important, it will only latch one way.
If you make a mistake, it's not the end of the world. Frequently it's possible to free a "locked in" connector. Here's the procedure I follow: First, push the pin as far forward in the housing as possible, opening a gap under the plastic latch. Then, carefully insert a jeweler's screwdriver under the latch. Then, pull back on the pin. When done properly, this frees the wire & leaves the latch intact. However, if you bend the latch out too far it deforms and will no longer retain a wire when one is re-inserted.
-
Zephyr Shell over USB or BLE + Bluefruit Connect Like Linux, Zephyr can route serial console streams to various hardware interfaces. This guide shows how to run the Zephyr Shell sample program on a QT Py ESP32-S3 using either USB serial or BLE with the Adafruit Bluefruit Connect app.
Prerequisites
To follow along with this guide, you will need:
- Linux computer running Debian 12, Ubuntu 22 LTS, Ubuntu 24 LTS, or similar
- Zephyr workspace including west and the Zephyr SDK's esp32-s3 toolchain (my Getting Started with Zephyr on Linux Playground guide explains how to set this up)
- Adafruit QT Py ESP32-S3 dev board (8flash/nopsram) with Zephyr bootloader (or you can use the ESP32 BOOT+RESET procedure to flash the Zephyr bootloader for the first time)
- iPhone with the Adafruit Bluefruit Connect iOS app.
-
Getting Started with Zephyr on Linux This is for folks interested in learning about Zephyr. The first section shows, step by step, how to work through the Zephyr Getting Started Guide to install Zephyr on Linux, build the hello world sample, and run it on an Adafruit QT Py ESP32-S3. The second part has notes for tuning the default settings to use fewer resources for faster CI builds.
What are Zephyr and West?
The Zephyr Real Time Operating System (RTOS) provides an abstraction layer that helps make it easier to port applications like CircuitPython to boards from various manufacturers.
In theory, using an RTOS makes it easier to implement features using audio synthesis, graphic displays, HTTPS, MQTT, BLE, etc. By building on top of Zephyr APIs, rather than vendor-specific SDK APIs, application code can ignore some of the differences between microcontroller families. Zephyr helps with low-level hardware details and coordinating CPU time for concurrent tasks including application logic, hardware IO, network stacks, and number crunching.
Zephyr has a command line tool called
west
to manage and coordinate the many tasks involved in working on a Zephyr project. Once you install west, you can dowest help
to see documentation on the available sub-commands. -
Cedar Grove Weather Architecture v2.0 Overview
The first version of the weather system architecture (Display AIO Local Weather Conditions: MatrixWeather System) worked nicely, but reliability suffered when the multiple transmitter and receiver devices competed to access the Adafruit IO (AIO) feeds. To prevent access collisions using the first architecture, each independent device was designed to only transmit or receive at fixed rates well below the AIO+ subscription rate limit of 60 data point transactions per minute. However, since each device operated autonomously, there were occasions when two transactions would heterodyne and stress the limit and cause feed failures.
To remedy the reliability issue, the new architecture design was switched from using MQTT to the HTTP protocol. Even though MQTT makes it relatively easy to "subscribe" to AIO feeds, HTTP provides more control granularity that includes a relatively new feature for independent devices to monitor feed access activity. Collisions can be avoided by watching how many data point transactions remain and waiting until enough are available for the queued transaction event.
The primary change to the architecture was to incorporate throttling. A secondary goal was to reduce the number of devices in the system by combining the existing Corrosion Monitor sensor with the REPEATER device, creating the new Weather SOURCE device. The Weather SOURCE extracts local weather conditions from AIO+ Weather and combines it with the local sensor's temperature, humidity, dew point, and corrosion detection data. Weather SOURCE then publishes the information to a collection of standard AIO feeds.
The other devices in the system are displays that extract data stored in the AIO feeds. One display replaces the existing Workshop Corrosion LCARS Monitor (PyPortal M4) that lives in the workshop and now is named Workshop Corrosion Monitor Display. The second is our living room MatrixWeather Display (upgraded from a Matrix Portal M4 to the S3 version). Since AIO feed access rates are monitored, it will be possible to create additional task-customized displays, perhaps for the studio or kitchen.
An advantage of the new architecture is that some display devices will not require large PSRAM for retaining the huge JSON file that AIO+ Weather provides, with the exception of a Matrix Portal. The single Source device with a large PSRAM extracts only the essential information needed by the displays -- and stores the extraction into the AIO feeds.
Weather Source
The primary source of AIO+ Weather and the local workstation temperature/humidity sensor used for corrosion detection. Weather and the local workstation conditions are sent to AIO feeds in the client's account to be retrieved by display devices.
This version of the Weather Source will be replaced by the Nuevo Combined Weather Source device sometime in late March 2025.
CircuitPython code can be found in the
Weather_Source/bundle
folder of the CedarGrove Weather System repository. -
GFFA - Aurebesh! I really enjoy coming up with new ways to combine my appreciation for Science Fiction linguistics with Adafruit products (especially the neotrinkey!) and CircuitPython. For this project I combined a classic tool "FIGlet" with the Aurebesh, the alphabet from the Galaxy Far, Far Away... (GFFA).
I started with FIGlet, the computer program that generates text banners, in a variety of typefaces, composed of letters made up of conglomerations of smaller ASCII characters. I modified an existing font file (standard.flf), replacing the letters a-z with my handmade versions of the letters seen above (note: anyone know of a good editor for FIGlet fonts? I'd love to improve the above).
That file was rather big for the neotrinkey - so I just extracted the Aurebesh and made it into an array for aure.py, a module to convert alphabetic English into Aurebesh. Then I made a program, aurebesh.py which could call aure.py's function doAure() for displaying different sayings or the alphabet, character by character - a useful training tool to become familiar with the alphabet. That's an important skill if you come across warnings like this:
All of this work went into a Github repository "Aurebesh" - from the Readme file:
-
Using a modified Figlet font ("standard.flf") I created aurebesh.flf, replacing a-z in the font with Aurebesh symbols.
-
I extracted the text for the a-z from Aurebesh.flf and made them into an array of texts for aure.py
-
aure.py has a function doAure(text,delay,REPL) - text = the text to display in Aurebesh, delay is how long between each letter, and REPL indicates if the output is to go to the REPL or, via HID, out as keyboard input.
-
aurebesh.py is a CircuitPython program that uses prt.py and ncount.py. Touching pad#1 will deliver one-by-one the alphabet, touching #2 will choose a random saying from sayings[] and print the English version, then the Aurebesh letters, one-by-one.
Notes:
Edit the variable REPL in aurebesh.py to True for text to show up in the REPL; make it False for text to be delivered as if typed. Edit the variable "sayings" to the list of sayings you want to display in Aurebesh.
Files (copy these all to your neotrinkey)
- ncount.py
- aure.py
- prt.py
- aurebesh.py -- copy this to "code.py"
If output is going out as if typed, the program will pause when started, blinking red till you touch one of the pads - this gives you a chance to move the cursor to the window you wish to receive the output.
Info:
Figlet: https://en.wikipedia.org/wiki/FIGlet Aurebesh: https://starwars.fandom.com/wiki/Aurebesh
-