Now we'll install the libraries that we need to run the code on the Circuit Playground Bluefruit.
Download the Project Bundle link in the code embed element below.
Uncompress the .zip file and then copy the following directories and .mpy files from the version of CircuitPython you are using to the lib directory of the CIRCUITPY drive:
- adafruit_ble
- adafruit_bluefruit_connect
- adafruit_bus_device
- adafruit_lis3dh.mpy
- neopixel.mpy
Your lib directory on the CIRCUITPY drive should be similar to the picture here.
The Mu Editor
Adafruit recommends using the free program Mu to edit your CircuitPython programs and save them on your Circuit Playground Bluefruit. You can use any text editor, but Mu has some handy features.
See this page on the Circuit Playground Bluefruit guide on the steps used to install Mu.
Snow Globe Code
Here is the code that we'll run on the Circuit Playground Bluefruit.
Copy this code and then paste it into a new document in Mu, then save it to your CIRCUITPY drive as code.py
# SPDX-FileCopyrightText: 2019 Carter Nelson for Adafruit Industries
#
# SPDX-License-Identifier: MIT
import time
import random
import board
import busio
import neopixel
import adafruit_lis3dh
from adafruit_bluefruit_connect.packet import Packet
from adafruit_bluefruit_connect.color_packet import ColorPacket
from adafruit_bluefruit_connect.button_packet import ButtonPacket
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
from adafruit_ble.services.nordic import UARTService
#===| User Config |==================================================
SNOWGLOBE_NAME = "SNOWGLOBE" # name that will show up on smart device
DEFAULT_ANIMATION = 0 # 0-3, index in ANIMATIONS list
DEFAULT_DURATION = 5 # total seconds to play animation
DEFAULT_SPEED = 0.1 # delay in seconds between updates
DEFAULT_COLOR = 0xFF0000 # hex color value
DEFAULT_SHAKE = 20 # lower number is more sensitive
# you can define more animation functions below
# here, specify the four to be used
ANIMATIONS = ('spin', 'pulse', 'strobe', 'sparkle')
#===| User Config |==================================================
# Configuration settings
snow_config = {
'animation' : DEFAULT_ANIMATION,
'duration' : DEFAULT_DURATION,
'speed' : DEFAULT_SPEED,
'color' : DEFAULT_COLOR,
'shake' : DEFAULT_SHAKE,
}
# Setup NeoPixels
pixels = neopixel.NeoPixel(board.NEOPIXEL, 10)
# Setup accelo
accelo_i2c = busio.I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA)
accelo = adafruit_lis3dh.LIS3DH_I2C(accelo_i2c, address=0x19)
# Setup BLE
ble = BLERadio()
uart = UARTService()
advertisement = ProvideServicesAdvertisement(uart)
ble._adapter.name = SNOWGLOBE_NAME #pylint: disable=protected-access
#--| ANIMATIONS |----------------------------------------------------
def spin(config):
start_time = time.monotonic()
last_update = start_time
p = -1
while time.monotonic() - start_time < config['duration']:
if time.monotonic() - last_update > config['speed']:
pixels.fill(0)
pixels[p % 10] = config['color']
p -= 1
last_update = time.monotonic()
def pulse(config):
start_time = time.monotonic()
last_update = start_time
brightness = 0
delta = 0.05
pixels.brightness = 0
pixels.fill(config['color'])
while time.monotonic() - start_time < config['duration']:
if time.monotonic() - last_update > config['speed']:
brightness += delta
if brightness > 1:
brightness = 1
delta *= -1
if brightness < 0:
brightness = 0
delta *= -1
pixels.brightness = brightness
last_update = time.monotonic()
def strobe(config):
start_time = time.monotonic()
last_update = start_time
turn_on = True
while time.monotonic() - start_time < config['duration']:
if time.monotonic() - last_update > config['speed']:
if turn_on:
pixels.fill(config['color'])
else:
pixels.fill(0)
turn_on = not turn_on
last_update = time.monotonic()
def sparkle(config):
start_time = time.monotonic()
last_update = start_time
while time.monotonic() - start_time < config['duration']:
if time.monotonic() - last_update > config['speed']:
pixels.fill(0)
pixels[random.randint(0, 9)] = config['color']
last_update = time.monotonic()
#--| ANIMATIONS |----------------------------------------------------
def play_animation(config):
#pylint: disable=eval-used
eval(ANIMATIONS[config['animation']])(config)
pixels.fill(0)
def indicate(event=None):
if not isinstance(event, str):
return
event = event.strip().upper()
if event == 'START':
for _ in range(2):
for i in range(10):
pixels[i] = DEFAULT_COLOR
time.sleep(0.05)
pixels.fill(0)
if event == 'CONNECTED':
for _ in range(5):
pixels.fill(0x0000FF)
time.sleep(0.1)
pixels.fill(0)
time.sleep(0.1)
if event == 'DISCONNECTED':
for _ in range(5):
pixels.fill(0x00FF00)
time.sleep(0.1)
pixels.fill(0)
time.sleep(0.1)
indicate('START')
# Are we already advertising?
advertising = False
while True:
# While BLE is *not* connected
while not ble.connected:
if accelo.shake(snow_config['shake'], 5, 0):
play_animation(snow_config)
if not advertising:
ble.start_advertising(advertisement)
advertising = True
# connected
indicate('CONNECTED')
while ble.connected:
# Once we're connected, we're not advertising any more.
advertising = False
if accelo.shake(snow_config['shake'], 5, 0):
play_animation(snow_config)
if uart.in_waiting:
try:
packet = Packet.from_stream(uart)
except ValueError:
continue
if isinstance(packet, ColorPacket):
#
# COLOR
#
snow_config['color'] = packet.color
pixels.fill(snow_config['color'])
time.sleep(0.5)
pixels.fill(0)
if isinstance(packet, ButtonPacket) and packet.pressed:
#
# SPEED
#
if packet.button == ButtonPacket.UP:
speed = snow_config['speed'] - 0.05
speed = 0.05 if speed < 0.05 else speed
snow_config['speed'] = speed
play_animation(snow_config)
if packet.button == ButtonPacket.DOWN:
speed = snow_config['speed'] + 0.05
snow_config['speed'] = speed
play_animation(snow_config)
#
# DURATION
#
if packet.button == ButtonPacket.LEFT:
duration = snow_config['duration'] - 1
duration = 1 if duration < 1 else duration
snow_config['duration'] = duration
play_animation(snow_config)
if packet.button == ButtonPacket.RIGHT:
duration = snow_config['duration'] + 1
snow_config['duration'] = duration
play_animation(snow_config)
#
# ANIMATION
#
if packet.button == ButtonPacket.BUTTON_1:
snow_config['animation'] = 0
play_animation(snow_config)
if packet.button == ButtonPacket.BUTTON_2:
snow_config['animation'] = 1
play_animation(snow_config)
if packet.button == ButtonPacket.BUTTON_3:
snow_config['animation'] = 2
play_animation(snow_config)
if packet.button == ButtonPacket.BUTTON_4:
snow_config['animation'] = 3
play_animation(snow_config)
# disconnected
indicate('DISCONNECTED')
Once you've saved the code to the board, the Circuit Playground Bluefruit will swirl the NeoPixel ring once in the default color. It is now ready to be shaken, try it out!
The default animation will play each time you shake the CPB. You can now connect to it with the Bluefruit app on iOS or Android to adjust the color, animation pattern, speed, and duration.
We'll take a closer look at those settings on the next page after we build the snow globe!
Page last edited January 21, 2025
Text editor powered by tinymce.