from machine import Pin, SoftI2C
import network
import urequests
import utime
from time import sleep
from i2c_lcd import I2cLcd
from servo import Servo
import time
import umqtt.simple as mqtt  # Import MQTT library

# WiFi Connection
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.connect('Wokwi-GUEST', '')  # Adjust WiFi credentials if needed
while not sta_if.isconnected():
    print(".", end="")
    utime.sleep(0.1)
print("Connected!")

# MQTT Parameters
MQTT_BROKER = "broker.hivemq.com"  # Public MQTT broker for testing
MQTT_PORT = 1883
MQTT_CLIENT_ID = "ESP32_SmartDoorLock"
MQTT_TOPIC = "SmartDoorLock/Status"

# Initialize MQTT client
mqtt_client = mqtt.MQTTClient(MQTT_CLIENT_ID, MQTT_BROKER, MQTT_PORT)

def mqtt_connect():
    try:
        mqtt_client.connect()
        print("Connected to MQTT Broker")
    except Exception as e:
        print(f"Failed to connect to MQTT Broker: {e}")

def mqtt_publish(topic, message):
    try:
        mqtt_client.publish(topic, message)
        print(f"Published to {topic}: {message}")
    except Exception as e:
        print(f"Failed to publish message: {e}")

# Keypad Setup
keys = [['1', '2', '3', 'A'],
        ['4', '5', '6', 'B'],
        ['7', '8', '9', 'C'],
        ['*', '0', '#', 'D']]

cols = [5, 18, 19, 23]
rows = [15, 4, 16, 17]

row_pins = [Pin(pin_name, mode=Pin.OUT) for pin_name in rows]
col_pins = [Pin(pin_name, mode=Pin.IN, pull=Pin.PULL_DOWN) for pin_name in cols]

# Initialize servo
servo = Servo(pin=26)

# I2C LCD Setup
i2c = SoftI2C(scl=Pin(22), sda=Pin(21), freq=400000)
lcd = I2cLcd(i2c, 0x27, 4, 20)

# Add a buffer for password input
password_buffer = ""  # Buffer to store the entered password
correct_password = "1234"  # Example correct password

# Functions for keypad scan
def scan(row, col):
    row_pins[row].value(1)
    key = None
    if col_pins[col].value() == 1:
        key = keys[row][col]
    row_pins[row].value(0)
    return key

def scankeys():
    key = None
    for row in range(4):
        for col in range(4):
            key = scan(row, col)
            if key:
                utime.sleep_ms(200)  # Debouncing delay (200 ms)
                return key
    return None

# Door lock functions
def True_Pass():
    status = "Door Opened"
    mqtt_publish(MQTT_TOPIC, status)  # Publish to MQTT
    servo.move(180)
    lcd.clear()
    lcd.putstr("Access Granted")
    sleep(5)
    Default_Screen()
    status = "Door Closed"
    mqtt_publish(MQTT_TOPIC, status)  # Publish to MQTT

def Wrong_Pass():
    status = "Wrong Password"
    mqtt_publish(MQTT_TOPIC, status)  # Publish to MQTT
    lcd.clear()
    lcd.putstr("Access Denied")
    sleep(2)
    Default_Screen()

# Process keypad input
def process_key(key):
    global password_buffer
    lcd.clear()
    masked_password = "*" * len(password_buffer)  # Mask the entered password with asterisks

    if key == "#":  # Confirm input
        if password_buffer == correct_password:
            True_Pass()
        else:
            Wrong_Pass()
        password_buffer = ""  # Reset the buffer
    elif key == "*":  # Clear input
        password_buffer = ""
        lcd.clear()
        lcd.putstr("Input cleared")
    else:
        if len(password_buffer) < len(correct_password):  # Limit buffer length
            password_buffer += key
            masked_password = "*" * len(password_buffer)  # Update the masked password

    lcd.clear()
    lcd.putstr(f"Input: {masked_password}")  # Display the masked password

# Default screen for LCD
def Default_Screen():
    lcd.clear()
    lcd.putstr("Smart Door Lock\nEnter Pass:")

# Main Loop
Default_Screen()
mqtt_connect()

while True:
    print("Waiting for keypad input...")
    key = scankeys()
    if key:
        print(f"Key Pressed: {key}")
        process_key(key)