import time
import board
import digitalio
import busio
from i2c_lcd import I2cLcd
import builtins
str = builtins.str
# ===== LCD Setup (I2C) =====
i2c = busio.I2C(scl=board.GP1, sda=board.GP16)
lcd = I2cLcd(i2c, 0x27, 2, 16)
# ===== Keypad Setup =====
keymap = [
['1', '2', '3'],
['4', '5', '6'],
['7', '8', '9'],
['*', '0', '#']
]
row_pins = [board.GP18, board.GP19, board.GP20, board.GP21]
col_pins = [board.GP22, board.GP26, board.GP27, board.GP28]
rows = [digitalio.DigitalInOut(pin) for pin in row_pins]
cols = [digitalio.DigitalInOut(pin) for pin in col_pins]
for row in rows:
row.direction = digitalio.Direction.OUTPUT
row.value = False
for col in cols:
col.direction = digitalio.Direction.INPUT
col.pull = digitalio.Pull.DOWN
# ===== Buttons =====
submit_button = digitalio.DigitalInOut(board.GP15)
submit_button.direction = digitalio.Direction.INPUT
submit_button.pull = digitalio.Pull.UP
shutdown_button = digitalio.DigitalInOut(board.GP14)
shutdown_button.direction = digitalio.Direction.INPUT
shutdown_button.pull = digitalio.Pull.UP
# ===== LEDs =====
green_led = digitalio.DigitalInOut(board.GP6)
green_led.direction = digitalio.Direction.OUTPUT
green_led.value = False
red_led = digitalio.DigitalInOut(board.GP7)
red_led.direction = digitalio.Direction.OUTPUT
red_led.value = False
shutdown_led = digitalio.DigitalInOut(board.GP17)
shutdown_led.direction = digitalio.Direction.OUTPUT
shutdown_led.value = False
# ===== 7-Segment Setup (A–G) =====
seg_pins = [board.GP2, board.GP3, board.GP4, board.GP5, board.GP8, board.GP9, board.GP10]
segments_gpio = [digitalio.DigitalInOut(pin) for pin in seg_pins]
for seg in segments_gpio:
seg.direction = digitalio.Direction.OUTPUT
seg.value = False
dp = digitalio.DigitalInOut(board.GP11)
dp.direction = digitalio.Direction.OUTPUT
dp.value = False
# ===== Segment Display Map =====
segments = {
'0': [0,0,0,0,0,0,1],
'1': [1,0,0,1,1,1,1],
'2': [0,0,1,0,0,1,0],
'3': [0,0,0,0,1,1,0],
'4': [1,0,0,1,1,0,0],
'5': [0,1,0,0,1,0,0],
'6': [0,1,0,0,0,0,0],
'7': [0,0,0,1,1,1,1],
'8': [0,0,0,0,0,0,0],
'9': [0,0,0,0,1,0,0],
' ': [1,1,1,1,1,1,1]
}
def display_digit(digit, dot=False):
pattern = segments.get(digit, segments[' '])
for seg, val in zip(segments_gpio, pattern):
seg.value = val
dp.value = dot
def clear_digit():
for seg in segments_gpio:
seg.value = False
dp.value = False
# ===== Display Functions =====
def read_keypad():
for i, row in enumerate(rows):
row.value = True
for j, col in enumerate(cols):
if col.value:
while col.value:
time.sleep(0.01)
row.value = False
return keymap[i][j]
row.value = False
return None
def display_message(line1, line2=""):
try:
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr(str(line1)[:16])
lcd.move_to(0, 1)
lcd.putstr(str(line2)[:16])
except Exception as e:
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("LCD ERROR")
lcd.move_to(0, 1)
lcd.putstr(str(e)[:16])
# ===== Countdown Functions =====
def start_countdown():
global countdown_active, countdown_value, last_countdown_time
countdown_active = True
countdown_value = 9
last_countdown_time = time.monotonic()
display_digit(str(countdown_value))
display_message("ACCESS GRANTED", f"Time left: {countdown_value}s")
def update_countdown():
global countdown_active, countdown_value, last_countdown_time
now = time.monotonic()
if now - last_countdown_time >= 1: # 1 second elapsed
countdown_value -= 1
last_countdown_time = now
if countdown_value >= 0:
display_digit(str(countdown_value))
display_message("ACCESS GRANTED", f"Time left: {countdown_value}s")
else:
# Countdown finished
countdown_active = False
display_digit(' ')
display_message("Enter PIN:")
green_led.value = False
# ===== Constants & Variables =====
SECRET_CODE = "1111"
input_code = ""
last_input_time = time.monotonic()
# Countdown state
countdown_active = False
countdown_value = 9
last_countdown_time = 0
# Shutdown state
system_active = True
# ===== Startup Display =====
display_message("Welcome", "Enter PIN:")
display_digit(' ')
# ===== Main Loop =====
while True:
now = time.monotonic()
# Shutdown toggle
if not shutdown_button.value:
time.sleep(0.3) # debounce
system_active = not system_active
if not system_active:
# System off: clear everything
lcd.clear()
green_led.value = False
red_led.value = False
clear_digit()
shutdown_led.value = False
else:
# System on again
shutdown_led.value = True
display_message("Enter PIN:")
display_digit(' ')
continue # skip rest of loop when toggled
# Skip all functions if system is OFF
if not system_active:
time.sleep(0.1)
continue
# Handle countdown if active
if countdown_active:
update_countdown()
time.sleep(0.1) # Shorter sleep during countdown
continue # Skip other inputs during countdown
# Submit PIN
if not submit_button.value:
time.sleep(0.2) # debounce
if input_code == SECRET_CODE:
display_message("ACCESS", "GRANTED")
green_led.value = True
red_led.value = False
start_countdown()
else:
display_message("ACCESS", "DENIED")
green_led.value = False
red_led.value = True
time.sleep(2)
display_message("Enter PIN:")
display_digit(' ')
input_code = ""
last_input_time = now
# Timeout reset (20s)
if now - last_input_time > 20:
input_code = ""
display_message("Timeout", "Enter PIN:")
display_digit(' ')
last_input_time = now
# Keypad input
key = read_keypad()
if key:
last_input_time = now
if key == "*":
input_code = input_code[:-1]
elif len(input_code) < 4:
input_code += key
display_message("Enter PIN:", "*" * len(input_code))
if input_code:
digit = input_code[-1]
display_digit(digit, dot=(len(input_code) == 4))
else:
display_digit(' ')
time.sleep(0.1) # Reduced sleep for better responsiveness