from machine import Pin, PWM ,I2C
from time import sleep
from i2c_lcd import I2cLcd
from keypad import Keypad
from safe_state import SafeState
# Locking mechanism definitions
SERVO_LOCK_POS = 20
SERVO_UNLOCK_POS = 90
servo_pin = Pin(6, Pin.OUT)
pwm = PWM(servo_pin)
pwm.freq(50)
# Creates a function for mapping the 0 to 180 degrees to 20 to 120 pwm duty values
def map(x, in_min, in_max, out_min, out_max):
return int((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)
# Creates another function for turning the servo according to input angle
def servo(pwm_pin, angle):
pwm.duty_u16(map(angle, 0, 180, 20, 120))
# Display
i2c = I2C(0, sda=Pin(0), scl=Pin(21), freq=400000)
DEFAULT_I2C_ADDR = i2c.scan()[0]
lcd = I2cLcd(i2c, DEFAULT_I2C_ADDR, 2, 16)
# Keypad setup
keypad_rows = [5, 4, 3, 2]
keypad_cols = [28, 27, 26, 22] # Analog pins on Raspberry Pi Pico
keypad = Keypad(keypad_rows, keypad_cols, ['1', '2', '3', 'A', '4', '5', '6', 'B', '7', '8', '9', 'C', '*', '0', '#', 'D'])
# SafeState stores the secret code in EEPROM
safe_state = SafeState()
def lock():
pwm.duty_u16(SERVO_LOCK_POS)
safe_state.lock()
def unlock():
pwm.duty_u16(SERVO_UNLOCK_POS)
def show_startup_message():
lcd.clear()
lcd.move_to(0,0)
lcd.putstr("Welcome!")
sleep(1)
def input_secret_code():
lcd.clear()
lcd.putstr("[____]")
code = ''
while len(code) < 4:
key = keypad.get_key()
if key and key.isdigit():
lcd.putstr('*')
code += key
return code
def show_wait_screen(delay_millis):
lcd.clear()
lcd.putstr("[..........]")
sleep(delay_millis / 1000)
def set_new_code():
lcd.clear()
lcd.putstr("Enter new code:")
new_code = input_secret_code()
lcd.clear()
lcd.putstr("Confirm new code")
confirm_code = input_secret_code()
if new_code == confirm_code:
safe_state.set_code(new_code)
return True
else:
lcd.clear()
lcd.putstr("Code mismatch\nSafe not locked!")
sleep(2)
return False
def show_unlock_message():
lcd.clear()
lcd.putstr("Unlocked!")
sleep(1)
def safe_unlocked_logic():
lcd.clear()
lcd.move_to(0,0)
lcd.putstr('# to unlock')
if safe_state.has_code():
lcd.clear()
lcd.move_to(0, 1)
lcd.putstr("A = new code")
new_code_needed = False
else:
new_code_needed = True
key = ''
while key != 'A' and key != '#':
key = keypad.get_key()
ready_to_lock = True
if key == 'A' or new_code_needed:
ready_to_lock = set_new_code()
if ready_to_lock:
lcd.clear()
safe_state.lock()
lock()
show_wait_screen(100)
def safe_locked_logic():
lcd.clear()
lcd.putstr(" Safe Locked! ")
user_code = input_secret_code()
unlocked_successfully = safe_state.unlock(user_code)
show_wait_screen(200)
if unlocked_successfully:
show_unlock_message()
unlock()
else:
lcd.clear()
lcd.putstr("Access Denied!")
show_wait_screen(1000)
def setup():
pwm.freq(50) # Set PWM frequency
pwm.duty_u16(SERVO_UNLOCK_POS) # Make sure the servo is initially unlocked
show_startup_message()
def loop():
if safe_state.locked():
safe_locked_logic()
else:
safe_unlocked_logic()
if __name__ == "__main__":
setup()
while True:
loop()