import machine
import utime
from machine import Pin, PWM

# Define Servo
servo = PWM(Pin(2), freq=50)
led = Pin(15, Pin.OUT)

# Define row and column pins for keypad
ROW_PINS = [13, 12, 14, 27]
COL_PINS = [26, 25, 33, 32]
# Initialize row pins as inputs with pull up
rows = [Pin(pin, Pin.IN, Pin.PULL_UP) for pin in ROW_PINS]
# Initialize column pins as outputs
cols = [Pin(pin, Pin.OUT) for pin in COL_PINS]
keys = [
    ['1', '2', '3', 'A'],
    ['4', '5', '6', 'B'],
    ['7', '8', '9', 'C'],
    ['*', '0', '#', 'D']
]

# Constants
CORRECT_CODE = '1729'
entered_code = ''
door_opened_time = None
DOOR_OPEN_DURATION = 5  # 5 seconds

# Servo Control Functions
def open_door():
    global door_opened_time
    servo.duty(40)  # Adjust duty for fully open position
    print("Door Opened")  # Print message to console for debugging
    door_opened_time = utime.time()  # Record the time the door was opened

def close_door():
    servo.duty(75)  # Adjust duty for fully closed position
    print("Door Closed")  # Print message to console for debugging
    utime.sleep(2)

def scan_keypad():
    for col_index, col in enumerate(cols):
        col.off()  # Set the current col pin low
        for row_index, row in enumerate(rows):
            if row.value() == 0:  # Check if the row pin is low
                col.on()  # Set the col pin to high
                return keys[row_index][col_index]  # Return the key from the key map
        col.on()  # Set the col pin to high after scanning all rows
    return None  # Return None if no key is pressed

# Main Loop
print("Enter Code:")
while True:
    key = scan_keypad()
    if key:
        if key == 'D':
            close_door()
            door_opened_time = None  # Reset the door opened time
        elif len(entered_code) < 4:
            entered_code += key
            print('*', end='')  # Print '*' on the console to indicate code entry
        if len(entered_code) == 4:
            if entered_code == CORRECT_CODE:
                open_door()
            else:
                print("\nIncorrect Code")
                led.on()
                utime.sleep(2)
                led.off()
                utime.sleep(2)
            entered_code = ''
        utime.sleep(0.3)
    
    # Check if the door has been open for more than the allowed duration
    if door_opened_time is not None and (utime.time() - door_opened_time) > DOOR_OPEN_DURATION:
        close_door()
        door_opened_time = None  # Reset the door opened time
esp:0
esp:2
esp:4
esp:5
esp:12
esp:13
esp:14
esp:15
esp:16
esp:17
esp:18
esp:19
esp:21
esp:22
esp:23
esp:25
esp:26
esp:27
esp:32
esp:33
esp:34
esp:35
esp:3V3
esp:EN
esp:VP
esp:VN
esp:GND.1
esp:D2
esp:D3
esp:CMD
esp:5V
esp:GND.2
esp:TX
esp:RX
esp:GND.3
esp:D1
esp:D0
esp:CLK
keypad1:R1
keypad1:R2
keypad1:R3
keypad1:R4
keypad1:C1
keypad1:C2
keypad1:C3
keypad1:C4
led1:A
led1:C
servo2:GND
servo2:V+
servo2:PWM
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL