225 lines
7.2 KiB
Python
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')
|