142 lines
5.2 KiB
Python
142 lines
5.2 KiB
Python
# SPDX-FileCopyrightText: 2021 Anne Barela for Adafruit Industries
|
|
#
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
"""
|
|
Code for the LED Infinity Mirror Collar. Allows the animation sequence
|
|
and color to be controlled by input from the Adafruit Bluefruit App
|
|
"""
|
|
import board
|
|
import random
|
|
from rainbowio import colorwheel
|
|
import neopixel
|
|
import digitalio
|
|
from adafruit_debouncer import Debouncer
|
|
|
|
# LED Animation modules
|
|
from adafruit_led_animation.animation.comet import Comet
|
|
from adafruit_led_animation.animation.chase import Chase
|
|
from adafruit_led_animation.animation.rainbowcomet import RainbowComet
|
|
from adafruit_led_animation.animation.pulse import Pulse
|
|
from adafruit_led_animation.sequence import AnimationSequence
|
|
|
|
|
|
# Bluetooth modules
|
|
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.color_packet import ColorPacket
|
|
from adafruit_bluefruit_connect.button_packet import ButtonPacket
|
|
|
|
# NeoPixel control pin
|
|
pixel_pin = board.D5
|
|
|
|
# Number of pixels in the collar (arranged in two rows)
|
|
pixel_num = 24
|
|
|
|
pixels = neopixel.NeoPixel(pixel_pin, pixel_num, brightness=0.5, auto_write=False)
|
|
|
|
# Create a switch from the ItsyBity's on-board pushbutton to toggle charge mode
|
|
mode_pin = digitalio.DigitalInOut(board.SWITCH)
|
|
mode_pin.direction = digitalio.Direction.INPUT
|
|
mode_pin.pull = digitalio.Pull.UP
|
|
switch = Debouncer(mode_pin)
|
|
|
|
# Create the animations
|
|
comet = Comet(pixels, speed=0.06, color=(180,0,255), tail_length=10, bounce=True)
|
|
chase = Chase(pixels, speed=0.05, size=3, spacing=3, color=(0,255,255), reverse=True)
|
|
rainbow_comet = RainbowComet(pixels, speed=.06)
|
|
pulse = Pulse(pixels, speed=.04, color=(255,0,0), period = 0.2)
|
|
|
|
|
|
# Our animations sequence
|
|
seconds_per_animation = 10
|
|
animations = AnimationSequence(comet, rainbow_comet, chase, advance_interval=seconds_per_animation, auto_clear=True)
|
|
# Current display determines whether we are showing the animation sequence or the pulse animation
|
|
current_display = animations
|
|
|
|
# Mode changes the color of random animations randomly
|
|
random_color_mode = True
|
|
|
|
def random_animation_color(anims):
|
|
if random_color_mode:
|
|
anims.color = colorwheel(random.randint(0,255))
|
|
|
|
animations.add_cycle_complete_receiver(random_animation_color)
|
|
|
|
|
|
# After we complete three pulse cycles, return to main animations list
|
|
def pulse_finished(anim):
|
|
global current_display
|
|
current_display = animations
|
|
|
|
pulse.add_cycle_complete_receiver(pulse_finished)
|
|
pulse.notify_cycles = 3
|
|
|
|
|
|
# Bluetooth
|
|
ble = BLERadio()
|
|
uart_service = UARTService()
|
|
advertisement = ProvideServicesAdvertisement(uart_service)
|
|
|
|
# Set charge_mode to True to turn off the LED Animations and Bluetooth
|
|
# e.g. when charging the battery
|
|
charge_mode = False
|
|
|
|
# Checks the ItsyBitsy's switch button
|
|
def check_switch():
|
|
global charge_mode
|
|
switch.update()
|
|
if switch.fell: #Switch changed state
|
|
charge_mode = not charge_mode
|
|
# if display has just been turned off, clear all LEDs, disconnect, stop advertising
|
|
if charge_mode:
|
|
pixels.fill((0,0,0))
|
|
pixels.show()
|
|
if ble.connected:
|
|
for conn in ble.connections:
|
|
conn.disconnect()
|
|
if ble.advertising:
|
|
ble.stop_advertising()
|
|
|
|
# Main program loop
|
|
while True:
|
|
# Check whether charge mode has been changed
|
|
check_switch()
|
|
if charge_mode:
|
|
pass
|
|
else:
|
|
current_display.animate()
|
|
if ble.connected:
|
|
if uart_service.in_waiting:
|
|
#Packet is arriving
|
|
packet = Packet.from_stream(uart_service)
|
|
if isinstance(packet, ButtonPacket) and packet.pressed:
|
|
if packet.button == ButtonPacket.BUTTON_1:
|
|
# Animation colors change to a random new value after every animation sequence
|
|
random_color_mode = True
|
|
elif packet.button == ButtonPacket.BUTTON_2:
|
|
# Animation colors stay the same unless manually changed
|
|
random_color_mode = False
|
|
elif packet.button == ButtonPacket.BUTTON_3:
|
|
# Stay on the same animation
|
|
animations._advance_interval = None
|
|
elif packet.button == ButtonPacket.BUTTON_4:
|
|
# Auto-advance animations
|
|
animations._advance_interval = seconds_per_animation*1000
|
|
elif packet.button == ButtonPacket.LEFT:
|
|
# Go to first animation in the sequence
|
|
animations.activate(0)
|
|
elif packet.button == ButtonPacket.RIGHT:
|
|
# Go to the next animation in the sequence
|
|
animations.next()
|
|
elif isinstance(packet, ColorPacket):
|
|
animations.color = packet.color
|
|
pulse.color = packet.color
|
|
# temporarily change to pulse display to show off the new color
|
|
current_display = pulse
|
|
|
|
else:
|
|
if not ble.advertising:
|
|
ble.start_advertising(advertisement)
|