from machine import Pin, I2C
import dht
import time
from BlynkLib import Blynk
from lcd_api import LcdApi
from i2c_lcd import I2cLcd
from ds1307 import DS1307
import network

# Wi-Fi credentials
SSID = 'Wokwi-GUEST'
PASSWORD = ''

# Connect to Wi-Fi
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)

while not wlan.isconnected():
    time.sleep(1)

print("Connected to Wi-Fi:", wlan.ifconfig())

# Blynk authentication token
BLYNK_AUTH = 'np-OPFzaZiwkwKAJPq2--IUJ14Ld75Qp'
blynk = Blynk(BLYNK_AUTH)

# Initialize sensors and devices
dht_sensor = dht.DHT22(Pin(14))
pir_sensor = Pin(27, Pin.IN)
relay = Pin(19, Pin.OUT)
led = Pin(25, Pin.OUT)
led.value(0)
relay.value(0)

i2c_lcd = I2C(1, scl=Pin(22), sda=Pin(21), freq=400000)
lcd = I2cLcd(i2c_lcd, 0x27, 4, 20)
i2c_rtc = I2C(0, scl=Pin(26), sda=Pin(23), freq=400000)
rtc = DS1307(i2c_rtc)

DELAY_TIME = 10  # Delay after motion detected before turning off lamp

lamp_on = False
last_motion_time = 0
lamp_start_time = 0

last_temp = None
last_humidity = None
last_lamp_status = None
last_time = None

def get_time():
    """Get the current time from RTC."""
    try:
        datetime = rtc.datetime()
        if isinstance(datetime, tuple) and len(datetime) >= 7:
            return "{:02}:{:02}:{:02}".format(datetime[4], datetime[5], datetime[6])
    except Exception as e:
        print("Error reading from RTC:", e)
    return "00:00:00"

def update_lcd(temp, humidity, lamp_status, time_str, usage_time):
    """Update the LCD display with temperature, humidity, lamp status, time, and usage time."""
    global last_temp, last_humidity, last_lamp_status, last_time

    if (temp != last_temp or
        humidity != last_humidity or
        lamp_status != last_lamp_status or
        time_str != last_time):

        lcd.clear()
        lcd.putstr("Suhu: {}C".format(temp))
        lcd.move_to(0, 1)
        lcd.putstr("Kelembapan: {:.1f}%".format(humidity))
        lcd.move_to(0, 2)
        lcd.putstr("Lampu: {}".format("HIDUP" if lamp_status else "MATI"))
        lcd.move_to(0, 3)
        lcd.putstr("WaktuLampu: {} detik".format(usage_time))

        last_temp = temp
        last_humidity = humidity
        last_lamp_status = lamp_status
        last_time = time_str

def control_lamp(motion_detected):
    """Control lamp based on motion detection."""
    global lamp_on, last_motion_time, lamp_start_time

    if motion_detected:
        last_motion_time = time.time()
        if not lamp_on:
            turn_on_lamp()
    else:
        if lamp_on and (time.time() - last_motion_time > DELAY_TIME):
            turn_off_lamp()

def turn_on_lamp():
    """Turn on the lamp and LED."""
    global lamp_on, lamp_start_time
    relay.value(1)
    led.value(1)
    lamp_on = True
    lamp_start_time = time.time()
    print("Lamp ON - Time:", get_time())

def turn_off_lamp():
    """Turn off the lamp and LED."""
    global lamp_on
    relay.value(0)
    led.value(0)
    lamp_on = False
    print("Lamp OFF - Time:", get_time())

@blynk.on("V1")  # Handler for Virtual Pin 1
def v1_handler(value):
    global last_temp
    last_temp = value[0]  # Capture the temperature value
    print("Temperature set to:", last_temp)

@blynk.on("V2")  # Handler for Virtual Pin 2
def v2_handler(value):
    global last_humidity
    last_humidity = value[0]  # Capture the humidity value
    print("Humidity set to:", last_humidity)

@blynk.on("V3")  # Handler for Virtual Pin 3
def v3_handler(value):
    global lamp_on
    lamp_on = bool(value[0])  # Capture lamp status
    print("Lamp status set to:", lamp_on)
    if lamp_on:
        turn_on_lamp()
    else:
        turn_off_lamp()

try:
    while True:
        try:
            dht_sensor.measure()
            temperature = int(dht_sensor.temperature())
            humidity = dht_sensor.humidity()
        except OSError as e:
            print("Failed to read from DHT22:", e)
            continue

        current_time = get_time()
        motion_detected = pir_sensor.value()

        control_lamp(motion_detected)

        usage_time = int(time.time() - lamp_start_time) if lamp_on else 0

        update_lcd(temperature, humidity, lamp_on, current_time, usage_time)

        # Update Blynk with current readings
        blynk.virtual_write(1, temperature)  # Send temperature to virtual pin 1
        time.sleep(0.1)
        blynk.virtual_write(2, int(humidity))     # Send humidity to virtual pin 2
        blynk.virtual_write(3, int(lamp_on))      # Send lamp status to virtual pin 3

        blynk.run()  # Call the run method to handle Blynk communication
        time.sleep(1)

except KeyboardInterrupt:
    print("Program stopped")
    lcd.clear()
$abcdeabcde151015202530fghijfghij
NOCOMNCVCCGNDINLED1PWRRelay Module
GND5VSDASCLSQWRTCDS1307+