Neopixel Lighted Unicorn Night Light
I found an old glass unicorn I've had since I was kid while cleaning out some old boxes. It originally came with a white incandescent light and was a night light. I wanted to use it again but wanted it do more than just light up with a white light.
I have an Adafruit Circuit Playground Bluefruit (CPB) that has a built in Neopixel ring. Its the perfect size to light up my unicorn. So I generated a 3"x3"x2" box on MakeCase. If you haven't used it the site is awesome. It lets you enter the dimensions of your box, material thickness and what type of joints you want. It then auto generates a box and gives you either a .dxf or .svg output. You can put this in your laser cutter software and use it to make a box.
I left the bottom of the box open to add the electronics and cut a circle in the top of the box. I cut a clear piece of acrylic and etched the bottom to give it a frosted look. The box is five pieces plus the acrylic and assembles in about five minutes with some wood glue.
The code I used for the CPB is based on an Adafruit project for a lighted hat. I just didn't like the limited number of animations that were included. Adafruit has an animation library that includes more animations. The CPB also has a easy to used app that can be controlled from an iPhone or Apple Watch. It has built in buttons that you can assign functions. So the code was pretty easy.
Here is the code:
""" FancyLED Palette and Color Picker Control with BlueFruit App | |
Code by Phil Burgess, Dan Halbert & Erin St Blaine for Adafruit Industries | |
""" | |
import board | |
import time | |
import neopixel | |
import adafruit_fancyled.adafruit_fancyled as fancy | |
from adafruit_ble import BLERadio | |
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement | |
from adafruit_ble.services.nordic import UARTService | |
from adafruit_bluefruit_connect.packet import Packet | |
from adafruit_bluefruit_connect.button_packet import ButtonPacket | |
from adafruit_bluefruit_connect.color_packet import ColorPacket | |
from adafruit_led_animation.animation.blink import Blink | |
from adafruit_led_animation.animation.comet import Comet | |
from adafruit_led_animation.group import AnimationGroup | |
from adafruit_led_animation.sequence import AnimationSequence | |
from adafruit_led_animation.animation.solid import Solid | |
from adafruit_led_animation.animation.colorcycle import ColorCycle | |
from adafruit_led_animation.animation.chase import Chase | |
from adafruit_led_animation.animation.comet import Comet | |
from adafruit_led_animation.animation.pulse import Pulse | |
from adafruit_led_animation.animation.rainbow import Rainbow | |
from adafruit_led_animation.animation.rainbowchase import RainbowChase | |
from adafruit_led_animation.animation.rainbowcomet import RainbowComet | |
from adafruit_led_animation.animation.rainbowsparkle import RainbowSparkle | |
from adafruit_led_animation.animation.SparklePulse import SparklePulse | |
from adafruit_led_animation.animation.sparkle import Sparkle | |
from adafruit_circuitplayground.bluefruit import cpb | |
from adafruit_led_animation.color import AMBER | |
from adafruit_led_animation.color import PURPLE | |
from adafruit_led_animation.color import WHITE | |
from adafruit_led_animation.color import JADE | |
from adafruit_led_animation.color import PINK | |
from adafruit_led_animation.color import MAGENTA | |
from adafruit_led_animation.color import ORANGE | |
from adafruit_led_animation.color import TEAL | |
from adafruit_led_animation.color import RED | |
import adafruit_led_animation.color as color | |
#Color_choice is the variable used to change the color in each animation where the color can be changed | |
color_choice = JADE | |
#Sets the default animation to sparkle_pulse | |
sparkle_pulse = SparklePulse(cpb.pixels, speed=0.05, period=3, color=color_choice) | |
chase = Chase(cpb.pixels, speed=0.1, color=color_choice, size=3, spacing=6) | |
#effect variable is used to change the name of the variable in the animte command | |
effect = chase | |
#color_number is used to track the user input when changing the color | |
color_number = 1 | |
#Establishes bluetooth connection | |
ble = BLERadio() | |
uart_service = UARTService() | |
advertisement = ProvideServicesAdvertisement(uart_service) | |
# True if cycling a palette | |
cycling = True | |
while True: | |
# Advertise when not connected. | |
ble.start_advertising(advertisement) | |
while not ble.connected: | |
if cycling: | |
#set_palette(palette_choice) | |
effect.animate() | |
#offset = (offset + offset_increment) % OFFSET_MAX | |
# Now we're connected | |
while ble.connected: | |
if uart_service.in_waiting: | |
packet = Packet.from_stream(uart_service) | |
if isinstance(packet, ColorPacket): | |
cycling = False | |
# Set all the pixels to one color and stay there. | |
cpb.pixels.fill(packet.color) | |
cpb.pixels.show() | |
elif isinstance(packet, ButtonPacket): | |
cycling = True | |
if packet.pressed: | |
#Each button calls a different animation | |
if packet.button == ButtonPacket.BUTTON_1: | |
chase = Chase(cpb.pixels, speed=0.1, color=color_choice, size=3, spacing=6) | |
effect = chase | |
elif packet.button == ButtonPacket.BUTTON_2: | |
sparkle_pulse = SparklePulse(cpb.pixels, speed=0.05, period=3, color=color_choice) | |
effect = sparkle_pulse | |
elif packet.button == ButtonPacket.BUTTON_3: | |
comet = Comet(cpb.pixels, speed=0.01, color=color_choice, tail_length=10, bounce=True) | |
effect = comet | |
elif packet.button == ButtonPacket.BUTTON_4: | |
pulse = Pulse(cpb.pixels, speed=0.1, color=color_choice, period=3) | |
effect = pulse | |
# the UP arrow is used to change the color of the animation for every push of the button color_number | |
# increases by 1 | |
elif packet.button == ButtonPacket.UP: | |
color_number = color_number + 1 | |
print(color_number) | |
elif packet.button == ButtonPacket.DOWN: | |
rainbow = Rainbow(cpb.pixels, speed=0.1, period=2) | |
effect = rainbow | |
elif packet.button == ButtonPacket.LEFT: | |
rainbow_chase = RainbowChase(cpb.pixels, speed=0.1, size=5, spacing=3) | |
effect = rainbow_chase | |
elif packet.button == ButtonPacket.RIGHT: | |
rainbow_comet = RainbowComet(cpb.pixels, speed=0.1, tail_length=7, bounce=True) | |
effect = rainbow_comet | |
if cycling: | |
#the if statements check the color_number and set the color | |
if color_number == 1: | |
color_choice = JADE | |
print("Jade") | |
if color_number == 2: | |
color_choice = PURPLE | |
print("Purple") | |
elif color_number == 3: | |
color_choice = WHITE | |
print("WHITE") | |
elif color_number == 4: | |
color_choice = AMBER | |
print("AMBER") | |
elif color_number == 5: | |
color_choice = PINK | |
print("PINK") | |
elif color_number == 6: | |
color_choice = MAGENTA | |
print("MAGENTA") | |
elif color_number == 7: | |
color_choice = ORANGE | |
print("ORANGE") | |
elif color_number == 8: | |
color_choice = TEAL | |
print("TEAL") | |
elif color_number == 9: | |
color_choice = RED | |
print("RED") | |
elif color_number == 10: | |
color_number = 1 | |
print(color_number) | |
#execute the selected animation; the effect variable changes to set the animation | |
effect.animate() |
I 3D printed a holder for the CPB and added some wood blocks for mounting. I drilled holes in the wood blocks to attach to the box and screwed it in. I had also ordered a 3x AAA battery box with a switch for power. I plugged it in and added velcro to mount. This way I can easily pull the batteries out and recharged.
When assembled I had a compact modern lighted glass unicorn base I could control with remotely. See the video below for the assembly and to see it in action.
Leave a comment