![](/assets/playground/adafruit_playground_1200x900-699010177a4a3fd6bac6bc31deae0bfa3eb9ea777ba62aaa5cbc1225bb45bfcc.jpg)
Adafruit Playground is a wonderful place to share what you find interesting. 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.
Adafruit Playground is a safe place to share with the wonderful Adafruit community of makers and doers.
Click here to learn more about Adafruit Playground and how to get started.
-
SevenSeg: Create an Instrumentation Vibe for Displayio SevenSeg is a CircuitPython displayio -compatible collection of four ultra-compact monospaced
.bdf
fonts that mimic the look of a seven segment LED display. To keep the font file size small, only the numeric characters that a seven-segment display can represent are included in the font, including uppercase and lowercase hexadecimal. Okay -- there are a couple of other useful things in there, too.Supported characters:
+ - . 0 1 2 3 4 5 6 7 8 9 : A B C D E F _ a b c d e f °
SevenSeg Font GitHub repository
-
Running Two Programs on a Single CircuitPython Device Running Two Programs on a Single CircuitPython Device
I have a nice e-ink display on my shelf running a CircuitPython program that updates the display every fifteen minutes. Recently I wrote a second program that would also just be ideal for this display.
Thinking about my options, I could either
- copy the relevant program to the MCU everytime I want to switch
- write a wrapper application for both programs
The first option was not attractive, because I want to switch on a regular basis. The second option also has it's problems. Both existing programs are valid stand-alone and are maintained in their own Github-repositories, so adding a wrapper would make changes to the software much more complicated.
So I was thinking about a sort of "boot-switcher". Users running Linux on their PCs often have a boot-manager that allows them to switch to more obscure operating systems once in a while, and I wondered if there is a simple way to use this concept also for a CircuitPython device.
Hardware Setup
Since a MCU neither has a BIOS that can start a boot-manager before the real OS, nor (usually) a mouse or keyboard attached for the selection of the target program, this solution needs a free GPIO and a slider or button.
Our "boot-manager" is the code in
boot.py
. This code reads the state of the GPIO and starts one of the programs depending on the value. Using a slider will result in a "sticky" behavior: unless you flip it again, each reset will start the same program. The button is different, since you have to keep it pressed during power-on/reset to start the second program. So the second program is more of an exception while the first program runs as the default.Software Setup
For the boot-switcher to work, the programs can't be deployed to the top-level directory of the CIRCUITPY-drive. Instead, the layout on the drive is like this:
So every application moves one level down into its own directory.
You can find the necessary
boot.py
in the Github-repo https://github.com/bablokb/cp-bootswitcher. In this file, you have to configure your setup, e.g.PIN_SWITCH = board.D1 APP_NAMES = ["_app0","_app1"] SHARED_FILES = ["boot.py"]+APP_NAMES
The names of the application directories don't matter, but you have to add the names to
APP_NAMES
. You can also add more files/directories toSHARED_FILES
, but all of these entries must be top-level. One use case for this is if your applications share the lib-folder.How does it Work?
The implementation of the boot-switcher turned out to be simple and during power-on or reset you won't notice a delay. The code in
boot.py
only checks the state of the GPIO and then moves all files from the top-level back to the appropriate application folder and then all files from the other application folder to the toplevel. Moving is a fast operation, since it only changes the entry in the directory-table (FAT), so moving a very large lib-folder won't be slower than movingcode.py
.Other Use-Cases
There are a number of other use-cases for the boot-switcher, e.g.
- providing two versions of an application, e.g. a beta version in addition to a productive version
- providing a special diagnostic application in addition to the normal application
- running the same application with two different configurations (e.g. within two different WLAN-networks)
- having two sets of libraries e.g. for CP 8.x and 9.x
Final Notes
If you only want to start different top-level programs and otherwise share the rest of your code and all settings, you don't need the boot-switcher. You can do this with a few lines of code, e.g.:
import supervisor ... supervisor.set_next_code_file("admin.py",sticky_on_reload=True) supervisor.reload()
Code within
boot.py
can do many things for you. For example, you can make the CIRCUITPY drive writable for your program or hide it for the PC. Of course you can also shoot yourself in the foot, so reading the documentation is recommended. -
Tiny Plaintext MIDI Sequencer for SAMD21 When playing with synthesizer patches, it helps to have a MIDI sequencer to generate note triggers for you. One option is to use a DAW on a laptop, like Ableton or whatever. But, it can also be nice to go DAWless with a hardware sequencer, because buttons and knobs and blinking lights are fun. With DIY sequencer projects in mind, I wrote a plaintext music notation sequencer module for CircuitPython, called txtseq.
The sequencer can read a song from a text file on your CIRCUITPY drive, parse the music notation into an array of MIDI note on and off events, then play the MIDI events in an event loop (allowing time to run other code). The music notation is loosely based on a subset of the abc standard. Notation for note pitch, accidentals, octave, and duration is very similar to abc. For everything else, the sequencer uses a simpler grammar and syntax that is easy to parse on a microcontroller.
-
Magicquest! Revisiting some of my Neo Trinkey experiments, I've been modifying code that no longer works with CircuitPython 9.x. This is another story generator I created using names and items generated with fantasynamegenerators.com.
Like "Tell me a story, Neo Trinkey" you get random stories by touching tab #2. Tab #1 chooses the hero name, class and race.
The repository is here
and includes
- magicquest.py - program file, rename to code.py
- prt.py - helper file for prt("text",REPL) function. REPL=True to send output to REPL and False for keystroke output
Data files for story input :
- destination.mq
- enemy.mq
- forest.mq
- names.mq
- treasure.mq
- weapon.mq
Load these on your NeoTrinkey and you can get stories like this:
The dwarf burglar Polo Littlefoot
gets lost at
Corftey Fortress
discovering Black Magic Tome
Polo Littlefoot is surprised when The Black-Eyed Cinder Spider attacks from Jagged Covert
Stumbling badly, Polo Littlefoot somehow manages to find the Mournblade, Gift of Ancient Power and dispatch them!
No, not great literature, but I had fun creating it!
note: illustration above from
https://www.publicdomainpictures.net/pictures/190000/velka/medieval-fantasy-castle-2.jpg
-
Raspberry Pi Pico Dice Programmed with CircuitPython Add more fun to your board games by creating an electronic die!
-
SerialFruit Connect - A bookmarklet to replace Adafruit BlueFruit Connect apps + Add WiFi/USB/BLE for all! So what's this project for? Scott (CircuitPython Lead Developer a.k.a @tannewt on GitHub and Discord) has been working on ESP32 bluetooth in Circuitpython and I'm excited, so much so I wanted to test out the Bluefruit related projects in anticipation of the upcoming ESP support. I read a bunch and then thought surely we can do that with web workflow, or even web-BLE (bluetooth connections in the browser)...
Click a button in your browser and a magic panel appears on code.circuitpython.org or your web workflow circuitpython device. That panel expands to reveal all the same* screens and functionality as the Adafruit Bluefruit Connect mobile apps (plus extras), but accessible to WiFi users for the first time! *Soon there will be BLE and USB and WiFi support for all the screens/functions of the mobile app, but for now I decided to get started recreating John Parks "CircuitPython BLE Rover" which uses the Bluefruit Connect "ColorPacket" and "ButtonPacket" type of packets (the only ones I've tested so far).
-
Adafruit Connection Manager What is the Adafruit Connection Manager? It is a helper class designed around making connections to the internet easier and does this by simplifying a few things.
First, what are the underlying pieces we need to connect to the internet?
Sockets
Everything that connects to the internet needs a socket. A socket is what handles the basic sending and receiving of messages between 2 devices (like your microcontroller and a web API).
Microcontrollers, unlike desktop computers, have limited memory and can't have 100s of sockets open. The average chip can have maybe 2-3 and the bigger ones top out around 10.
Previously the sockets were controlled at a per library level. Meaning if you used
adafruit_requests
(to get info from the web) andadafruit_minimqtt
(to send something to AdafruitIO) they both managed sockets separately, which means that one might block the other from getting one. And on top of that, the way you interfaced with them was different!Here comes ConnectionManager to the rescue! Both these libraries now ask the ConnectionManager for a socket and it handles tracking what's open and what's not. And to make code even simpler, it's what's called a singleton. There is only one, where previously you needed to create your
requests.Session()
early in your code and use that one everywhere, now it doesn't matter.Socket Pool and SSL Context Helpers
What are these?
The
socketpool
is what creates the sockets for each internet connected chip, and thessl_context
is what has all the certificate information to validate that the connection is secure. -
Get Radio I've been spending a bunch of time testing code across different MCUs and networking chips. It started with my work with Connection Manager. Then I was digging into Requests and MiniMQTT . Which of course lead me to places like NTP, AzureIoT and AWS_IOT.
As I jumped around, I needed a way to always get the right radio. Sometimes it's native WiFi, which is easy:
wifi.raidio
, but other times, it's some SPI based FeatherWing or maybe a M4 with and AirLift (talking to youPyPortal
andMatrixPortal M4
)...Introducing:
get_radio
It's not perfect, and I'm guessing there are things I haven't thought of, but it works for me so far.
The only thing a normal developer, with the right libraries installed and only one radio needs to do is:
-
Mandelbrot on a Neotrinkey? ... It's Complicated. It's no secret that I keep trying to think of new things to do with the NeoTrinkey. One day, for some reason*, I wondered if it would be possible to render the Mandelbrot set in ascii... with a NeoTrinkey.
Since the NeoTrinkey runs CircuitPython and since many, many projects are shared online in Python... it seemed reasonable to assume I could find code that would help me do this. And I did - I found a github project by "LadyClaire" : https://github.com/claiire/python-mandelbrot - this seemed exactly like what I wanted.
Except... well, I said it was "complicated." The math to render the Mandelbrot set involves manipulating points on the complex number plane and Python easily does such math, CircuitPython doesn't.
Which meant I couldn't just run LadyClaire's code - I needed to write my own complex.py module that let me do the work. Import complex.py and you get:
- absC - returns absolute value of a complex number
- plsC - adds two complex numbers
- sqrC - squares two complex numbers
- mltC - multiplies a complex number by a number
- mltCC - multiplies two complex numbers.
- mltI - multiplies a complex number by i
With those functions, I could tweak the code into mandelbrotx.py - adding in some blinking lights (you need ncount.py). The mandelbrotx.py module (which you'll rename code.py) has a variable REPL - REPL=True directs the output to the REPL, REPL=False sends it out as keystrokes.
When you run the program you need to touch pad #2 to start the rendering - you'll see lights blink as each row is calculated. When it's done you'll see the image at the top - generated not by some supercomputer... but your friendly, NeoTrinkey!
*Note: I know the reason, it's because I follow a Mastodon account, [email protected], which posts random images from the Mandelbrot set.
-
Look Ma, No Microcontroller! (Night Light Edition) Inspiration
This is a piece of "found art"; a multi-colored circuit board hiding inside some old discarded electronics. It just needed a backlight and a frame to highlight its beauty. From the beginning, I knew this would become a nightlight and held onto the board until I had acquired the perfect combination of discarded LEDs and a few other components needed to make it shine.
-
Web API's & You - An uncomprehensive & comprehensible guide to using Adafruit Requests with web API's.
The amount of online API examples for the Adafruit_Requests library is growing. If you're interested in using an API but an example does not exist and you're unsure how to start I will help walk you through the process.
I wrote the majority of the web API examples currently in the examples directory. I'm a pretty good source on how to approach a new unknown web API and wrangle out some basic data.
JSON
Data is malleable, it can be shaped and formed in a variety of ways. The most common format currently used with REST API's is JSON. The Adafruit_Requests library is particularly good with JSON data. If you don't know how to read or write in JSON don't worry, you won't need to. The library handles all the format conversions for you. All you need to know is how to get at the data you want and I will walk you through how to do that.
Before we begin there are some glossary terms that you'll need to know in order to make sense of JSON for the web.
REST
Representational State Transfer (REST) is a software architecture that imposes conditions on how an API should work. Most web API's use the REST architecture. All a beginner needs to know about REST is it's the way a website allows you to retrieve data from an API.
Endpoint
An endpoint refers to the data to retrieve from an API. This can be part of the JSON heirarchy path or a key:value pair. For web API's typically this refers to the JSON Key:Value pair.
Key:Value
- Key:Value (always a pair separated by a colon)
A key is a unique identifier associated with data and the value is the actual data. An example would be if you're working with a weather API and might want to return current:temperature for a geographic area to display freedom units on a TFT. It would return as `current:70.0` (in Fahrenheit) or if you're living in a sensible country using the metric system it would return `current:21.1` (in Celsius).
Key Error
It's useful to know the above terms because an error that a website or Circuit Python might return is `invalid key:value pair` or simply `key error`. That error means you requested a key:value that does not exist, you spelled it incorrectly, or the request was otherwise incorrectly formatted.
-
Babel - Let's make some Alien words!! Here's another silly NeoTrinkey project - let's make some alien words!
babel.py - generates "alien" words using a set of rules for Wookie, Klingon, Vulcan, Mando'a and Romulan.
ncount.py - blinks numbers
Touching pad #1 toggles between the five languages, and blinks the number (1..5) for the language choice. Each language defines a set of consonants, vowels and an array of word patterns (V for vowel, C for consonant, v 50% chance for a vowel, c 50% chance for consonant). When you touch pad #2, a list of words (random quantity, 1 to 10) is created following the rule sets. The rule sets were created using known words from those languages.
Change the variable REPL to direct the output: True means the program prints to the repl, False sends the output to the keyboard.
Example output:
Wookie: OUWA ROR HOH AROOAUW HOUW WOH ORAUW ORUUUUR WOR OWOUOOR
Klingon: laq noegh tSyIm DIyS mI Ho jaab
Vulcan: su tuai tiustoa het' tiy k' t
Mando'a: ary reara 'hr syc tmn cor khc
Romulan: ihf ki'vh ies lu'm m'ih ih eenh hieh uek
Note: These are generated words, and only by coincidence match vocabulary in any real lexicons.
For fun you can replace my rule sets for any other alien or fantasy language you wish to create.
There's a hoopy frood who really knows where his towel is. -
Stuff My Dog Said (via AdafruitIO) Inspiration
This project is an extension of the original doggy buttons project where I'll be showing how to make a public dashboard that publishes everything my dog says. This project is just one example of how to extend the features of my doggy buttons and perhaps one of the silliest IOT devices ever made. If you want to know about the buttons themselves, see the original project writeup.
With a project like this, it's also important to think about privacy. I don't want my dog making it possible to tell when we're away from home, so I'll also show how to add a delay so that activity is only published once it's sufficiently stale. -
Getting QWIIC thru window, door, etc. A few hours ago, I saw an announcement of a new Adafruit product #5961, connecting Stemma QT/Qwiic connector to a breadboard.
I quickly realized that by having two of these, with headers soldered on (consider using right-angle headers for this), one can use "Flat Flexible Cable" ("FFC") AF04-5-ND from Digi-Key, along with Digi-Key crimp-on connectors 609-3512-ND, to connect something like a sensor on one side of a door/operating window/etc to a microcontroller on the other side.
The FFC is MUCH thinner than a normal Stemma QT/Qwiic cable, or indeed any sort of "ribbon" cable I've seen in my nearly 60 years of "doing" electronics, so the FFC is MUCH better at getting through doors/windows/etc. You may be familiar with FFC in a custom form (often called Flexible Printed Circuits) for connectors on various small displays.
I should mention that those "crimp on" connectors can be a tad bit ornery to get on. I usually find that a largish pair of "pump" pliers to do the ''crimping' and another pair of pliers to "convince" the side pieces to close will do the trick. Also, if you have a sensor exposed to the weather, you might want to consider adding some conformal coating (though the device and connections before applying the coating, and if your sensor includes humidity and/or barometric pressure, be sure to protect the "sensor hole" from the coating.
One instance of this that I've used the FFC for is a sensor outside a window while keeping an ESP-8266 safely on the window sill. I also have sensors inside both the fridge section and freezer section of my side-by-side with an ESP-8266 on top of the unit. (A fridge would make a pretty good Faraday Cage, so WiFi inside the fridge probably wouldn't work.)
-
NeoPixel Stick and Pi Pico Need to add a simple diagnostic display to a Pico project? Or perhaps you want a quick and easy NeoPixel light show? Let's see what we can do!