# 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 / Emergency)
rgb_green = Pin(18, Pin.OUT) # Green LED (Access Granted)
buzzer = Pin(15, Pin.OUT) # Buzzer for incorrect passcode / emergency alarm
emergency_button = Pin(34, Pin.IN, Pin.PULL_UP) # Pushbutton for emergency lockdown
# ADDITIONAL PIN CONFIGURATION FOR POTENTIOMETER (Pin 39)
potentiometer_pin = Pin(39, Pin.IN) # Pin 39 connected to potentiometer
adc = machine.ADC(potentiometer_pin) # Create ADC object for Pin 39
adc.width(machine.ADC.WIDTH_12BIT) # Set ADC width to 12 bits (0-4095 range)
adc.atten(machine.ADC.ATTN_0DB) # Set ADC attenuation (0-3.3V range)
# 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
buzzer.value(0) # Make sure the buzzer is off
print("Buzzer OFF")
# FUNCTION TO CONTROL SERVO MOTOR (DOOR LOCK/UNLOCK)
def control_servo(open_door, speed):
if open_door:
servo.duty(speed) # Adjust the servo speed based on potentiometer value
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, speed=25) # Adjust speed of servo
# 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, speed=75) # 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.value(1) # Turn on buzzer
sleep(0.3)
rgb_red.on()
buzzer.value(0) # Turn off buzzer
sleep(0.3)
sleep(3)
turn_off_system()
# FUNCTION TO ACTIVATE EMERGENCY LOCKDOWN MODE (Triggered by PB)
def emergency_lockdown(pin):
global door_locked
# Lock door immediately
control_servo(open_door=False, speed=75) # Lock door
lcd.clear()
lcd.putstr("Emergency Mode!")
update_tft("EMERGENCY LOCKDOWN", color=color565(255, 0, 0)) # Red text on TFT
# Activate alarm and red LED
buzzer.value(1) # Start buzzer (fully on)
rgb_red.off() # Red LED ON for emergency
rgb_green.on() # Turn off green LED to indicate the alert
sleep(5) # Keep alarm and LED on for a short period
# Disable further input (for safety)
turn_off_system()
# FUNCTION TO ADJUST SERVO SPEED BASED ON POTENTIOMETER
def adjust_servo_speed():
# Read potentiometer value (0-4095)
pot_value = adc.read() # Get potentiometer reading
# Print potentiometer value for debugging
print("Potentiometer Value:", pot_value)
# Map potentiometer value to servo speed (duty cycle between 0-1023)
speed = int(pot_value / 4095 * 1023) # Map to a duty cycle range for servo
# Adjust servo speed (duty cycle) based on potentiometer value
return speed
# SET PIR INTERRUPT
pir_sensor.irq(trigger=Pin.IRQ_RISING, handler=sub_pir)
# SET BUTTON INTERRUPT FOR EMERGENCY LOCKDOWN
emergency_button.irq(trigger=Pin.IRQ_FALLING, handler=emergency_lockdown)
# SYSTEM STARTS IN OFF STATE
turn_off_system()
# MAIN LOOP (SYSTEM DOES NOTHING UNTIL MOTION IS DETECTED OR EMERGENCY BUTTON IS PRESSED)
while True:
speed = adjust_servo_speed() # Continuously adjust the servo speed based on the potentiometer value
sleep(0.1) # Small delay to avoid excessive updates