Code the NeoPixel Controller with CircuitPython

CircuitPython is a derivative of MicroPython designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the CIRCUITPY flash drive to iterate.

The following instructions will show you how to program a PyGamer with the NeoPixel Strip Controller with CircuitPython, instead of MakeCode. The user interface looks a bit different from the MakeCode Arcade version, but perform the same functions.

Set up CircuitPython on PyGamer

If you haven't yet set up your PyGamer with CircuitPython, follow this quick step-by-step page:

You'll also want to install a code editor for use with CircuitPython. Mu is a simple code editor that works with the Adafruit CircuitPython boards. It's written in Python and works on Windows, MacOS, Linux and Raspberry Pi. The serial console is built right in so you get immediate feedback from your board's serial output!

Mu is our recommended editor - please use it (unless you are an experienced coder with a favorite editor already!)

Install CircuitPython Libraries

You'll need to install a few libraries used by the CircuitPython code.

First make sure you are running the latest version of Adafruit CircuitPython for your board.

Next you'll need to install the necessary libraries to use the hardware--carefully follow the steps to find and install these libraries from Adafruit's CircuitPython library bundle.  Our introduction guide has a great page on how to install the library bundle for both express and non-express boards.

You should manually install these necessary libraries from the bundle:

  • adafruit_cursorcontrol.mpy
  • cursorcontrol_cursormanager.mpy
  • adafruit_button
  • neopixel

Before continuing make sure your board's lib folder or root filesystem has the above files copied over.

Next connect to the board's serial REPL so you are at the CircuitPython >>> prompt.

CircuitPython Usage

To demonstrate the usage of the CursorControl library, we'll use the example below. Save the file below to a code.py file. Then, upload the code.py file to the CIRCUITPY drive.

# PyGamer NeoPixel Strip Control with CusorControl
# Adapted from PyPortal_NeoPixel_Color_Picker.py by Kattni Rembor
import time
import board
from adafruit_button import Button
import displayio
import neopixel
from adafruit_cursorcontrol.cursorcontrol import Cursor
from adafruit_cursorcontrol.cursorcontrol_cursormanager import DebouncedCursorManager

# Set the NeoPixel brightness
NEO_BRIGHTNESS = 0.3

# Set up the NeoPixel strip
strip = neopixel.NeoPixel(board.D3, 30, brightness=NEO_BRIGHTNESS)

# Turn off NeoPixels to start
strip.fill(0)

# Create the display
display = board.DISPLAY

# Create the display context
splash = displayio.Group(max_size=15)

# Button colors
RED = (255, 0, 0)
ORANGE = (255, 34, 0)
YELLOW = (255, 170, 0)
GREEN = (0, 255, 0)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
VIOLET = (153, 0, 255)
MAGENTA = (255, 0, 51)
PINK = (255, 51, 119)
AQUA = (85, 125, 255)
WHITE = (255, 255, 255)
OFF = (0, 0, 0)

# Button properties
btn_x = 40
btn_y = 40

spots = [
    {"label": "1", "pos": (0, 5), "size": (btn_x, btn_y), "color": RED},
    {"label": "2", "pos": (40, 5), "size": (btn_x, btn_y), "color": ORANGE},
    {"label": "3", "pos": (80, 5), "size": (btn_x, btn_y), "color": YELLOW},
    {"label": "4", "pos": (120, 5), "size": (btn_x, btn_y), "color": GREEN},
    {"label": "5", "pos": (0, 45), "size": (btn_x, btn_y), "color": CYAN},
    {"label": "6", "pos": (40, 45), "size": (btn_x, btn_y), "color": BLUE},
    {"label": "7", "pos": (80, 45), "size": (btn_x, btn_y), "color": VIOLET},
    {"label": "8", "pos": (120, 45), "size": (btn_x, btn_y), "color": MAGENTA},
    {"label": "9", "pos": (0, 85), "size": (btn_x, btn_y), "color": PINK},
    {"label": "10", "pos": (40, 85), "size": (btn_x, btn_y), "color": AQUA},
    {"label": "11", "pos": (80, 85), "size": (btn_x, btn_y), "color": WHITE},
    {"label": "12", "pos": (120, 85), "size": (btn_x, btn_y), "color": OFF},
]

buttons = []
for spot in spots:
    button = Button(
        x=spot["pos"][0],
        y=spot["pos"][1],
        width=spot["size"][0],
        height=spot["size"][1],
        style=Button.SHADOWROUNDRECT,
        fill_color=spot["color"],
        outline_color=0x222222,
        name=spot["label"],
    )
    splash.append(button.group)
    buttons.append(button)

# initialize the mouse cursor object
mouse_cursor = Cursor(display, display_group=splash)

# initialize the cursormanager
cursor = DebouncedCursorManager(mouse_cursor)

# Show splash group
display.show(splash)

prev_btn = None
while True:
    cursor.update()
    if cursor.is_clicked is True:
        for i, b in enumerate(buttons):
            if b.contains((mouse_cursor.x, mouse_cursor.y)):
                b.selected = True
                print("Button %d clicked" % i)
                strip.fill(b.fill_color)
                prev_btn = b
    elif prev_btn is not None:
        prev_btn.selected = False
    time.sleep(0.1)

After saving the code.py to your CIRCUITPY drive, you should see a cursor appear on your device's display along with 12 colorful buttons.

Move the cursor around by pressing the PyBadge's D-Pad buttons or moving the PyGamer's Joystick!

Move the cursor to a color and press the A button to click one of the buttons on the display. The NeoPixel strand will light up with the button's color.

Changing the cursor's speed

Is the cursor moving too slowly across the display? You can increase (or decrease) the cursor's speed by changing this line:

mouse_cursor = Cursor(display, display_group=splash)

to

mouse_cursor = Cursor(display, display_group=splash, cursor_speed=10)

Setting a larger cursor_speed will increase the speed of the cursor, setting a smaller cursor_speed will decrease the cursor's speed.

Changing the cursor's size

Having trouble seeing the cursor? You can increase the cursor's size by changing the following line:

mouse_cursor = Cursor(display, display_group=splash)

to

mouse_cursor = Cursor(display, display_group=splash, cursor_speed=10, scale=2)

Setting a larger scale value will scale the cursor in both dimensions. For example, when scale=2 each pixel will be represented by 2x2 pixels.

Code Overview

This code combines the CircuitPython CursorControl module with a pre-existing project - the PyPortal NeoPixel Color Picker. 

This guide was first published on Jul 26, 2019. It was last updated on Jul 26, 2019. This page (Code the NeoPixel Controller with CircuitPython ) was last updated on Nov 17, 2019.