# IMPORT NECESSARY LIBRARIES
import machine
from machine import Pin, I2C, SPI, PWM
from time import sleep
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
from ili9341 import Display, color565
from xglcd_font import XglcdFont
# PIN CONFIGURATION
pir_sensor = Pin(36, Pin.IN) # PIR motion sensor
servo = PWM(Pin(32), freq=50) # Servo motor on GPIO32 (PWM for door lock/unlock)
rgb_red = Pin(19, Pin.OUT) # Red LED (Access Denied)
rgb_green = Pin(18, Pin.OUT) # Green LED (Access Granted)
buzzer = Pin(15, Pin.OUT) # Buzzer for incorrect passcode
# I2C SETUP FOR 1602 LCD
sda = Pin(21)
scl = Pin(22)
i2c = I2C(0, scl=scl, sda=sda, freq=400000)
lcd = I2cLcd(i2c, 0x27, 2, 16) # LCD 16x2
# SPI SETUP FOR TFT DISPLAY
sck = machine.Pin(4)
mosi = machine.Pin(16)
miso = machine.Pin(0)
spi = machine.SPI(1, baudrate=32000000, sck=sck, mosi=mosi, miso=miso)
rst = machine.Pin(5)
dc = machine.Pin(17)
cs = machine.Pin(23)
# TFT DISPLAY SETUP
display = Display(spi, dc=dc, cs=cs, rst=rst)
arcadepix = XglcdFont('ArcadePix9x11.c', 9, 11)
# KEYPAD SETUP (WITHOUT LIBRARY)
ROWS = [2, 13, 12, 14] # Connect to keypad row pins
COLS = [27, 26, 25, 33] # Connect to keypad column pins
key_map = [['1', '2', '3', 'A'],
['4', '5', '6', 'B'],
['7', '8', '9', 'C'],
['*', '0', '#', 'D']]
row_pins = [Pin(pin, Pin.OUT) for pin in ROWS]
col_pins = [Pin(pin, Pin.IN, Pin.PULL_DOWN) for pin in COLS]
# CORRECT PASSCODE
correct_passcode = "1234" # Change this as needed
# FUNCTION TO UPDATE TFT DISPLAY
def update_tft(message, color=color565(255, 255, 255)):
display.fill_rectangle(10, 50, 220, 20, color565(0, 0, 0)) # Clear text area
display.draw_text(10, 50, message, arcadepix, color)
# FUNCTION TO TURN OFF SYSTEM
def turn_off_system():
rgb_red.on()
rgb_green.on()
lcd.clear()
display.fill_rectangle(0, 0, 240, 320, color565(0, 0, 0)) # Clear TFT display
print('off')
# FUNCTION TO CONTROL SERVO MOTOR (DOOR LOCK/UNLOCK)
def control_servo(open_door):
if open_door:
servo.duty(25) # Adjust for door open position
else:
servo.duty(75) # Adjust for locked position
# FUNCTION TO HANDLE PIR SENSOR INTERRUPT
def sub_pir(pin):
if pir_sensor.value() == 1:
rgb_red.off()
rgb_green.on()
lcd.clear()
lcd.move_to(3, 0)
lcd.putstr("Door Locked")
update_tft("MOTION DETECTED", color=color565(255, 0, 0)) # Red text on TFT
sleep(1)
enter_passcode()
# FUNCTION TO SCAN KEYPAD
def get_key():
""" Scans the keypad and returns the key pressed. """
for i, row in enumerate(row_pins):
row.value(1) # Activate row
for j, col in enumerate(col_pins):
if col.value() == 1: # Key is pressed
row.value(0) # Deactivate row
return key_map[i][j]
row.value(0) # Deactivate row
return None
# FUNCTION TO ENTER PASSCODE
def enter_passcode():
lcd.clear()
lcd.putstr("Enter Passcode:")
update_tft("PASSWORD REQUIRED", color=color565(255, 255, 0)) # Yellow text on TFT
user_input = ""
while len(user_input) < 4: # Wait for 4-digit passcode
key = get_key() # Read keypad input
if key:
lcd.move_to(len(user_input), 1)
lcd.putstr("*") # Display * instead of the number for security
user_input += key
update_tft("Passcode: " + "*" * len(user_input), color=color565(255, 255, 255)) # Masked display
sleep(0.3) # Prevent multiple inputs for one key press
# CHECK PASSCODE
if user_input == correct_passcode:
access_granted()
else:
access_denied()
# FUNCTION WHEN ACCESS IS GRANTED
def access_granted():
lcd.clear()
lcd.putstr("Access Granted")
update_tft("CORRECT PASSCODE", color=color565(0, 255, 0)) # Green text on TFT
rgb_green.off()
rgb_red.on()
# Unlock door using servo
control_servo(open_door=True)
# Display "Door Unlocked" on LCD
lcd.clear()
lcd.putstr("Door Unlocked")
update_tft("DOOR OPENED", color=color565(0, 255, 0)) # Green text on TFT
sleep(5)
control_servo(open_door=False) # Relock door
turn_off_system()
# FUNCTION WHEN ACCESS IS DENIED
def access_denied():
lcd.clear()
lcd.putstr("Access Denied!")
update_tft("WRONG PASSCODE!", color=color565(255, 0, 0)) # Red text on TFT
rgb_red.off()
rgb_green.on()
# Blink red LED and buzzer for warning
for _ in range(3):
rgb_red.off()
buzzer.on()
sleep(0.3)
rgb_red.on()
buzzer.off()
sleep(0.3)
sleep(3)
turn_off_system()
# SET PIR INTERRUPT
pir_sensor.irq(trigger=Pin.IRQ_RISING, handler=sub_pir)
# SYSTEM STARTS IN OFF STATE
turn_off_system()
# MAIN LOOP (SYSTEM DOES NOTHING UNTIL MOTION DETECTED)
while True:
sleep(1) # System stays idle until motion is detected