Skip to content

Commit 9e4452a

Browse files
authored
Merge pull request #931 from caternuson/ble_snowglobe
Add BLE CPB snow globe
2 parents 93d2025 + d4be285 commit 9e4452a

File tree

1 file changed

+203
-0
lines changed

1 file changed

+203
-0
lines changed

Snow_Globe_BLE_CPB/ble_snowglobe.py

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
import time
2+
import random
3+
import board
4+
import busio
5+
import neopixel
6+
import adafruit_lis3dh
7+
8+
from adafruit_ble.uart_server import UARTServer
9+
from adafruit_bluefruit_connect.packet import Packet
10+
from adafruit_bluefruit_connect.color_packet import ColorPacket
11+
from adafruit_bluefruit_connect.button_packet import ButtonPacket
12+
13+
#===| User Config |==================================================
14+
SNOWGLOBE_NAME = "SNOWGLOBE" # name that will show up on smart device
15+
DEFAULT_ANIMATION = 0 # 0-3, index in ANIMATIONS list
16+
DEFAULT_DURATION = 5 # total seconds to play animation
17+
DEFAULT_SPEED = 0.1 # delay in seconds between updates
18+
DEFAULT_COLOR = 0xFF0000 # hex color value
19+
DEFAULT_SHAKE = 27 # lower number is more sensitive
20+
# you can define more animation functions below
21+
# here, specify the four to be used
22+
ANIMATIONS = ('spin', 'pulse', 'strobe', 'sparkle')
23+
#===| User Config |==================================================
24+
25+
# Configuration settings
26+
snow_config = {
27+
'animation' : DEFAULT_ANIMATION,
28+
'duration' : DEFAULT_DURATION,
29+
'speed' : DEFAULT_SPEED,
30+
'color' : DEFAULT_COLOR,
31+
'shake' : DEFAULT_SHAKE,
32+
}
33+
34+
# Setup NeoPixels
35+
pixels = neopixel.NeoPixel(board.NEOPIXEL, 10)
36+
37+
# Setup accelo
38+
accelo_i2c = busio.I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA)
39+
accelo = adafruit_lis3dh.LIS3DH_I2C(accelo_i2c, address=0x19)
40+
41+
# Setup BLE
42+
uart_server = UARTServer(name=SNOWGLOBE_NAME)
43+
44+
#--| ANIMATIONS |----------------------------------------------------
45+
def spin(config):
46+
start_time = time.monotonic()
47+
last_update = start_time
48+
p = -1
49+
while time.monotonic() - start_time < config['duration']:
50+
if time.monotonic() - last_update > config['speed']:
51+
pixels.fill(0)
52+
pixels[p % 10] = config['color']
53+
p -= 1
54+
last_update = time.monotonic()
55+
56+
def pulse(config):
57+
start_time = time.monotonic()
58+
last_update = start_time
59+
brightness = 0
60+
delta = 0.05
61+
pixels.brightness = 0
62+
pixels.fill(config['color'])
63+
while time.monotonic() - start_time < config['duration']:
64+
if time.monotonic() - last_update > config['speed']:
65+
brightness += delta
66+
if brightness > 1:
67+
brightness = 1
68+
delta *= -1
69+
if brightness < 0:
70+
brightness = 0
71+
delta *= -1
72+
pixels.brightness = brightness
73+
last_update = time.monotonic()
74+
75+
def strobe(config):
76+
start_time = time.monotonic()
77+
last_update = start_time
78+
turn_on = True
79+
while time.monotonic() - start_time < config['duration']:
80+
if time.monotonic() - last_update > config['speed']:
81+
if turn_on:
82+
pixels.fill(config['color'])
83+
else:
84+
pixels.fill(0)
85+
turn_on = not turn_on
86+
last_update = time.monotonic()
87+
88+
def sparkle(config):
89+
start_time = time.monotonic()
90+
last_update = start_time
91+
while time.monotonic() - start_time < config['duration']:
92+
if time.monotonic() - last_update > config['speed']:
93+
pixels.fill(0)
94+
pixels[random.randint(0, 9)] = config['color']
95+
last_update = time.monotonic()
96+
#--| ANIMATIONS |----------------------------------------------------
97+
98+
def play_animation(config):
99+
#pylint: disable=eval-used
100+
eval(ANIMATIONS[config['animation']])(config)
101+
pixels.fill(0)
102+
103+
def indicate(event=None):
104+
if not isinstance(event, str):
105+
return
106+
event = event.strip().upper()
107+
if event == 'START':
108+
for _ in range(2):
109+
for i in range(10):
110+
pixels[i] = DEFAULT_COLOR
111+
time.sleep(0.05)
112+
pixels.fill(0)
113+
if event == 'CONNECTED':
114+
for _ in range(5):
115+
pixels.fill(0x0000FF)
116+
time.sleep(0.1)
117+
pixels.fill(0)
118+
time.sleep(0.1)
119+
if event == 'DISCONNECTED':
120+
for _ in range(5):
121+
pixels.fill(0x00FF00)
122+
time.sleep(0.1)
123+
pixels.fill(0)
124+
time.sleep(0.1)
125+
126+
indicate('START')
127+
while True:
128+
uart_server.start_advertising()
129+
130+
# wait for connection
131+
while not uart_server.connected:
132+
# check for shake while waiting
133+
if accelo.shake(snow_config['shake'], 5, 0):
134+
play_animation(snow_config)
135+
136+
# connected
137+
indicate('CONNECTED')
138+
139+
while uart_server.connected:
140+
141+
if accelo.shake(snow_config['shake'], 5, 0):
142+
play_animation(snow_config)
143+
144+
if uart_server.in_waiting:
145+
try:
146+
packet = Packet.from_stream(uart_server)
147+
except ValueError:
148+
continue
149+
150+
if isinstance(packet, ColorPacket):
151+
#
152+
# COLOR
153+
#
154+
snow_config['color'] = packet.color
155+
pixels.fill(snow_config['color'])
156+
time.sleep(0.5)
157+
pixels.fill(0)
158+
159+
if isinstance(packet, ButtonPacket) and packet.pressed:
160+
#
161+
# SPEED
162+
#
163+
if packet.button == ButtonPacket.UP:
164+
speed = snow_config['speed'] - 0.05
165+
speed = 0.05 if speed < 0.05 else speed
166+
snow_config['speed'] = speed
167+
play_animation(snow_config)
168+
if packet.button == ButtonPacket.DOWN:
169+
speed = snow_config['speed'] + 0.05
170+
snow_config['speed'] = speed
171+
play_animation(snow_config)
172+
173+
#
174+
# DURATION
175+
#
176+
if packet.button == ButtonPacket.LEFT:
177+
duration = snow_config['duration'] - 1
178+
duration = 1 if duration < 1 else duration
179+
snow_config['duration'] = duration
180+
play_animation(snow_config)
181+
if packet.button == ButtonPacket.RIGHT:
182+
duration = snow_config['duration'] + 1
183+
snow_config['duration'] = duration
184+
play_animation(snow_config)
185+
186+
#
187+
# ANIMATION
188+
#
189+
if packet.button == ButtonPacket.BUTTON_1:
190+
snow_config['animation'] = 0
191+
play_animation(snow_config)
192+
if packet.button == ButtonPacket.BUTTON_2:
193+
snow_config['animation'] = 1
194+
play_animation(snow_config)
195+
if packet.button == ButtonPacket.BUTTON_3:
196+
snow_config['animation'] = 2
197+
play_animation(snow_config)
198+
if packet.button == ButtonPacket.BUTTON_4:
199+
snow_config['animation'] = 3
200+
play_animation(snow_config)
201+
202+
# disconnected
203+
indicate('DISCONNECTED')

0 commit comments

Comments
 (0)