Skip to content

Commit b1f35bf

Browse files
authored
Merge pull request #1816 from adafruit/TheKitty-patch-3
Create code.py for new guide
2 parents eb74742 + db5fb8e commit b1f35bf

1 file changed

Lines changed: 212 additions & 0 deletions

File tree

MacroPad_Scramble_Lock/code.py

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
"""
2+
Scramblepad - a random scramble keypad simulation for Adafruit MACROPAD.
3+
"""
4+
# SPDX-FileCopyrightText: Copyright (c) 2021 Anne Barela for Adafruit Industries
5+
#
6+
# SPDX-License-Identifier: MIT
7+
8+
import time
9+
import random
10+
import board
11+
from digitalio import DigitalInOut, Direction
12+
import displayio
13+
import terminalio
14+
from adafruit_display_shapes.rect import Rect
15+
from adafruit_display_text import label
16+
from adafruit_macropad import MacroPad
17+
18+
# CONFIGURABLES ------------------------
19+
20+
# Password information
21+
# For higher security, place password in a separate file like secrets.py
22+
PASSWORD = "2468"
23+
PASSWORD_LENGTH = len(PASSWORD)
24+
25+
# States keypad may be in
26+
STATE_ENTRY = 1
27+
STATE_CLEAR = 2
28+
STATE_RESET = 3
29+
30+
# Color defines for keys
31+
WHITE = 0xFFFFFF
32+
BLACK = 0x000000
33+
RED = 0xFF0000
34+
ORANGE = 0xFFA500
35+
YELLOW = 0xFFFF00
36+
GREEN = 0x00FF00
37+
BLUE = 0x0000FF
38+
PURPLE = 0x800080
39+
PINK = 0xFFC0CB
40+
TEAL = 0x2266AA
41+
MAGENTA = 0xFF00FF
42+
CYAN = 0x00FFFF
43+
44+
colors = [PINK, RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, TEAL, MAGENTA, CYAN]
45+
current_colors = []
46+
47+
# Define sounds the keypad makes
48+
tones = (440, 220, 245, 330, 440) # Initial tones while scrambling
49+
press_tone = 660 # This tone is used when each key is pressed
50+
51+
# Initial key values - this list will be scrambled by the scramble function
52+
key_values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
53+
54+
# Define the STEMMA QT I2C line SDA to be a digital output (nonstandard use)
55+
# SDA will be used as a digital pin to trigger a transistor to
56+
# axctivate a solenoid which will unlock, like a door
57+
solenoid = DigitalInOut(board.SDA)
58+
solenoid.direction = Direction.OUTPUT
59+
60+
# FUNCTIONS ------------------
61+
62+
def keys_clear(): # Set display in the Start mode, key LEDs off
63+
for i in range(12):
64+
macropad.pixels[i] = 0x000000
65+
group[i].text = " "
66+
macropad.pixels.show()
67+
group[9].text = "START"
68+
macropad.display.show(group)
69+
macropad.display.refresh()
70+
71+
def scramble(): # Scramble values of the keys and display on screen
72+
for times in range(5):
73+
# The following lines implement a random.shuffle method
74+
# See https://www.rosettacode.org/wiki/Knuth_shuffle#Python
75+
# random.shuffle(key_values) # Shuffle the key array
76+
for i in range(len(key_values)-1, 0, -1):
77+
j = random.randrange(i + 1)
78+
key_values[i], key_values[j] = key_values[j], key_values[i]
79+
keys_display()
80+
macropad.play_tone(tones[times], 0.3) # Play a tone each scramble iteration
81+
time.sleep(0.01)
82+
83+
def keys_display(): # Display the current values of the keys on screen
84+
for k in range(9): # The first 9 keys
85+
group[k].text = str(key_values[k])
86+
macropad.pixels[k] = colors[key_values[k]]
87+
group[10].text = str(key_values[9]) # The 'Zero' position number
88+
group[9].text = " " # Start blanks
89+
group[11].text = " " # Status blanks
90+
macropad.pixels[10] = colors[key_values[9]]
91+
macropad.display.refresh()
92+
macropad.pixels.show()
93+
94+
# INITIALIZATION -----------------------
95+
96+
macropad = MacroPad() # Set up MacroPad library and behavior
97+
macropad.display.auto_refresh = False
98+
macropad.pixels.auto_write = False
99+
100+
# Set up displayio group with all the labels
101+
group = displayio.Group()
102+
for key_index in range(12):
103+
x = key_index % 3
104+
y = key_index // 3
105+
group.append(label.Label(terminalio.FONT, text='', color=0xFFFFFF,
106+
anchored_position=((macropad.display.width - 1) * x / 2,
107+
macropad.display.height - 1 -
108+
(3 - y) * 12),
109+
anchor_point=(x / 2, 1.0)))
110+
group.append(Rect(0, 0, macropad.display.width, 12, fill=0xFFFFFF))
111+
group.append(label.Label(terminalio.FONT, text='ScramblePad', color=0x000000,
112+
anchored_position=(macropad.display.width//2, -2),
113+
anchor_point=(0.5, 0.0)))
114+
115+
116+
# Initialize in a clear state
117+
state = STATE_CLEAR
118+
macropad.keyboard.release_all()
119+
keys_clear()
120+
solenoid.value = False
121+
122+
# MAIN LOOP ----------------------------
123+
124+
while True:
125+
if state == STATE_RESET:
126+
print("Reset state")
127+
macropad.keyboard.release_all()
128+
password_guess = "" # Reset password entry
129+
state = STATE_CLEAR # Reset state
130+
131+
# Check for key presses/releases
132+
event = macropad.keys.events.get()
133+
if not event:
134+
continue
135+
key_number = event.key_number
136+
pressed = event.pressed
137+
138+
if pressed:
139+
if state == STATE_CLEAR:
140+
if key_number != 9: # Waiting to hit START
141+
print("You must press start, lower left")
142+
macropad.keyboard.release(key_number)
143+
else: # START pressed
144+
print("START pressed, enter your password")
145+
macropad.keyboard.release(key_number)
146+
password_guess = ""
147+
scramble()
148+
state = STATE_ENTRY
149+
continue
150+
if state == STATE_ENTRY:
151+
if key_number == 9: # Start key during entry
152+
print("Restart whole key entry")
153+
macropad.keyboard.release_all()
154+
password_guess = "" # Reset password entry
155+
scramble()
156+
continue
157+
#
158+
# From here out is password entry, state is KEY_ENTRY
159+
#
160+
if key_number < 11: # Ignore encoder and lower right button
161+
old_color = macropad.pixels[key_number] # Save color of key pressed
162+
macropad.pixels[key_number] = 0xFFFFFF # Turn key white while down
163+
macropad.pixels.show() # Show key as white
164+
macropad.play_tone(press_tone, 0.6) # Play tone when key pressed
165+
# Process input - add the key pressed to the password entry
166+
if key_number == 10: # The "0" position is shifted over, take one away
167+
password_guess = password_guess + str(key_values[key_number-1])
168+
else: # The 1-9 keys (index values 0 to 8)
169+
password_guess = password_guess + str(key_values[key_number])
170+
print(password_guess)
171+
if len(password_guess) == PASSWORD_LENGTH: # We've entered all digits
172+
keys_clear() # Clear the keypad
173+
if password_guess == PASSWORD: # Success
174+
group[9].text = " "
175+
group[11].text = "OPEN"
176+
macropad.display.show(group)
177+
macropad.display.refresh()
178+
macropad.pixels[11] = GREEN
179+
macropad.pixels.show()
180+
181+
# Activate solenoid
182+
solenoid.value = True
183+
time.sleep(2) # Limit time open to spare current in transistor
184+
solenoid.value = False
185+
# Reset
186+
time.sleep(5)
187+
macropad.pixels[11] = BLACK
188+
macropad.pixels.show()
189+
else: # fail!
190+
group[11].text = "FAIL"
191+
group[9].text = " "
192+
macropad.display.show(group)
193+
macropad.display.refresh()
194+
for _ in range(3): # Flash lower right 3 times red with beeps
195+
macropad.pixels[11] = RED
196+
macropad.pixels.show()
197+
macropad.play_tone(880, 1)
198+
time.sleep(0.1)
199+
macropad.pixels[11] = BLACK
200+
macropad.pixels.show()
201+
time.sleep(0.1)
202+
# Reset state after both success and failure
203+
keys_clear()
204+
state = STATE_RESET
205+
206+
else: # Release any still-pressed keys
207+
macropad.keyboard.release(key_number)
208+
# Change key color back
209+
if state == STATE_ENTRY:
210+
if key_number in (0, 1, 2, 3, 4, 5, 6, 7, 8, 10):
211+
macropad.pixels[key_number] = old_color
212+
macropad.pixels.show()

0 commit comments

Comments
 (0)