Create Your Own Animated Ornament with QTPy!
Written by Nick Biederman
With the holiday season in full swing, two things are sure to happen: 1) you'll want to do more holiday DIY projects, and 2) you won’t have time to do holiday DIY projects. Thankfully, the Neopixel Christmas ornament is a fantastic DIY project that won’t take long to put together. This is a simple project that requires minimal materials. We’ll be using a QTPy for its small size and will be powering the ornament via the USB port, but you can use almost any microcontroller and can power it with a battery if you’d prefer. It’s a great way to dip your feet into the CircuitPython ecosystem if you haven’t tried it out yet.
What You’ll Need
Materials:
- CircuitPython compatible Microcontroller (We chose Adafruit’s QTPy2040)
- 8x8 Neopixel Matrix
- Power Supply (We’ll be using a USB cable, but a battery would work well)
- Computer with a text editor (We used Notepad++ on Windows, but Mu is a more versatile option)
- Programming cable (This varies depending on the microcontroller you use. For the QTPy, a USB-C cable was required.)
- Hookup Wire
Tools:
- Soldering Iron and Solder
- Wirecutter and stripper
- 3D printer, laser cutter, or other method to manufacture a case
- Hot glue gun
How to Build Your Own Animated Ornament
CircuitPython Preparation
Start by downloading the most recent version of CircuitPython for your board. You can find it on the CircuitPython website. Next, hold the “boot” button on your microcontroller while plugging the microcontroller into your computer. You should see a new drive appear on your computer. Copy the CircuitPython file to the new drive and wait for it to reboot. After the microcontroller reboots you should see a handful of new files and directories.
Once CircuitPython has been installed you should see this file structure on your microcontroller.
Next, download the appropriate set of libraries for the version of CircuitPython you are using. You can find them here. They’re listed as “bundles” for 6.x.x or 7.x.x. Copy and paste the file “neopixel.mpy” and the directory “adafruit_bus_device” into the root of the lib directory on your microcontroller.
We need two libraries, which should be placed in the “lib” directory of the microcontroller.
Wiring
Now that we have our IDE (Or Integrated Development Environment - basically, where the programming will be created) set up, we can wire up our ornament. We’ll need 3 wires to the matrix: Power (5v), GND, and data. We’ll be connecting power and ground directly to our QTPy. This usually isn’t the best practice, but it works for our project, as we won’t be driving the LEDs at full brightness and are not working with many LEDs. For projects with more LEDs or LEDs operating at full brightness, you may need an external power supply. The data wire can be connected to any digital output pin on the microcontroller. I chose D2, which is labeled “A2” on the QTPy. All the code samples provided below assume you are also using D2.
With only 3 wires, there’s no need to use protoboard for this project.
Programming
Plug your microcontroller into your computer and navigate to the CIRCUITPY drive. Open the “code.py” file in your text editor, and copy and paste the following code into the file. Save the file. Your microcontroller will reboot, and if everything has been done properly you should see a nice gradient from red to green on your LED matrix.
import board import neopixel pixels = neopixel.NeoPixel(board.D2, 64) pixels[0] = (255, 255, 0) for i in range(64): pixels[i] = (i/4, (64-i)/4, 0)
If everything is set up properly you should see a nice gradient like this
If your matrix doesn’t light up, check your connections. If you’re using a pin other than 2 on your board you will need to change “Board.D2” in line 4 to the pin you’ve chosen.
Once we’re sure everything is working properly we can start drawing pictures. While it’s possible to draw an image in a program like Paint and display it on the matrix, I find it easier to create a matrix of RGB values by hand when working with small displays like this. The code below draws a simple Christmas tree with the image stored in an array named “image”:
import board import neopixel import time image =[( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),(255,255, 0),(255,255, 0),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),(255,255, 0),(255,255, 0),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),( 0,255, 0),( 0,255, 0),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0, 0, 0), ( 0, 0, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),(177, 76, 36),(177, 76, 36),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0)] pixels = neopixel.NeoPixel(board.D2, 64, brightness=0.05, auto_write=True) for i in range(64): pixels[i] = image[i]
The array “image” in the above code defines this Christmas tree image
You can change the image that’s displayed by replacing or editing the “image” array. Here’s one that draws a snowflake:
image =[( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 0, 0, 0), ( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255), ( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255), ( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0)]
The “image” array can easily be modified to define other figures, like this snowflake
The code is easy to understand, and can easily be expanded. For example, it can easily be modified to switch between two images as seen below:
import board import neopixel import time tree =[( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),(255,255, 0),(255,255, 0),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),(255,255, 0),(255,255, 0),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),( 0,255, 0),( 0,255, 0),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0, 0, 0), ( 0, 0, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0,255, 0),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),(177, 76, 36),(177, 76, 36),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0)] snowflake = [( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 0, 0, 0), ( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255), ( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255), ( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 0, 0, 0), ( 0, 0, 0),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 64, 64,255),( 0, 0, 0), ( 0, 0, 0),( 0, 0, 0),( 0, 0, 0),( 64, 64,255),( 64, 64,255),( 0, 0, 0),( 0, 0, 0),( 0, 0, 0)] pixels = neopixel.NeoPixel(board.D2, 64, brightness=0.05, auto_write=True) while True: for i in range(64): pixels[i] = tree[i] time.sleep(10) for i in range(64): pixels[i] = snowflake[i] time.sleep(10)
With some small changes, we can make an animated ornament
Closing it up
Now that we’ve assembled and programmed our ornament it’s time to put it in a case. We 3D printed a case using these files posted on Thingiverse. You could also use a laser cutter to build a box or make one from thick paper. Hot glue was used to hold everything in place, and the back pressed on without the need for glue. A bit of printer paper over the front can help diffuse the light and hide the circuit board, but we chose to leave ours exposed.
The case we used is a simple 2-piece design that offers plenty of room for a battery or larger microcontroller.
This quick project is a great way to add some extra light to your Christmas tree. With CircuitPython it’s easy to create dynamic lighting, and assembly is about as simple as it gets. The most time-consuming part is printing the enclosure, which took about 2.5 hours on an Ender 3 v2.
We’d love to see your ornaments and the images you come up with down below!
Looking for more Maker guides and ideas? We’ve got a full section dedicated to Maker as well as guides on How to Choose a 3D Printer, Understanding 3D Printer Filament Types, and New Projects for Old Raspberry Pis. And if you can’t find what you’re looking for, don’t hesitate to post a new discussion and the Community will be happy to help!
Comments
-
This looks like a super interesting little project.
Categories
- All Categories
- 1 The Blog
- 1 What's Trending
- 7.4K The Community
- 3K General Discussion
- 102 New Members
- 789 Consumer Tech
- 197 Prebuilt PCs and Laptops
- 154 Software
- 30 Audio/Visual
- 50 Networking & Security
- 4 Home Automation
- 5 Digital Photography
- 12 Content Creators
- 28 Hobby Boards & Projects
- 75 3D Printing
- 83 Retro Arcade/Gaming
- 60 All Other Tech
- 287 PowerSpec
- 2.5K Store Information and Policy
- 140 Off Topic
- 40 Community Ideas & Feedback
- 596 Your Completed Builds
- 3.6K Build-Your-Own PC
- 2.6K Help Choosing Parts
- 303 Graphics Cards
- 324 CPUs, Memory, and Motherboards
- 134 Cases and Power Supplies
- 50 Air and Liquid Cooling
- 46 Monitors and Displays
- 88 Peripherals
- 57 All Other Parts
- 62 Featured Categories
We love seeing what our customers build
Submit photos and a description of your PC to our build showcase
Submit NowLooking for a little inspiration?
See other custom PC builds and get some ideas for what can be done
View Build ShowcaseSAME DAY CUSTOM BUILD SERVICE
If You Can Dream it, We Can Build it.
Services starting at $149.99