import board
import busio
import digitalio
import time
import lcd
import i2c_pcf8574_interface
# -------------------------------------------------------------
# 1. HARDWARE SETUP
# -------------------------------------------------------------
# I2C LCD (GP4 = SDA, GP5 = SCL)
i2c_bus = busio.I2C(scl=board.GP5, sda=board.GP4)
i2c_obj = i2c_pcf8574_interface.I2CPCF8574Interface(i2c_bus, 0x27)
display = lcd.LCD(i2c_obj, num_rows=2, num_cols=16)
# Switches (Active Low - Pull UP)
# SW1 = Motion (GP15), SW2 = Reset (GP14)
sw1 = digitalio.DigitalInOut(board.GP15)
sw1.direction = digitalio.Direction.INPUT
sw1.pull = digitalio.Pull.UP
sw2 = digitalio.DigitalInOut(board.GP14)
sw2.direction = digitalio.Direction.INPUT
sw2.pull = digitalio.Pull.UP
# Keypad Rows (Outputs - GP13 to GP10)
r1 = digitalio.DigitalInOut(board.GP13)
r2 = digitalio.DigitalInOut(board.GP12)
r3 = digitalio.DigitalInOut(board.GP11)
r4 = digitalio.DigitalInOut(board.GP10)
rows = [r1, r2, r3, r4]
for r in rows:
r.direction = digitalio.Direction.OUTPUT
r.value = True # Set idle to HIGH
# Keypad Columns (Inputs - GP9 to GP6)
c1 = digitalio.DigitalInOut(board.GP9)
c2 = digitalio.DigitalInOut(board.GP8)
c3 = digitalio.DigitalInOut(board.GP7)
c4 = digitalio.DigitalInOut(board.GP6)
cols = [c1, c2, c3, c4]
for c in cols:
c.direction = digitalio.Direction.INPUT
c.pull = digitalio.Pull.UP
# -------------------------------------------------------------
# 2. SYSTEM VARIABLES
# -------------------------------------------------------------
PASSWORD = "1234"
entered_pin = ""
system_active = False
prev_sw1 = True
KEYMAP = [
["1", "2", "3", "A"],
["4", "5", "6", "B"],
["7", "8", "9", "C"],
["*", "0", "#", "D"]
]
# -------------------------------------------------------------
# 3. SCANNING FUNCTION
# -------------------------------------------------------------
def scan_keypad():
"""Checks every row and column manually"""
for r_idx in range(4):
rows[r_idx].value = False # Drive current row LOW
for c_idx in range(4):
if cols[c_idx].value == False: # If column reads LOW, key is pressed
key = KEYMAP[r_idx][c_idx]
time.sleep(0.2) # Basic Debounce
while cols[c_idx].value == False: # Wait for finger to lift
pass
rows[r_idx].value = True # Set row back to HIGH
return key
rows[r_idx].value = True # Set row back to HIGH
return None
# -------------------------------------------------------------
# 4. MAIN LOOP
# -------------------------------------------------------------
display.set_backlight(False) # Start with screen OFF (SDG 11 - Energy Save)
while True:
# --- SW1: MOTION SENSOR TOGGLE ---
if sw1.value == False and prev_sw1 == True:
system_active = not system_active
time.sleep(0.2)
if system_active:
display.set_backlight(True)
display.clear()
display.set_cursor_pos(0, 0)
display.print("Motion Detected")
display.set_cursor_pos(1, 0)
display.print("PIN: ____")
else:
display.set_backlight(False)
display.clear()
entered_pin = "" # Security reset
prev_sw1 = sw1.value
# --- KEYPAD & RESET (Only if Active) ---
if system_active:
# SW2: RESET INPUT
if sw2.value == False:
entered_pin = ""
display.set_cursor_pos(1, 5)
display.print("____") # Clear the underline area
time.sleep(0.2)
# KEYPAD SCAN
kp = scan_keypad()
if kp is not None:
if len(entered_pin) < 4:
entered_pin += kp
# Update LCD with stars
display.set_cursor_pos(1, 5)
display.print("*" * len(entered_pin))
# CHECK PASSWORD
if len(entered_pin) == 4:
time.sleep(0.4)
display.clear()
display.set_cursor_pos(0, 0)
if entered_pin == PASSWORD:
display.print("ACCESS GRANTED")
display.set_cursor_pos(1, 0)
display.print("Welcome Home!")
else:
display.print("ACCESS DENIED")
display.set_cursor_pos(1, 0)
display.print("Try Again")
time.sleep(2.0)
entered_pin = ""
display.clear()
display.set_cursor_pos(0, 0)
display.print("Motion Detected")
display.set_cursor_pos(1, 0)
display.print("PIN: ____")
time.sleep(0.01)