Adafruit_Learning_System_Gu.../Snow_Globe_BLE_CPB/code.py
2022-02-22 14:15:38 -05:00

225 lines
7.2 KiB
Python

# 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')