In this project we'll use a Circuit Playground Express to light up a 3D print Christmas tree. The 10x on-board NeoPixels are perfect for lighting up all sorts of decorations and props. Our custom designed geometric Christmas tree is hollow with a thin walled shell. This allows internal light to nicely diffuse the shape. It's also designed to be 3D printed without any support material.

Circuit Python Code

Learn how to use Adafruit's Circuit Python to write code and light up the NeoPixel LEDs using colors and animations. Just download the latest UF2 for your CPX and get the latest library bundle to get started. Our demo code will get you up and running quick and easy!

A special 3D printed mount secures the Adafruit Circuit Playground Express and snap fits under the Christmas Tree. For best lighting effects, use translucent PLA filament to nicely diffuse NeoPixel LEDs.

Prerequisite Guides

There's resources in these guides that go beyond what's covered in this tutorial. The introduction guide is all about setting up your Circuit Playground Express board. The Circuit Python introduction guide walks you through all of the pinouts, sensors and everything you need to know.

USB Power

The Circuit Playground Express can stay connected via USB power from either a wall adapter or computer's hub. This allows the Christmas Tree to stay lit as long as you want (nightlight mode anyone?). The Christmas tree has a cutaway to accommodate for a USB cable. Lipo battery is optional and can be tucked in between the Circuit Playground Express and 3D printed mount.

Snap-On CPX Mount

This 3D printed mount is designed specifically secure the Circuit Playground Express (and Classic) without any hardware screws. Tabs on the sides grasp the edges of the PCB and hold it in place. Built-in standoffs elevate the PCB allowing room for a 500mAh lipo battery. The symmetrical design allows any orientation and provides cut aways for JST and USB connectors. 

3d_printing_cpx-mount-battery.jpg

3d_printing_cpx-mount-side.jpg

3d_printing_cpx-mount-bottom.jpg

3D Modeling CAD

The geometric tree was designed in Autodesk Fusion 360. The source file is available to download and features sketches and parametric timeline so it's free to tweak and modify.

3D Printed Parts

The tree is printed in a translucent filament to better diffuse the LEDs. A special dual color version was designed for dual extrusion setups. The starfruit tree topper requires support material, optionally split in half  print in two pieces and glue together. 

Dual Extrusion

Different colors can be used to create masking effects that reveal light using translucent colors. The black tree is a mix of Fillamentum's Verito Galaxy PLA and Translucent PLA for the rings – This creates a lighting effects that illuminates the rings around the tree. 

Delicious Filaments

For high quality prints we suggest good quality filaments from awesome manufacturers. Here's a list of the various filaments we used in this project.

Slice Settings

Use these settings as reference. Values listed were used in Ultimaker's CURA 3.X slicing software.

  • 0.2mm Layer Height / 0.4mm nozzle
  • 0.38mm Line Width (inner & outer widths)
  • 60mm/s printing speed
  • 20% infill

Multi-Purpose CPX Mount

This mount makes for a quick 3D print and provide decent support for making a simple and portable project. To remove the Circuit Playground from the mount, use fingers to pull apart tabs and push PCB outwards from underneath.

3d_printing_cpx-mount-top.jpg

3d_printing_cpx-mount-solo.jpg

Design Source Files

The tree and CPX mount was designed in Fusion 360. This can be downloaded in different formats like STEP, SAT and more. Electronic components like the board, displays, connectors and more can be downloaded from our Fusion 360 CAD parts github repo.

Setup Adafruit Circuit Playground Express for CircuitPython

We'll need to get our board setup so we can run CircuitPython code. First thing we'll need to do is connect the board to your computer with a microUSB cable. Then double-click on the reset button to put it in "UF2" boot-loader mode. The NeoPixels will turn green. The board will then show up as a USB storage device on your computer named "CPLAYBOOT". 

Follow the guide below to setup the firmware, once complete, come back here and proceed.

Download Adafruit CircuitPython Library Bundle

In order to run the code, we'll need to download some libraries. The download linked below will contain all the libraries available for Circuit Python. To run the code for this project, we only need a few. Unzip the downloaded file and look for the following libraries.

Required Libraries 

  • Adafruit Neopixel – neopixel.mpy
  • Adafruit Circuit Playground – adafruit_circuitplayground

Install Circuit Python Libraries 

Now that we have all of the libraries and know which ones this project needs, we'll need to copy them onto the Circuit Playground Express USB drive (which will be named CIRCUITPY after flashing the firmware). In the CIRCUITPY drive, create a new folder and name it "lib". Then, copy the libraries to that "lib" folder. The lib folder should contain neopixel.mpy and adafruit_circuitplayground.

Upload Code

OK, now it's time to upload the code for this project onto the CIRCUITPY drive. Create a new text document using a text app. Then, copy the code below and paste it into that newly created text document. Save that text document to the CIRCUITPY drive and name it "main.py". Once saved, the code will automatically run and will start working.

Editing Code

You'll want to use the Mu python editor to modify the code. 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! See the guide below to for download and setup instructions.

Circuit Playground Christmas Tree Code

# SPDX-FileCopyrightText: 2018 Kattni Rembor for Adafruit Industries
#
# SPDX-License-Identifier: MIT

import time
import board
import neopixel

# On CircuitPlayground Express, and boards with built in status NeoPixel -> board.NEOPIXEL
# Otherwise choose an open pin connected to the Data In of the NeoPixel strip, i.e. board.D1
pixel_pin = board.NEOPIXEL

# On a Raspberry pi, use this instead, not all pins are supported
# pixel_pin = board.D18

# The number of NeoPixels
num_pixels = 10

# Increase or decrease between 0 and 1 to increase or decrease the brightness of the LEDs
brightness = 0.6

# The order of the pixel colors - RGB or GRB. Some NeoPixels have red and green reversed!
# For RGBW NeoPixels, simply change the ORDER to RGBW or GRBW.
ORDER = neopixel.GRB

pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=brightness, auto_write=False,
                           pixel_order=ORDER)


def colorwheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    # Works with RGB or RGBW LEDs.
    if pos < 0 or pos > 255:
        r = g = b = 0
    elif pos < 85:
        r = int(pos * 3)
        g = int(255 - pos * 3)
        b = 0
    elif pos < 170:
        pos -= 85
        r = int(255 - pos * 3)
        g = 0
        b = int(pos * 3)
    else:
        pos -= 170
        r = 0
        g = int(pos * 3)
        b = int(255 - pos * 3)
    return (r, g, b) if ORDER in (neopixel.RGB, neopixel.GRB) else (r, g, b, 0)


def rainbow_swirl(wait):
    for j in range(255):
        for i in range(num_pixels):
            pixel_index = (i * 256 // num_pixels) + j
            pixels[i] = colorwheel(pixel_index & 255)
        pixels.show()
        time.sleep(wait)


def rainbow_fill(wait):
    for j in range(255):
        for i in range(num_pixels):
            pixel_index = int(i + j)
            pixels[i] = colorwheel(pixel_index & 255)
        pixels.show()
        time.sleep(wait)


def christmas_flash(duration):
    pixels.fill((255, 0, 0))
    pixels.show()
    time.sleep(duration)
    pixels.fill((255, 255, 255))
    pixels.show()
    time.sleep(duration)


while True:
    for _ in range(5):
        christmas_flash(0.5)

    for _ in range(5):
        christmas_flash(0.1)

    pixels.fill((255, 0, 0))
    pixels.show()
    time.sleep(1)

    rainbow_fill(0.001)  # Increase the number to slow down the rainbow

    pixels.fill((0, 0, 0))
    pixels.show()
    time.sleep(1)
    rainbow_swirl(0.001)  # Increase the number to slow down the rainbow

This guide was first published on Dec 19, 2018. It was last updated on Dec 19, 2018.