I'm using CircuitPython and the FancyLED library by Phil Burgess to make a lovely color palette based animation for my necklace. If you want softly shifting mood light animations, this is the code for you.

I really like the FancyLED library for small color-shifting projects. At the time of writing, it's still a bit slow if you have a large number of LEDs. But for tiny projects like this, it works great and is very easy to customize with your own colors. 

The ItsyBitsy also works with Arduino or with Microsoft MakeCode, so if you prefer using one of those platforms, we have lots of tutorials and code samples in the Adafruit Learning System. 

We need to do a bit of setup to get the ItsyBitsy working with CircuitPython. Here's what's on this page:

  1. Install the latest version of CircuitPython on the board
  2. Install the necessary CircuitPython libraries
  3. Copy and update the Python code
  4. Save the code to your ItsyBitsy

Ready to start? Here we go!

Install CircuitPython

This guide tells you all you need to know about CircuitPython:

https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython

For now, I'll just cherry-pick the necessaries, but be sure to read through the guide to get all the nitty gritty details and troubleshooting tips.

Scroll down until you find the ItsyBitsy board you're using and click on it. Make sure you've got the right one - I'm using an M0, but there's also an M4 board option available.

Then click Download for the latest release. A file will download to your computer with a file extension of uf2. Take note of which version you downloaded.

Plug your ItsyBitsy into your computer with a USB cable. You may need to click or double-click the Reset button. The board will appear on your computer as a drive called ITSYBOOT. Drag the file you just downloaded onto this drive to install CircuitPython. The disk drive name ITSYBOOT will magically change to read CIRCUITPY.

Note: if you don't see ITSYBOOT, but instead see a drive called CIRCUITPY, that means CircuitPython is already installed. You probably still want to follow the instructions to update CircuitPython to the latest version.

Install Libraries

Now we need to install a few libraries onto our board as well. Here's a guide that tells you all you'll ever want to know about installing libraries:

https://learn.adafruit.com/welcome-to-circuitpython/circuitpython-libraries

I'll just hit the highlights again to get you up and running.

The above button takes you to a page where you can download the latest library release. Click the big purple button to do so.

Now go to your CIRCUITPY drive and create a new folder called lib. Unzip the Library bundle and find:

  • adafruit_fancyled
  • neopixel.mpy

Drag these two folders/files into your brand new lib folder.

Upload the Code

The last thing we need to add is a file called code.py on the CIRCUITPY drive. This is where the ItsyBitsy will look for actual instructions on what to do. Copy the code below into a text or code editor -- we recommend the Mu editor which can be downloaded here.

"""
FancyLED Necklace Insert Code
Written by Phil Burgess and Erin St Blaine for Adafruit Industries
Full tutorial: https://learn.adafruit.com/neopixel-led-necklace-insert-with-usb-charging

"""

import board
import neopixel
import adafruit_fancyled.adafruit_fancyled as fancy

NUM_LEDS = 15

# Define your palettes. Add as many colors as you like.
# You can use CRGB, CHSV or Hex format, or any combination therein
# Select which palette you're using below the palette definitions

palette_fire = [fancy.CRGB(0, 0, 0),        #Black
                fancy.CHSV(1.0),            #Red
                fancy.CRGB(1.0, 1.0, 0.0),  #Yellow
                0xFFFFFF,]                  #White


palette_water = [fancy.CRGB(0, 214, 214), # blues and cyans
                 fancy.CRGB(0, 92, 160),
                 fancy.CRGB(0, 123, 255),
                 fancy.CRGB(0, 100, 200),
                 fancy.CRGB(0, 120, 210),
                 fancy.CRGB(0, 123, 255),
                 fancy.CRGB(0, 68, 214),
                 fancy.CRGB(0, 68, 214),
                 fancy.CRGB(0, 28, 214),
                 fancy.CRGB(0, 68, 200),
                 fancy.CRGB(0, 68, 214),
                 fancy.CRGB(0, 200, 50),
                 fancy.CRGB(0, 200, 80),
                 fancy.CRGB(0, 200, 20),
                 fancy.CRGB(0, 100, 50),
                 fancy.CRGB(0, 150, 50),]

palette_forest = [0xa6db97,
                  0xc6de50,
                  0x2a7a02,
                  0x5fb862,
                  0x314a32,
                  0xd5e8d6,]

palette_cloud = [fancy.CHSV(0.8, 1.0, 1.0),
                 fancy.CHSV(0.6, 0.8, 0.7),
                 fancy.CHSV(0.7, 1.0, 0.8),]

#choose your active palette
palette = palette_water

# Declare a NeoPixel object on pin A1 with NUM_LEDS pixels, no auto-write.
# Set brightness to max because we'll be using FancyLED's brightness control.
pixels = neopixel.NeoPixel(board.A1, NUM_LEDS, brightness=1.0,
                           auto_write=False)

OFFSET = 0  # Positional offset into color palette to get it to 'spin'

while True:
    for i in range(NUM_LEDS):
        # Load each pixel's color from the palette using an offset, run it
        # through the gamma function, pack RGB value and assign to pixel.
        color = fancy.palette_lookup(palette, OFFSET + i / NUM_LEDS)
        color = fancy.gamma_adjust(color, brightness=0.25)
        pixels[i] = color.pack()
    pixels.show()

    OFFSET += 0.005  # Bigger number = faster spin

NUM_LEDs and Animation Flow

Once you have the code in your editor, look near the top and find this line:

Download: file
num_leds = 15

For the moment, change this number to reflect the total number of lights you have in your project.

Once your project is built and you're at the testing stage, come back here and make this number bigger, just to see the effect it has on the lights.

The code will automatically space your color palettes out to fill the total number of LEDs you have. If you have 7 colors in your palette and 7 pixels, you'll get one pixel per color. If you have 7 colors in your palette and 14 pixels, you'll get two pixels per color.

All the colors will be there, they'll just be more spread out. Since the palette is rotating along the strip, all the colors will eventually appear on the first 7 pixels. So, one quick and easy way to make the animation slower and smoother is to tell CircuitPython you have more NeoPixels than you actually have.

My necklace has just 7 pixels, but my final code pretends there are 15 pixels. This is a slightly hack-y way to fine tune the motion and color change, but it's really easy to do and works great! As long as your reported number of pixels is equal to or greater than your actual number of pixels, your lights will look fantastic. 

Don't make this number smaller than your actual number of pixels, or some of your pixels won't light up at all.

Customizing Palettes

I've added four different color palettes for the animations accessed from the Control Pad:  a "fire" and a "water" palette, plus "forest" and "cloud" colors. You can customize these fairly easily in the code. The power of the FancyLED library allows you so much control when it comes to choosing custom colors and animating them smoothly.

Find the palette definitions in the code:

Download: file
# Define your palettes. Add as many colors as you like. 
# You can use CRGB, CHSV or Hex format, or any combination therein
# Select which palette you're using below the palette definitions

palette_fire = [fancy.CRGB(0, 0, 0),        #Black
                fancy.CHSV(1.0),            #Red
                fancy.CRGB(1.0, 1.0, 0.0),  #Yellow
                0xFFFFFF,]                  #White
                  
  
palette_water = [fancy.CRGB(0, 214, 214), # blues and cyans
                 fancy.CRGB(0, 92, 160),
                 fancy.CRGB(0, 123, 255),
                 fancy.CRGB(0, 100, 200),
                 fancy.CRGB(0, 120, 210),
                 fancy.CRGB(0, 123, 255),
                 fancy.CRGB(0, 68, 214),
                 fancy.CRGB(0, 68, 214),
                 fancy.CRGB(0, 28, 214),
                 fancy.CRGB(0, 68, 200),
                 fancy.CRGB(0, 68, 214),
                 fancy.CRGB(0, 200, 50),
                 fancy.CRGB(0, 200, 80),
                 fancy.CRGB(0, 200, 20),
                 fancy.CRGB(0, 100, 50),
                 fancy.CRGB(0, 150, 50),]

palette_forest = [0xa6db97,
                  0xc6de50,
                  0x2a7a02,
                  0x5fb862,
                  0x314a32,
                  0xd5e8d6,]
            
palette_cloud = [fancy.CHSV(0.8, 1.0, 1.0),
                 fancy.CHSV(0.6, 0.8, 0.7),
                 fancy.CHSV(0.7, 1.0, 0.8),]

There are so many ways to define palettes. You can use CRGB values or CHSV values to choose colors, or use them both at the same time. You can also use HEX codes. There are also multiple ways to declare values and a lot of control over how spread out the gradients can be.

This is explained in detail in the FancyLED guide so take a look to find out all you need to know about creating your own custom color palettes.

My favorite way to pick colors is to use the Google Color Picker. Just drag the sliders to the color you want and you'll get the values to plug into your code.

Remember that lighter colors (with more white) will appear brighter when mapped to LEDs, and darker colors (with more black) will appear dimmer. 

Copy the HEX code from the colors. Get rid of the "#" and replace it with "0x" (as I've done in the palette_forest example above). Don't forget to put a comma between each color you choose.

Or, you can use the RGB values it gives you. Look at the palette_water definitions to see these being used.

HSV color values are available in the color picker too, but they don't correspond exactly to the HSV values that CircuitPython is looking for. It's possible to modify them to work, but easier to stick with RGB or HEX if you're a beginner.

Select Your Palette

Download: file
#choose your active palette
palette = palette_water

Just below the palette definitions you'll see a place to choose which palette you want to use. I like to save multiple palettes in the code so I can re-use the code on multiple projects, and just change this one line to get a totally different color gradient.

Save Your Code

Save the code on your CIRCUITPY drive, called code.py.

CircuitPython has a slightly different paradigm than Arduino or MakeCode. It works more like a USB stick, where you save the file to the drive and the code can be opened and edited directly on your microcontroller. You can even save multiple versions of the code on the CIRCUITPY drive if you'd like. The one you call code.py will be the one that runs. 

This guide was first published on Sep 16, 2020. It was last updated on Sep 16, 2020.
This page (Software) was last updated on Oct 20, 2020.