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.
-
Project Nyota Language tools for NeoTrinkey
Inspired by Star Trek's Nyota Uhura, these programs provide a way to use a NeoTrinkey to review alien (or foreign) language words or phrases. They are all contained in my github archive Project Nyota.
There are two programs, langtutor.py and langtest.py - copy the one you want to use to code.py. The helper files wise.py and prt.py are required.
The file "langs" is a list of the languages to review. Each line in "langs" should be the name of a file containing language information. In this archive the languages are: klingon, vulcan, mandoa, and Swahili (in honor of Uhura - "Nyota" means "star" in Swahili).
Language files should be in the form:
"Word-or-phrase", "target-language-translation" "Word-or-phrase", "target-language-translation" "Word-or-phrase", "target-language-translation" ....
When either program runs, you'll see:
number of languages: 4 klingon vulcan mandoa swahili Current lang: klingon
To toggle between languages, touch pad #1. When you reach the one you want to review (for the langtutor.py program) touch pad #2 and you'll see 5 random review pairs. For example from the Mando'a set:
You're right. : Gar serim. twenty : ad'eta seventy : tad'eta eighty : shehn'eta Good. : Jate.
With the langtest.py program, when you choose a language and touch pad#2, you'll get four tests where you're given a word or phrase, then a choice of two possible answers in the target language. Touch #1 or #2 to choose. A pixel will light green or red to indicate if you are right or wrong. (If wrong, the correct answer will be given). After four questions, you can touch #2 to get four more, or touch #1 to change languages.
For example:
Current lang: vulcan advise 1:lahso 2:a'Tha correct! walk (action-word) 1:imroy 2:lahso yes! 'logic', reality-truth, the way things are. 1:c'thia 2:lahso wrong: c'thia 'immanence' direc experience of the creator 1:kah-hir 2:a'Tha correct! touch #2 for another quiz, or #1 to change language.
When running the programs, you can set the variable REPL to "True" or "False" to direct the output. If REPL=True, all output is sent to the REPL. If it is False, output is directed as if typed using the HID interface. There is a delay when that is the case, to give you time to switch to an open editor window to receive the output.
Note:
Copy all these files to the neotrinkey: langtutor.py, langtest.py, wise.py, prt.py, langs, klingon, vulcan, mandoa, swahili. Then copy langtutor.py or langtest.py to code.py to run.
Language sources:
- Swahili vocab from: https://www.fluentin3months.com/swahili-words/
- Mando'a vocab from https://mandoa.org/ Note: the Mando'a language from Star Wars was developed originally by the author Karen Traviss for the Mandalorian people
- Klingon vocab from: https://kli.org and https://hol.kag.org
- Vulcan vocab from: https://tinyurl.com/VulcanArchive - archive.org of Marketa Zvelbil's original Vulcan work (note: In case archive.org is not available, I've copied the Dictionary and Lexicon to vulcdict.txt and vulcanlex.txt)
- To create your own language, you can use a tool like this: https://rollforfantasy.com/tools/language-generator.php
Nyota Uhura -
Display AIO+ Local Weather Conditions: MatrixWeather System The objective of this project is to replace the existing WeatherMatrix project's MatrixPortal M4 display with a newer version that uses weather data provided by Adafruit IO Plus (AIO+) instead of the openweathermap.org web API. The requirements include:
- Implement with CircuitPython for ease of development and prototyping.
- Duplicate the existing 64x32 LED matrix display layout including label colors and icons.
- Develop an architecture to support multiple autonomous displays and local data feed devices (new).
- Utilize a weather data source that accurately aggregates station information that closely matches local conditions.
- Weather data updated approximately 3 times per hour and is reliably available.
- Service subscription is free or reasonably priced.
- Include data elements for wind gusts and local workshop temperature (new).
- Display a progress bar to indicate data time since last update (new).
- If possible, use the existing MatrixPortal M4 hardware; upgrade to MatrixPortal S3 only if necessary.
Special Acknowledgements
Thank you to John Park for the initial weather display design concept (see Weather Display Matrix) that inspired this project. Also, the work of Trevor Beaton was instrumental in creating the updated display design with a clearer and simpler coding approach (see itsaSNAP Daily Weather Forecast Board).
Choose a Weather Observation Source
Three options for sourcing weather data were considered. Here are some pros and cons of each.
openweathermap.org:
- utilizes the existing or similar web API; minimal code changes will be needed
- weather station aggregation often doesn't always match local conditions
- data retrieval throttling is reasonable with a consistent service level
- free service was phased out; will eventually require paying for the service
weather.gov:
- a moderately well-documented web API; moderate code changes will be needed
- weather station data is not aggregated and closely matches local conditions
- single weather station data is not reliably available, sometime for hours at a stretch
- data retrieval throttling is currently reasonable, but without a guaranteed service level
- a free service
AIO+ Weather (Apple WeatherKit):
- moderately well-documented CircuitPython library approach; major code changes will be needed
- weather station data is aggregated and matches local and iPhone conditions
- data retrieval throttling is reasonable with a consistent service level
- weather data and workshop conditions can be combined and viewed on a web-based IO dashboard
- requires a paid subscription to AIO+ for access to its Weather Service
The choice to use AIO+ Weather was an easy one since my existing weather tracking and corrosion monitoring projects require a subscription to AIO+. We'll need a new system design and a major rewrite of the existing MatrixWeather project code to make this happen, providing ample opportunities to improve performance and reliability. The next step was to redesign the overarching weather system architecture.
See weather.gov: A Truly Free Weather API and AIO+ Weather: A Premium Alternative for Local Observations for a detailed discussion of each alternative.
-
Installing Python 3.13 using uv I use Debian Linux; the current stable version of Debian has Python 3.11.2. At the time I write this, Python 3.13 has just been released. So I used my desire to try out the new Python as a chance to explore uv as well. My instructions here are tested on Debian Linux, but may work with modifications on other Linux-based systems like Ubuntu or Raspberry Pi OS.
What's uv, anyway?
uv is "An extremely fast Python package and project manager, written in Rust." It's on github and pypi and is also well-documented.
Among its many features, uv is capable of managing multiple versions of Python, so I decided to use it to test drive Python 3.13.
Installing uv via pipx
First, install the pipx command using the operating system package manager. (debian package name: pipx)
Then, install uv:
pipx install uv
Once you've done this, you should have the
uv
command available. However, you may see a warning like this: -
Pumpkins vs Skeletons Game for CircuitPython This is a game about skeletons, pumpkins, and a catapult having a Spooky experience under the full moon. If you've thought about making a game in CircuitPython but aren't sure where to start, this project might be a useful source of ideas.
Charging a Pumpkin
This is how it looks when you hold the USB gamepad's A button to charge up a pumpkin.
-
Keyboard Featherwing Messenger powered by LVGL Several years ago Solder Party released the Keyboard Featherwing, a PCB that combines a Blackberry keyboard, a 320x240 TFT resistive touchscreen display, a 5-input DPAD, 4 tactile buttons, a microSD card reader, and more, all driven by an Adafruit Feather board of your choice. Eventually these were discontinued, I'm assuming because of the difficulty of sourcing the increasingly rare Blackberry keyboards. I didn't know what I wanted to do with them at the time, but I knew I was gonna want to do something with them at some point, so I ordered several of them before the stock was depleted.
One popular use for the Keyboard Featherwing has been to pair them with LoRa radio transceivers, to create a set of "Doomsday Messengers". These are devices that are able to send short text messages to each other using radio signals, sort of like walkie-talkies, but for text messaging. This makes sense: with the tactile keyboard, huge display, and instant compatibility with the Feather ecosystem (including the ability to use rechargable LiPo batteries), the Keyboard Featherwing practically seems designed for the use case!
I hacked together a quick demo a few years ago allowing for very basic communication between the devices, and then promptly lost interest. I wanted to write firmware that allowed for robust, reliable communication between the devices, but I also wanted something offering some of the affordances of a modern smartphone UI. If you've ever worked on UI for microcontrollers, you probably realize there are a lot of challenges. One of those challenges can be figuring out how to write a custom, complex UI with just the basic drawing functions provided by the commonly available drawing libraries. While possible, it can be really cumbersome once you start to want more modern UI features, such as widgets, scrolling, animation, multi-screen interfaces, and so on. Another challenge is implementing all of that in a performant way, given the limited speed and memory of most microcontrollers. At the time, I wasn't sure how I was to accomplish this without pulling my out my hair, so the project was put on the back burner.
Recently I decided to dig these up and give it another shot. I still wasn't sure exactly how I was going to do it, but I did have a concrete feature set in mind:
- The ability to send encrypted, reliable messages between two paired devices using LoRa technology
- The ability to pair each device with any other device using the same hardware and firmware, via a settings screen (i.e., no re-compilation needed to pair devices)
- The ability to modify and persist device settings and a small message history across power cycles
- Granular battery monitoring; specifically the ability to see the percentage of battery life remaining at any given time
- Heavy focus on physical controls, using the touchscreen to supplement the UI only where practical and/or necessary (if you aren't familiar with any of my previous projects, I'm a huge fan of physical controls)
Which Feather?
-
E-Ink Countdown in CircuitPython with Custom Stand Along the way I learned a few things:
- How to take an Adafruit PCB design in Eagle format and import the board outline all the way into FreeCAD for locating dimensions and features
- How to make my code robust against transient errors like network errors
- How to make my code deep sleep for the right length of time
There are also a few things this code demonstrates that are less common knowledge:
- Using fonts from the font bundle
- Using the datetime module for arithmetic on dates & times
- Increasing reliability by re-trying operations that can fail
- Reducing battery usage by deep sleeping and avoiding connecting to WiFi
This project uses FreeCAD & KiCAD, both of which are Open Source software that are free to download & use.
Parts Needed
Code & Installation
I recommend using Adafruit circup to install the needed libraries for projects. Here's what you need to do:
- Install circup on your desktop computer
- Enable the "fonts bundle" by running this command (just once, circup remembers this setting):
circup bundle-add adafruit/circuitpython-fonts
- Copy code.py to your CIRCUITPY drive (Download it via the "raw" link at https://gist.github.com/jepler/b2c020a6caa65a31297053b7216fcc15)
- Run the following command to auto-install required libraries:
circup install -a
You'll also want to configure wifi on your device using settings.toml. For lower power usage, configure WIFI_SSID and WIFI_PASSWORD options. For web workflow but higher power usage, configure CIRCUITPY_WIFI_SSID and CIRCUITPY_WIFI_PASSWORD options.
-
Creating Reduced Sized Bitmap Fonts From .ttf File ... using FontForge
Because CircuitPython uses bitmapped fonts (.bdf) as well as the binary .pcf format but many free fonts online are in .ttf format, following the Custom Fonts for CircuitPython Displays learning guide I came up with a cheatsheet to quickly take a full font, select only the limited characters I wanted and generate a small .bdf file. As I only do it once in a while if I don't write it down I wouldn't remember. Below is all covered in the above linked learning guide, but I wanted a quick and dirty cheatsheet, so here it is.
-
Open .ttf font file in FontForge
-
Select characters wanted including space before the “!” (you may need to scroll up). This is important and is missed in the learning guide example screenshot. Without selecting the ASCII 32 spot before the "!" character you won't have a way to display a space, so your display willlooklikethis. See first graphic below showing red box of missing space character you want to be sure to select.
-
Besides the basics of numbers, letters, and punctuation, be sure to select any others you want. I have noticed many .bdf fonts, including CircuitPython's built in terminalio.FONT, don't include a degree symbol (e.g. 78°F will display as 78F) even though many projects people create include temperature. So grab that symbol plus others that might be useful such as ± as another example.
-
Edit -> Select -> invert selection (selects everything you don’t want).
-
Encoding -> Detach & remove glyphs… (everything you don't want is removed)
-
Element -> Simplify -> Simplify and click OK on the warning box.
-
Element -> Bitmap Strikes Available…
-
In 3rd field, Pixel Sizes, enter size you want to create. For example if you want a 36 pixel font then type "36" (the first two fields will auto fill with values). Note that when you create a .bdf file you are only creating a file for that one pixel size.
-
File -> Generate Fonts…. Pick location to save then click Generate. Accept default of Other = 96.
To create other sizes go to step 7 and change the pixel size to the next pixel size file you want to create from the same font and characters already selected earlier. For example if you had just created a 36 pixel font, now change it to 24 in step 8 and generate the new file (step 9). Repeat for as many sizes as you need.
Finally if you really want to make the files small, following the online instructions using the web based Adafruit tool you can convert the .bdf files you just created to even smaller .pcf files. As an example, a (downloaded from Adafruit but further reduced by me) Arial-Bold-36.bdf font which was already a very compact 25kB on my disk got reduced further to a Arial-Bold-36.pcf file of only 16kB.
-
-
Set your sensor polling frequency to anything - WipperSnapper + API "testing" Adafruit IO I work on Adafruit IO, and I've had this mischievous plan for a while to adjust my WipperSnapper no-code sensor devices to poll more frequently than the 30s minimum that the web interface offers, like maybe as low as 5seconds to avoid burning my toast (having recently tried measuring the particle emissions again but found it too infrequent).
So Saturday morning I was having a prod at the firmware (you can too as it's open source code) and watching the API calls in the network monitor to see where gets prodded when the user changes a sensor to read every 30s.
-
Launching from DS9!!! Anyone who has seen the miniature 3D printed Trek and Star Wars ships hanging over my workbench (thanks, Thingiverse!) won't be surprised how many of my projects take an SF bent. But I've also got a space station!
And that inspires this Circuit Playground Express project - launching probes into the Bajoran Worhmhole!
I've got a repository for the code at DS9-game:
There are three files, two CircuitPython, and one JavaScript (or you can follow the makecode.com link)
- ds9.js - Javascript/Makecode version of game (https://makecode.com/_KhmDoYXCpVdh)
- ds9.py - CircuitPython version (rename to code.py)
- bach.py - helper code for music and sounds for ds9.py
It is a pretty simple game using the Circuit Playground circle of neopixels.
The premise is the space station Deep Space Nine (a blue neopixel) is in motion near the Bajoran Wormhole (a neopixel of shifting color). As the station shifts back and forth, the wormhole remains the same distance (five neopixels away). The station is launching automated probes to the wormhole - A sends them counter-clockwise, B sends them in a clockwise direction. You have ten probes to launch - if they successfully enter the wormhole, there will be a rainbow of neopixels across all ten. When you have sent all ten, you'll see pixels representing how many you managed to send into the wormhole (0-10). For the Makecode version, shake the CPX to restart. For the CircuitPython version press A or B.
Both versions make a sound when launching the probe, and will play a scale or musical flourish when you succeed. To turn that off, slide the switch to the left. To the right turns the game sounds on.
I found the differences in coding Makecode and CircuitPython versions interesting. With Makecode I could have multiple "forever" loops handling different actions - toggling Booleans to activate/deactivate them. With CircuitPython I used a single game loop and controlled the movement of the probe with a Boolean and a counter (it can only go 4 steps). The same Boolean prevents the A/B buttons from launching more than one probe at a time.
Give it a try - see how many you can get to land in the wormhole!
-
Create a Looping Apple Shortcut for Sending Data to itsaSnap Recently I've been experimenting with Apple Shortcuts to interface with the new itsaSnap app. This app lets you interface with Adafruit IO feeds on your phone. With Apple Shortcuts, you can get data from your phone to Adafruit IO. You can, for example, send health data, weather data, even encoded photos.
One topic that comes up in Apple Shortcuts is not being able to easily create an automated Shortcut that loops. For example, having data be sent every 30 minutes. There is a time automation, but you have to setup an automation instance for every time you need the Shortcut to run.
I wanted to figure out a way to do this and found a helpful post on the Apple Shortcuts subreddit that describes using alarms as a workaround. I normally avoid Reddit but that particular subreddit has had very helpful posts with folks sharing their Shortcuts and tips for folks to accomplish what they're looking for.
Flow Chart
I've adapted the suggested Shortcut from the subreddit post a bit. I've found that wrapping my head around the logic can be a little tricky, so here is a visual explainer before we get into building out the Shortcuts.
-
Feather TFT Clock with Gamepad Input This clock project uses USB gamepad input to control its time setting menu. The display uses TileGrid sprites that I made in Krita. The code demonstrates how to use timers and a state machine to build an event loop with gamepad input, I2C real time clock IO, and display updates.
Overview and Context
This clock is a step along the way on my quest towards learning how to build little games and apps in CircuitPython. The look for the display theme is about digital watches and alarm clocks from the 80's and 90's.
Some of the technical bits and pieces from this project that you might be able to reuse in your own projects include:
Menu system for manually setting time and date
USB gamepad input system with edge-triggered button press events and repeating timer-triggered button hold events
Data-watch style display theme with three display areas: 20 ASCII characters at the top, an eight digit 7-segment clock display in the middle, and another 20 ASCII character display at the bottom
Main event loop with gamepad button polling, real time clock polling, state machine updates and display updates
-
Prime Time Python! I think prime numbers are like life. They are very logical but you could never work out the rules, even if you spent all your time thinking about them - Mark Haddon, The Curious Incident of the Dog in the Night-Time
At some point, I realize I consider the Circuit Playground kind of a multi-tool - sensors, inputs, sound output, control of motors and more... actually, maybe more like Doctor Who's Sonic Screwdriver....
This week I worked to reconfigure my CPX to search for prime numbers because... why not? With my memory of the Sieve of Eratosthenes it took no time to find Python code to adapt for CircuitPython. In fact the code pretty much ran fine from the start.
First though, I made a version for Makecode - essentially using the Python code as a model. And then I made the CircuitPython version - actually two versions. More on that later. (And, yes, there is a NeoTrinkey version as well).
It is all in this repository : Eratosthenes
- ESieve.js - MakeCode/Javascript for finding all primes < 1000 https://makecode.com/_H5qFx46rYF1c for Makecode version
- ESieve.py - CircuitPython for finding all primes < 1000 - copy to code.py
- ESievePlus.py - CircuitPython for finding all primes < 8000 - copy to code.py
All three of the above will flash colored lights while searching for the prime numbers. When done, A will pick a random prime and display it, first in binary, then digit-by-digit in decimal version. Pressing B will step through all of the primes it found, displaying in binary. Touch A1 to display the last random prime it found in the random selection from pressing A.
The coding of binary values uses the ten neopixels - Green for 1's and Blue for 0's
NeoPixel: 0 1 2 3 4 5 6 7 8 9
Value: 1 2 4 8 16 32 64 128 256 512
The digit-by-digit display of a number lights up yellow pixels to show a value, with the rest of the pixels blue (so for 0 they all are blue).
- neosieve.py - neotrinkey version (copy to code.py)
- ncount.py - support file for neosieve.py
NeoTrinkey version. It finds all primes < 1000. First it flashes colored lights while searching, then, when done, touching pad #1 will display a random prime digit by digit with binary coding. Touching pad #2 will redisplay the last random prime found.
The "digits" displayed use the binary coding I had in the RRPN Calculator project:
All of the Circuit Python versions (neotrinkey or Circuit Playground), if connected to Mu or a similar IDE, will print information to the REPL.
Code based on https://www.geeksforgeeks.org/python-program-for-sieve-of-eratosthenes/ - MakeCode version written from scratch recreating the algorithm followed in that sample Python code.
Challenges
It seemed ... paltry to ONLY do the primes < 1000 but creating a Boolean array of more than 1000 ran into memory limitations. To fix that, in ESievePlus.py, instead of an array of Booleans, I created an array of 1000 8 bit numbers, initially set to 255 (11111111 in binary) and wrote functions to clear bits (indicating NOT prime) and another to test whether individual bits were 1 (prime) or 0 (not prime).
This introduced another problem - numbers greater than 1023 need more than 10 bits to display - so I modified the showbin() routine to shift all the pixels when displaying the higher bits.
Note: Since it takes a while to display hundreds of prime numbers when you push the B button (over a thousand for the ESievePlus.py version!) - the A button is an easy way to sample the primes that were found.
NeoTrinkey Binary Values -
Work in Progress: Feather TFT Clock This is an update on my current work in progress. I'm making a clock that will use gamepad buttons to set the time and date. The look is about 80's and 90's LED alarm clocks and digital watches. My larger goal is to explore making USB gamepad controlled GUIs in CircuitPython.
For now, I'm deciding how I want time and date setting to work, including how the final sprites will look. To watch my video progress update, click through to the full post.
Video Progress Update
-
Orrery: Put a solar system in your pocket! For hundreds of years, the clockwork orrery has been a way to demonstrate the movement of planets around the sun - as Wikipedia describes them: "An orrery is a mechanical model of the Solar System that illustrates or predicts the relative positions and motions of the planets and moons, usually according to the heliocentric model. "
It occurred to me that, the circular display of ten neopixels on the Circuit Playground might be a way to make a different kind of orrery... so I did. My programs are in this repository and consist of three programs:
-
orrery.js - Javascript/Makecode version for the Circuit Playground (https://makecode.com/_EHeh61h4Dcvo for the Makecode IDE version)
-
orrery.py - Circuit Python version for the Circuit Playground (copy to code.py on the device)
-
neo-orrery.py - Circuit Python version for the NeoTrinkey - again, copy to code.py on the device (you didn't think I'd leave the NeoTrinkey out did you?)
I opted to just do Mercury, Venus, Earth and Mars - adding more planets was too cluttered, plus the relative speeds of the inner planets are easier to see.
All versions start by showing Mercury (pale white), Venus (yellow), Earth (green) and Mars (red) as neo pixels moving at their relative speeds around the sun - from Mercury the fastest to Mars the slowest.
Each can switch to a random setting, changing the color and speeds of the four planets.
Makecode version: "A" stops/starts motion, "B" sets up a random solar system, and "Shake" resets to defaults.
Circuit Python Playground version: "B" sets up a random solar system and "A" resets to defaults
Circuit Python NeoTrinkey version: Touch pad #2 to get a random solar system and pad #1 to reset to defaults
NOTE:
The mechanics of the simulation are simple. Each program has a loop that increments a counter for each "planet." There is a table of periods for each planet, an integer that is 100 times the length of the planet year, so, for example, Mercury's period is 22 and Earth's is 100. When a planet's counter reaches the value of its period, the counter is cleared and the planet's position is advanced one position.
A small orrery showing Earth and the inner planets -
-
LED Pixel Mapping with WLED and LEDLabs Hello, my name is Erin St Blaine and I love making things that light up.
When I'm not writing tutorials for the Adafruit Learning System, I spend my time creating beautiful things, and exploring the meeting of art and technology whenever I get the chance. Over the last several years I've been focusing on creating larger scale LED artwork, home decor and chandeliers. I started out using Arduino with FastLED and learned to code the hard way, but nowadays there are so many software packages out there that I've been learning and exploring them. This article is about my experience of LED mapping my newest chandelier commission using WLED, PixelBlaze and LEDLabs.
What is Pixel Mapping?
Pixel mapping is a technique used to control and program individual LEDs or pixels within a lighting display, allowing each light to be addressed and manipulated independently. By mapping out the exact location of each pixel in a 2D or 3D space, artists and designers can create intricate patterns, animations, and effects that synchronize with the physical layout of the lights. This method is essential for creating dynamic, visually stunning displays, as it enables precise control over color, intensity, and timing across complex setups like LED walls, chandeliers, and sculptures.
A pixel map is needed when the LED layout is not precisely rectangular. Basically, a pixel map forces a non-rectangular shape into a rectangle that can be divided into rows and columns so the animations lay out correctly in the physical space.
My first foray into pixel mapping was making an LED Festival Coat using WLED. This was a fairly straightforward map -- the layout was generally rectangular, with just a few "holes" in the rectangle to account for -- I needed the map to fill in the arm hole areas so that my animations would look even across the whole coat. I used WLED for this, and found it to be a little mind-bending and tricky even with a simple map.
After the success of that project I decided to give mapping my chandelier a try. The chandelier is shaped like a hot-air balloon with eight spokes and no rectangles at all. This looked to be a challenge but I knew the end result could be absolutely stunning if I succeeded.