from machine import Pin, PWM, I2C
import time
# ==================== PIN CONFIGURATION ====================
PASSWORD = "21907894"
# Keypad: 4 rows and 4 columns
rows = [
Pin(6, Pin.OUT),
Pin(7, Pin.OUT),
Pin(8, Pin.OUT),
Pin(9, Pin.OUT)
]
cols = [
Pin(10, Pin.IN, Pin.PULL_DOWN),
Pin(11, Pin.IN, Pin.PULL_DOWN),
Pin(12, Pin.IN, Pin.PULL_DOWN),
Pin(13, Pin.IN, Pin.PULL_DOWN)
]
KEYS = [
["1", "2", "3", "A"],
["4", "5", "6", "B"],
["7", "8", "9", "C"],
["*", "0", "#", "D"]
]
# Servo
servo = PWM(Pin(15))
servo.freq(50)
# LEDs
red_led = Pin(2, Pin.OUT)
green_led = Pin(3, Pin.OUT)
# LCD: I2C address 0x27
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=100000)
LCD_ADDR = 0x27
BL = 0x08
EN = 0x04
RS = 0x01
# ==================== LCD DRIVER ====================
def lcd_write_byte(data):
i2c.writeto(LCD_ADDR, bytes([data | BL]))
def lcd_pulse(data):
lcd_write_byte(data | EN)
time.sleep_us(500)
lcd_write_byte(data & ~EN)
time.sleep_us(100)
def lcd_send(value, mode):
high = value & 0xF0
low = (value << 4) & 0xF0
lcd_write_byte(high | mode)
lcd_pulse(high | mode)
lcd_write_byte(low | mode)
lcd_pulse(low | mode)
def lcd_cmd(value):
lcd_send(value, 0)
def lcd_char(value):
lcd_send(ord(value), RS)
def lcd_init():
time.sleep_ms(50)
for _ in range(3):
lcd_write_byte(0x30)
lcd_pulse(0x30)
time.sleep_ms(5)
lcd_write_byte(0x20)
lcd_pulse(0x20)
lcd_cmd(0x28)
lcd_cmd(0x0C)
lcd_cmd(0x06)
lcd_cmd(0x01)
time.sleep_ms(5)
def lcd_clear():
lcd_cmd(0x01)
time.sleep_ms(3)
def lcd_line(row, text):
lcd_cmd(0x80 if row == 0 else 0xC0)
text = str(text)[:16].ljust(16)
for character in text:
lcd_char(character)
def lcd_message(line1, line2=""):
lcd_clear()
lcd_line(0, line1)
lcd_line(1, line2)
# ==================== SERVO CONTROL ====================
def set_servo(angle):
# Convert angle to a 50 Hz servo duty cycle
duty = int(1638 + (angle / 180) * (8192 - 1638))
servo.duty_u16(duty)
# ==================== KEYPAD SCAN ====================
def scan_keypad():
for r in range(4):
for row in rows:
row.value(0)
rows[r].value(1)
time.sleep_us(50)
for c in range(4):
if cols[c].value():
key = KEYS[r][c]
# Wait for key release to avoid repeated input
while cols[c].value():
time.sleep_ms(10)
time.sleep_ms(30)
return key
return None
# ==================== LOCK STATE ====================
entered = ""
unlocked = False
wrong_attempts = 0
LOCKOUT_SECONDS = 10
lockout_until = 0
def show_locked():
red_led.value(1)
green_led.value(0)
set_servo(0)
lcd_message("LOCKED", "Enter PIN:")
def show_unlocked():
red_led.value(0)
green_led.value(1)
set_servo(90)
lcd_message("ACCESS GRANTED", "* to lock")
# ==================== MAIN PROGRAM ====================
print("Combination lock started")
print("LCD address:", hex(LCD_ADDR))
try:
print("STEP 1: Starting LCD")
lcd_init()
print("STEP 2: LCD initialized")
lcd_message("DIAGNOSTIC", "PLEASE WAIT")
print("STEP 3: LCD message sent")
time.sleep(3)
print("STEP 4: Starting servo and LEDs")
show_locked()
print("STEP 5: Lock screen sent")
while True:
now = time.time()
# Handle temporary lockout
if now < lockout_until:
remaining = lockout_until - now
lcd_message("TOO MANY ERRORS", "Wait: {} sec".format(remaining))
time.sleep_ms(200)
continue
key = scan_keypad()
if key is None:
time.sleep_ms(20)
continue
print("Key pressed:", key)
# While unlocked, '*' locks the system again
if unlocked:
if key == "*":
unlocked = False
entered = ""
wrong_attempts = 0
show_locked()
print("System locked")
continue
# Clear the currently entered PIN
if key == "*":
entered = ""
lcd_message("LOCKED", "PIN cleared")
time.sleep_ms(500)
lcd_message("LOCKED", "Enter PIN:")
continue
# Submit the PIN
if key == "#":
if entered == PASSWORD:
unlocked = True
wrong_attempts = 0
entered = ""
show_unlocked()
print("Correct PIN: unlocked")
else:
wrong_attempts += 1
entered = ""
print("Incorrect PIN. Attempts:", wrong_attempts)
if wrong_attempts >= 3:
lockout_until = time.time() + LOCKOUT_SECONDS
lcd_message("TOO MANY ERRORS", "Wait: 10 sec")
print("Lockout for 10 seconds")
else:
lcd_message(
"WRONG PIN",
"Attempts: {}/3".format(wrong_attempts)
)
time.sleep_ms(1200)
lcd_message("LOCKED", "Enter PIN:")
continue
# Accept numeric keys only
if key.isdigit():
if len(entered) < len(PASSWORD):
entered += key
# Show asterisks rather than revealing the PIN
lcd_message("Enter PIN:", "*" * len(entered))
except Exception as error:
print("ERROR:", error)
try:
lcd_message("SYSTEM ERROR", "Check console")
except Exception:
pass