import time
from machine import I2C, Pin, ADC
import dht
from i2c_lcd import I2cLcd
from umqtt.robust import MQTTClient

# WiFi Configuration
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASSWORD = ""

# MQTT Configuration
MQTT_CLIENT_ID = "khalaf_esp32_project"
MQTT_BROKER = "broker.mqttdashboard.com"
MQTT_TOPIC_TEMPERATURE = "home/temperature"
MQTT_TOPIC_HUMIDITY = "home/humidity"
MQTT_TOPIC_LUMINOSITY = "home/luminosity"
MQTT_TOPIC_AC = "home/ac"
MQTT_TOPIC_MOTION = "home/motion"

# LCD Configuration
I2C_SDA = 21
I2C_SCL = 22
I2C_ADDR = 0x27
lcd = None

# DHT22 Configuration
DHT_PIN = 4
dht_sensor = dht.DHT22(Pin(DHT_PIN))

# LDR and LED Configuration
LDR_PIN = 34
LED_PIN = 2
LDR_THRESHOLD = 250

ldr = ADC(Pin(LDR_PIN))
ldr.width(ADC.WIDTH_10BIT)
ldr.atten(ADC.ATTN_11DB)
led = Pin(LED_PIN, Pin.OUT, value=0)

# PIR Sensor Configuration
PIR_PIN = 35
pir = Pin(PIR_PIN, Pin.IN)

# Air Conditioner Configuration
AC_PIN = 16  # Air Conditioner Control Pin
ac = Pin(AC_PIN, Pin.OUT, value=0)  # Initially OFF

# MQTT client
client = None

# Function to connect to WiFi
def connect_to_wifi():
    import network
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print("Connecting to WiFi...")
        wlan.connect(WIFI_SSID, WIFI_PASSWORD)
        while not wlan.isconnected():
            print(".", end="")
            time.sleep(0.5)
    print("\nWiFi connected!")
    print("IP Address:", wlan.ifconfig()[0])

# Function to connect to MQTT broker without encryption
def connect_to_mqtt():
    global client
    print("Connecting to MQTT...")
    client = MQTTClient(MQTT_CLIENT_ID, MQTT_BROKER)
    while True:
        try:
            client.connect()
            print("Connected to MQTT Broker!")
            break
        except Exception as e:
            print("Failed to connect to MQTT, retrying:", e)
            time.sleep(5)

# Function to read DHT22 sensor
def read_dht():
    for _ in range(3):
        try:
            dht_sensor.measure()
            temp = dht_sensor.temperature()
            hum = dht_sensor.humidity()
            return temp, hum
        except Exception as e:
            print("Failed to read DHT22, retrying:", e)
            time.sleep(2)
    return None, None

# Initialize the LCD
def init_lcd():
    global lcd
    i2c = I2C(0, sda=Pin(I2C_SDA), scl=Pin(I2C_SCL), freq=400000)
    print("I2C Scan:", i2c.scan())
    lcd = I2cLcd(i2c, I2C_ADDR, 4, 20)

# Method to overwrite text on the LCD using set cursor
def write_lcd(temp, humidity, ldr_value, led_status, motion_status, ac_status):
    lcd.clear()
    lcd.move_to(0, 0)
    lcd.putstr(f"Temp: {temp}C")
    lcd.move_to(0, 1)
    lcd.putstr(f"Humidity: {humidity}%")
    lcd.move_to(0, 2)
    lcd.putstr(f"Luminosity: {ldr_value}")
    lcd.move_to(0, 3)
    lcd.putstr(f"AC: {'ON' if ac_status == 1 else 'OFF'} | Motion: {motion_status}")

# Main program
def main():
    connect_to_wifi()
    connect_to_mqtt()
    init_lcd()

    while True:
        try:
            # Read LDR value
            ldr_value = ldr.read()
            ldr_value = max(0, min(ldr_value, 1023))  # Ensure valid range
            print("LDR Value:", ldr_value)

            # Read DHT22 values
            temperature, humidity = read_dht()
            if temperature is None or humidity is None:
                temperature = "N/A"
                humidity = "N/A"

            # Check PIR sensor status
            motion_detected = pir.value()
            motion_status = "Detected" if motion_detected else "No"

            # Control LED based on LDR
            if ldr_value < LDR_THRESHOLD:
                led.value(1)
                led_status = 1
            else:
                led.value(0)
                led_status = 0

            # Control Air Conditioner based on temperature
            if temperature != "N/A" and temperature >= 38:
                ac.value(1)  # Turn ON AC
                ac_status = 1
            else:
                ac.value(0)  # Turn OFF AC
                ac_status = 0

            # Update LCD
            write_lcd(temperature, humidity, ldr_value, led_status, motion_status, ac_status)

            # Publish data to MQTT
            if temperature != "N/A" and humidity != "N/A":
                try:
                    client.publish(MQTT_TOPIC_TEMPERATURE, str(temperature))
                    client.publish(MQTT_TOPIC_HUMIDITY, str(humidity))
                    client.publish(MQTT_TOPIC_LUMINOSITY, str(ldr_value))
                    client.publish(MQTT_TOPIC_AC, "ON" if ac_status == 1 else "OFF")
                    client.publish(MQTT_TOPIC_MOTION, motion_status)
                    print("Published to MQTT:")
                    print(f"Temp: {temperature}, Humidity: {humidity}, Luminosity: {ldr_value}")
                    print(f"AC: {'ON' if ac_status == 1 else 'OFF'}, Motion: {motion_status}")
                except Exception as e:
                    print("Error publishing to MQTT:", e)
                    connect_to_mqtt()  # Reconnect to MQTT if there's an error

            time.sleep(2)

        except Exception as e:
            print("Error in main loop:", e)
            connect_to_mqtt()  # Reconnect to MQTT if there's an error

# Run the program
main()