Adafruit_Learning_System_Gu.../ItsyBitsy_Infinity_Collar/code.py
2022-02-23 13:29:01 -05:00

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)