Skip to content

Commit 7e37264

Browse files
authored
Merge pull request #2645 from adafruit/fraz_wrench
Adding code and sound effects for fraz wrench
2 parents 6a8012c + 7e514ac commit 7e37264

6 files changed

Lines changed: 179 additions & 0 deletions

File tree

Fraz_Wrench/code.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2023 Liz Clark for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import os
6+
import random
7+
import board
8+
import audiocore
9+
import audiobusio
10+
import audiomixer
11+
from digitalio import DigitalInOut, Direction
12+
import neopixel
13+
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
14+
from adafruit_led_animation.animation.pulse import Pulse
15+
from adafruit_led_animation.color import RED, GREEN
16+
import adafruit_character_lcd.character_lcd_i2c as character_lcd
17+
import adafruit_lis3dh
18+
from adafruit_seesaw.seesaw import Seesaw
19+
from adafruit_seesaw.rotaryio import IncrementalEncoder
20+
import keypad
21+
22+
puzzle_time = 5 # seconds
23+
24+
lcd_columns = 16
25+
lcd_rows = 2
26+
27+
# enable external power pin
28+
# provides power to the external components
29+
external_power = DigitalInOut(board.EXTERNAL_POWER)
30+
external_power.direction = Direction.OUTPUT
31+
external_power.value = True
32+
33+
i2c = board.I2C()
34+
35+
int1 = DigitalInOut(board.ACCELEROMETER_INTERRUPT)
36+
lis3dh = adafruit_lis3dh.LIS3DH_I2C(i2c, int1=int1)
37+
lis3dh.range = adafruit_lis3dh.RANGE_2_G
38+
39+
ss_enc0 = Seesaw(i2c, addr=0x36)
40+
enc0 = IncrementalEncoder(ss_enc0)
41+
42+
button = keypad.Keys((board.EXTERNAL_BUTTON, board.D13,), value_when_pressed=False, pull=True)
43+
44+
lcd = character_lcd.Character_LCD_I2C(i2c, lcd_columns, lcd_rows)
45+
lcd.backlight = True
46+
47+
puzzle_msgs = ["UNLOCK\nDOOR", "DOOR\nUNLOCKED", "UNLOCKING"]
48+
49+
wavs = []
50+
for filename in os.listdir('/fraz_sounds'):
51+
if filename.lower().endswith('.wav') and not filename.startswith('.'):
52+
wavs.append("/fraz_sounds/"+filename)
53+
wavs.sort()
54+
print(wavs)
55+
56+
audio = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA)
57+
mixer = audiomixer.Mixer(voice_count=1, sample_rate=22050, channel_count=1,
58+
bits_per_sample=16, samples_signed=True, buffer_size=32768)
59+
volume = 0.5
60+
mixer.voice[0].level = volume
61+
audio.play(mixer)
62+
wav_length = len(wavs) - 1
63+
64+
def open_audio(num):
65+
n = wavs[num]
66+
f = open(n, "rb")
67+
w = audiocore.WaveFile(f)
68+
return w
69+
70+
PIXEL_PIN = board.EXTERNAL_NEOPIXELS
71+
BRIGHTNESS = 0.3
72+
NUM_PIXELS = 8
73+
74+
PIXELS = neopixel.NeoPixel(PIXEL_PIN, NUM_PIXELS, auto_write=True)
75+
pulse = Pulse(PIXELS, speed=0.001, color=RED, period=3)
76+
77+
puzzle_clock = ticks_ms()
78+
puzzle_time = puzzle_time * 1000
79+
80+
puzzle = False
81+
wave = open_audio(0)
82+
pos0 = volume
83+
last_pos0 = pos0
84+
node_num = 0
85+
86+
def normalize(val, min_v, max_v):
87+
return max(min(max_v, val), min_v)
88+
89+
def puzzle_string(length):
90+
_string = ""
91+
for _ in range(length/2):
92+
b = random.randint(0, 1)
93+
if b == 0:
94+
r = chr(random.randint(ord('A'), ord('Z')))
95+
else:
96+
r = str(random.randint(0, 9))
97+
_string += r
98+
_string += "\n"
99+
for _ in range(length/2):
100+
b = random.randint(0, 1)
101+
if b == 0:
102+
r = chr(random.randint(ord('A'), ord('Z')))
103+
else:
104+
r = str(random.randint(0, 9))
105+
_string += r
106+
lcd.message = _string
107+
return _string
108+
109+
while True:
110+
event = button.events.get()
111+
if event and event.pressed:
112+
number = event.key_number
113+
if number == 0 and not puzzle:
114+
pulse.fill(GREEN)
115+
puzzle = True
116+
lcd.clear()
117+
lcd.message = puzzle_msgs[2]
118+
wave = open_audio(1)
119+
mixer.voice[0].play(wave)
120+
while mixer.playing:
121+
pass
122+
puzzle_clock = ticks_add(ticks_ms(), puzzle_time)
123+
if number == 1:
124+
lcd.clear()
125+
node_num = (node_num + 1) % 5
126+
print(node_num)
127+
128+
if puzzle:
129+
x, y, z = [
130+
value / adafruit_lis3dh.STANDARD_GRAVITY for value in lis3dh.acceleration
131+
]
132+
puzzle_string(lcd_columns*lcd_rows)
133+
if z > 0:
134+
wave = open_audio(2)
135+
print("playing up")
136+
pulse.fill(GREEN)
137+
else:
138+
wave = open_audio(3)
139+
print("playing down")
140+
pulse.fill(RED)
141+
mixer.voice[0].play(wave)
142+
while mixer.playing:
143+
puzzle_string(lcd_columns*lcd_rows)
144+
x, y, z = [
145+
value / adafruit_lis3dh.STANDARD_GRAVITY for value in lis3dh.acceleration
146+
]
147+
if z > 0:
148+
pulse.fill(GREEN)
149+
else:
150+
pulse.fill(RED)
151+
if ticks_diff(ticks_ms(), puzzle_clock) >= puzzle_time:
152+
lcd.clear()
153+
puzzle = False
154+
lcd.message = puzzle_msgs[1]
155+
wave = open_audio(4)
156+
mixer.voice[0].play(wave)
157+
while mixer.playing:
158+
pass
159+
print("puzzle done")
160+
wave = open_audio(0)
161+
lcd.clear()
162+
pulse.fill(RED)
163+
164+
if not puzzle:
165+
pulse.animate()
166+
mixer.voice[0].play(wave, loop=True)
167+
if node_num > 3:
168+
lcd.message = "SECURITY\nBREACHED"
169+
else:
170+
lcd.message = f"DEACTIVATED:\n{node_num} of 4"
171+
pos0 = -enc0.position
172+
if pos0 != last_pos0:
173+
if pos0 > last_pos0:
174+
volume = volume + 0.1
175+
else:
176+
volume = volume - 0.1
177+
volume = normalize(volume, 0.0, 1.0)
178+
mixer.voice[0].level = volume
179+
last_pos0 = pos0

Fraz_Wrench/fraz_sounds/0_idle.wav

159 KB
Binary file not shown.
116 KB
Binary file not shown.
90.5 KB
Binary file not shown.
86.2 KB
Binary file not shown.
122 KB
Binary file not shown.

0 commit comments

Comments
 (0)