'''
Voltaat Learn (http://learn.voltaat.com)
Link to the full tutorial:
Tutorial: Building a password-protected safe using a Raspberry Pi Pico board.
This code is for building a password-protected safe using a Raspberry Pi Pico board
Note: You can use this sketch with any Raspberry Pi Pico.
'''
import machine
from machine import Pin, I2C
import time
from lcd_api import LcdApi
from pico_i2c_lcd import I2cLcd
from servo import Servo
# Define LCD constants
I2C_ADDR = 0x27
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
# Define keypad rows and columns
rows = [Pin(26, Pin.OUT), Pin(22, Pin.OUT), Pin(21, Pin.OUT), Pin(20, Pin.OUT)]
cols = [Pin(19, Pin.IN, Pin.PULL_DOWN), Pin(18, Pin.IN, Pin.PULL_DOWN),
Pin(17, Pin.IN, Pin.PULL_DOWN), Pin(16, Pin.IN, Pin.PULL_DOWN)]
# Key map (according to the 4x4 keypad layout)
keys = [
['1', '2', '3', 'A'],
['4', '5', '6', 'B'],
['7', '8', '9', 'C'],
['*', '0', '#', 'D']
]
# Initialize buzzer on pin 15
buzzer = Pin(15, Pin.OUT)
def read_keypad():
for i, row in enumerate(rows):
row.value(1) # Activate current row
for j, col in enumerate(cols):
if col.value() == 1: # If a key is pressed
row.value(0)
return keys[i][j]
row.value(0)
return None
def beep_success():
"""صوت ناجح - صفارة واحدة طويلة"""
buzzer.value(1) # تشغيل البوزر
time.sleep(0.5) # استمرارية الصوت لمدة 0.5 ثانية
buzzer.value(0) # إيقاف البوزر
def beep_error():
"""صوت خطأ - صفارتين قصيرتين"""
# الصفارة الأولى
buzzer.value(1)
time.sleep(0.2)
buzzer.value(0)
time.sleep(0.1)
# الصفارة الثانية
buzzer.value(1)
time.sleep(0.2)
buzzer.value(0)
# Initialize I2C for LCD (SDA=GP0, SCL=GP1 on Pico)
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)
# Initialize servo (GP3 on Pico)
servo_pin = Pin(3)
servo = Servo(servo_pin)
# Set password and other variables
password = "1234B" # Set the password to open the safe
MAX_PASSWORD_LENGTH = 5 # maximum password length
entered_password = "" # Store the entered password
safe_open = False # Store the state of the safe (open or closed)
# Initialize LCD
lcd.clear()
lcd.move_to(1, 0)
lcd.putstr("Voltaat Learn")
lcd.move_to(1, 1)
lcd.putstr("Security Safe")
# Variables for timing
prev_millis = time.ticks_ms()
show_enter_password = False
show_safe_closed = False
safe_closed_millis = 0
last_key_time = 0
key_debounce_delay = 200 # 200ms debounce delay
# Commands inside main loop run forever
while True:
current_millis = time.ticks_ms()
# Show "Enter Password" message after 5 seconds
if not show_enter_password and time.ticks_diff(current_millis, prev_millis) >= 5000:
show_enter_password = True
prev_millis = current_millis
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Enter Password:")
# Read keypad input with debouncing
key = None
if time.ticks_diff(current_millis, last_key_time) >= key_debounce_delay:
key = read_keypad()
if key:
last_key_time = current_millis
# Handle password entry
if show_enter_password and key:
if key == '#': # Check if enter key is pressed
if entered_password == password: # Compare entered password with the correct password
if safe_open: # If safe is already open, close it and ask to enter password again
safe_open = False
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Press C to close")
entered_password = "" # Clear entered password
else: # If safe is closed, open it and ask to close it
safe_open = True
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Safe is open")
lcd.move_to(0, 1)
lcd.putstr("Press C to close")
servo.write(90) # Open the safe by turning the servo to 90 degrees
entered_password = "" # Clear entered password
# تشغيل صوت النجاح
beep_success()
else: # Incorrect password entered
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Wrong Password!")
# تشغيل صوت الخطأ
beep_error()
time.sleep(2)
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Enter Password:")
entered_password = "" # Clear entered password
elif key == '*': # Check if clear key is pressed
entered_password = "" # Clear entered password
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Enter Password:")
elif key == 'C': # Check if C key is pressed
if safe_open: # If safe is open, close it
safe_open = False
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Safe is closed")
servo.write(0) # Close the safe by turning the servo to 0 degrees
show_safe_closed = True
safe_closed_millis = current_millis
entered_password = "" # Clear entered password
# تشغيل صوت عند الإغلاق
beep_success()
elif key == 'D': # Check if D key is pressed
if len(entered_password) > 0: # If password is not empty, delete last character
entered_password = entered_password[:-1]
lcd.move_to(0, 1)
lcd.putstr(" " * 16) # Clear the password field on the LCD screen
lcd.move_to(0, 1)
# Print asterisks instead of the actual password characters
lcd.putstr("*" * len(entered_password))
else: # Append entered key to the entered password
if len(entered_password) < MAX_PASSWORD_LENGTH and not safe_open:
entered_password += key
lcd.move_to(0, 1)
# Print asterisks instead of the actual password characters
lcd.putstr("*" * len(entered_password))
# Show "Safe Closed" message for 2 seconds after the safe is closed
if show_safe_closed and time.ticks_diff(current_millis, safe_closed_millis) >= 2000:
show_safe_closed = False
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Enter Password:")
time.sleep(0.05) # Small delay to prevent excessive CPU usage