Skip to content

Commit 89d8c22

Browse files
authored
Code for guide "Dotstar Matrix Necklace with Bluetooth and Touch"
Code for the new guide "Dotstar Matrix Necklace with Bluetooth and Touch"
1 parent 38bf307 commit 89d8c22

File tree

1 file changed

+273
-0
lines changed

1 file changed

+273
-0
lines changed

ItsyBitsy_DotStar_Necklace/code.py

+273
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
import time
2+
import adafruit_dotstar
3+
import board
4+
import random
5+
import touchio
6+
from adafruit_pixel_framebuf import PixelFramebuffer
7+
from adafruit_led_animation.animation.rainbowchase import RainbowChase
8+
from adafruit_led_animation.animation.rainbowcomet import RainbowComet
9+
from adafruit_led_animation.animation.chase import Chase
10+
from adafruit_led_animation.color import PINK
11+
12+
from adafruit_ble import BLERadio
13+
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
14+
from adafruit_ble.services.nordic import UARTService
15+
from adafruit_bluefruit_connect.packet import Packet
16+
from adafruit_bluefruit_connect.color_packet import ColorPacket
17+
from adafruit_bluefruit_connect.button_packet import ButtonPacket
18+
19+
################################################################################
20+
# Customize variables
21+
22+
# Set capacitive touch pin
23+
TOUCH_PIN = board.D11
24+
25+
# These are the pixels covered by the brass cap touch
26+
# We will try to avoid using these pixels in the "twinkle" default animation
27+
COVERED_PIXELS = [40,41,42,48,49,50,56,57,58]
28+
29+
# Adjust this higher if touch is too sensitive
30+
TOUCH_THRESHOLD = 3000
31+
32+
# Adjust SCROLL_TEXT_COLOR_CHANGE_WAIT lower to make the color changes for
33+
# the text scroll animation faster
34+
SCROLL_TEXT_COLOR_CHANGE_WAIT = 5
35+
36+
# Change this text that will be displayed when tapping 2 on the
37+
# Bluefruit app control pad (after connecting on your phone)
38+
SCROLL_TEXT_CUSTOM_WORD = "hello world"
39+
40+
# Increase number to slow down scrolling
41+
SCROLL_TEXT_WAIT = 0.05
42+
43+
# How bright each pixel in the default twinkling animation will be
44+
TWINKLE_BRIGHTNESS = 0.1
45+
46+
###############################################################################
47+
# Initialize hardware
48+
49+
touch_pad = TOUCH_PIN
50+
touch = touchio.TouchIn(touch_pad)
51+
touch.threshold = TOUCH_THRESHOLD
52+
53+
ble = BLERadio()
54+
uart_service = UARTService()
55+
advertisement = ProvideServicesAdvertisement(uart_service)
56+
57+
# Colors
58+
YELLOW = (255, 150, 0)
59+
TEAL = (0, 255, 120)
60+
CYAN = (0, 255, 255)
61+
PURPLE = (180, 0, 255)
62+
TWINKLEY = (255, 255, 255)
63+
OFF = (0, 0, 0)
64+
65+
# Setup Dotstar grid and pixel framebuffer for fancy animations
66+
pixel_width = 8
67+
pixel_height = 8
68+
num_pixels = pixel_width * pixel_height
69+
pixels = adafruit_dotstar.DotStar(board.A1, board.A2, num_pixels, auto_write=False, brightness=0.1)
70+
pixel_framebuf = PixelFramebuffer(
71+
pixels,
72+
pixel_width,
73+
pixel_height,
74+
rotation=1,
75+
alternating=False,
76+
reverse_x=True
77+
)
78+
# Fancy animations from https://learn.adafruit.com/circuitpython-led-animations
79+
rainbow_chase = RainbowChase(pixels, speed=0.1, size=3, spacing=6, step=8)
80+
chase = Chase(pixels, speed=0.1, color=CYAN, size=3, spacing=6)
81+
rainbow_comet = RainbowComet(pixels, speed=0.1, tail_length=5, bounce=True, colorwheel_offset=170)
82+
83+
84+
def scroll_framebuf_neg_x(word, color, shift_x, shift_y):
85+
pixel_framebuf.fill(0)
86+
color_int = int('0x%02x%02x%02x' % color, 16)
87+
88+
# negate x so that the word can be shown from left to right
89+
pixel_framebuf.text(word, -shift_x, shift_y, color_int)
90+
pixel_framebuf.display()
91+
time.sleep(SCROLL_TEXT_WAIT)
92+
93+
def scroll_text(packet, word):
94+
# scroll through entire length of string.
95+
# each letter is always 5 pixels wide, plus 1 space per letter
96+
scroll_len = (len(word) * 5) + len(word)
97+
color_list = [CYAN, TWINKLEY, PINK, PURPLE, YELLOW]
98+
99+
color_i = 0
100+
color_wait_tick = 0
101+
# start the scroll from off the grid at -pixel_width
102+
for x_pos in range(-pixel_width, scroll_len):
103+
# detect touch
104+
if touch.value:
105+
pixel_framebuf.fill(0)
106+
pixel_framebuf.display()
107+
return;
108+
109+
# detect new packet
110+
if isinstance(packet, ButtonPacket) and packet.pressed:
111+
return;
112+
113+
color = color_list[color_i]
114+
scroll_framebuf_neg_x(word, color, x_pos, 0)
115+
116+
# Only change colors after SCROLL_TEXT_COLOR_CHANGE_WAIT
117+
color_wait_tick = color_wait_tick + 1
118+
if color_wait_tick == SCROLL_TEXT_COLOR_CHANGE_WAIT:
119+
color_i = color_i + 1
120+
color_wait_tick = 0
121+
122+
if color_i == len(color_list):
123+
color_i=0
124+
125+
# wait a bit before scrolling again
126+
time.sleep(.5)
127+
128+
# Manually chosen pixels to display "Y"
129+
# in the proper orientation
130+
def yes(color):
131+
pixels[26] = color
132+
pixels[27] = color
133+
pixels[28] = color
134+
pixels[36] = color
135+
pixels[44] = color
136+
pixels[21] = color
137+
pixels.show()
138+
time.sleep(0.1)
139+
pixels.fill(0)
140+
141+
# Manually chosen pixels to display "N"
142+
# in the proper orientation
143+
def no(color):
144+
pixels[26] = color
145+
pixels[19] = color
146+
pixels[12] = color
147+
pixels[27] = color
148+
pixels[28] = color
149+
pixels[29] = color
150+
pixels[30] = color
151+
pixels[37] = color
152+
pixels[44] = color
153+
pixels.show()
154+
time.sleep(0.1)
155+
pixels.fill(0)
156+
157+
def yes_or_no():
158+
pixels.fill(0)
159+
print(touch.raw_value)
160+
value = 0
161+
pick=0
162+
163+
pick = random.randint(0,64)
164+
time.sleep(0.1)
165+
166+
if pick % 2:
167+
print('picked yes!');
168+
yes(PINK)
169+
time.sleep(1)
170+
else:
171+
print('picked no!');
172+
no(TEAL)
173+
time.sleep(1)
174+
175+
176+
def twinkle_show():
177+
pixels.brightness = TWINKLE_BRIGHTNESS
178+
pixels.show()
179+
time.sleep(.1)
180+
if touch.value:
181+
return;
182+
183+
def twinkle():
184+
# randomly choose 3 pixels
185+
spark1 = random.randint(0, num_pixels-1)
186+
spark2 = random.randint(0, num_pixels-1)
187+
spark3 = random.randint(0, num_pixels-1)
188+
189+
# make sure that none of the chosen pixels are covered
190+
while spark1 in COVERED_PIXELS:
191+
spark1 = random.randint(0, num_pixels-1)
192+
while spark2 in COVERED_PIXELS:
193+
spark2 = random.randint(0, num_pixels-1)
194+
while spark3 in COVERED_PIXELS:
195+
spark3 = random.randint(0, num_pixels-1)
196+
197+
# Control when chosen pixels turn on for dazzling effect
198+
pixels[spark1] = TWINKLEY
199+
pixels[spark2] = OFF
200+
pixels[spark3] = OFF
201+
twinkle_show()
202+
pixels[spark1] = TWINKLEY
203+
pixels[spark2] = TWINKLEY
204+
pixels[spark3] = OFF
205+
twinkle_show()
206+
pixels[spark1] = TWINKLEY
207+
pixels[spark2] = TWINKLEY
208+
pixels[spark3] = TWINKLEY
209+
twinkle_show()
210+
pixels[spark1] = OFF
211+
pixels[spark2] = TWINKLEY
212+
pixels[spark3] = TWINKLEY
213+
twinkle_show()
214+
pixels[spark1] = OFF
215+
pixels[spark2] = OFF
216+
pixels[spark3] = TWINKLEY
217+
twinkle_show()
218+
219+
pixels.fill(OFF)
220+
pixels.show()
221+
time.sleep(0.6)
222+
223+
# Initial empty state
224+
state = ""
225+
226+
while True:
227+
# Advertise when not connected.
228+
ble.start_advertising(advertisement)
229+
230+
while not ble.connected:
231+
if touch.value:
232+
yes_or_no()
233+
else:
234+
twinkle()
235+
236+
while ble.connected:
237+
# Set the state
238+
if uart_service.in_waiting:
239+
# Packet is arriving.
240+
packet = Packet.from_stream(uart_service)
241+
242+
# set state string based on pressed button from Bluefruit app
243+
# and to prevent redundant hits
244+
if isinstance(packet, ButtonPacket) and packet.pressed:
245+
# UP button pressed
246+
if packet.button == ButtonPacket.UP and state != "chase":
247+
state = "chase"
248+
# DOWN button
249+
elif packet.button == ButtonPacket.DOWN and state != "comet":
250+
state = "comet"
251+
# 1 button
252+
elif packet.button == '1' and state != "rainbowchase":
253+
state = "rainbowchase"
254+
# 2 button
255+
elif packet.button == '2' and state != "hello":
256+
state = "hello"
257+
258+
# Touch is handled as an interrupt state
259+
if touch.value:
260+
yes_or_no()
261+
262+
# Act upon the state
263+
if state == "chase":
264+
chase.animate()
265+
elif state == "comet":
266+
rainbow_comet.animate()
267+
elif state == "rainbowchase":
268+
rainbow_chase.animate()
269+
elif state == "hello":
270+
pixels.fill(0)
271+
scroll_text(packet, SCROLL_TEXT_CUSTOM_WORD)
272+
else:
273+
chase.animate()

0 commit comments

Comments
 (0)