from machine import Pin, I2C, PWM
import time
import dht

# Library untuk I2C LCD
class I2cLcd:
    # Constants
    LCD_CLR = 0x01
    LCD_HOME = 0x02

    LCD_ENTRY_MODE = 0x04
    LCD_ENTRY_INC = 0x02
    LCD_ENTRY_SHIFT = 0x01

    LCD_ON_CTRL = 0x08
    LCD_ON_DISPLAY = 0x04
    LCD_ON_CURSOR = 0x02
    LCD_ON_BLINK = 0x01

    LCD_MOVE = 0x10
    LCD_MOVE_DISP = 0x08
    LCD_MOVE_RIGHT = 0x04

    LCD_FUNCTION = 0x20
    LCD_FUNCTION_8BIT = 0x10
    LCD_FUNCTION_2LINES = 0x08
    LCD_FUNCTION_10DOTS = 0x04

    LCD_CGRAM = 0x40
    LCD_DDRAM = 0x80

    LCD_RS = 0x01
    LCD_RW = 0x02
    LCD_EN = 0x04

    def __init__(self, i2c, addr, rows, cols):
        self.i2c = i2c
        self.addr = addr
        self.rows = rows
        self.cols = cols
        self.backlight = True

        self.i2c.writeto(self.addr, bytearray([0x33]))  # Initialize
        self.i2c.writeto(self.addr, bytearray([0x32]))  # Set to 4-bit mode
        self.i2c.writeto(self.addr, bytearray([0x28]))  # 2 line display
        self.i2c.writeto(self.addr, bytearray([0x0C]))  # Display on, cursor off
        self.clear()

    def clear(self):
        self.command(self.LCD_CLR)
        time.sleep_ms(2)

    def command(self, cmd):
        self.i2c.writeto(self.addr, bytearray([cmd & 0xF0 | 0x04]))
        self.i2c.writeto(self.addr, bytearray([cmd & 0xF0]))
        self.i2c.writeto(self.addr, bytearray([(cmd << 4) & 0xF0 | 0x04]))
        self.i2c.writeto(self.addr, bytearray([(cmd << 4) & 0xF0]))

    def putstr(self, string):
        for char in string:
            self.i2c.writeto(self.addr, bytearray([ord(char) & 0xF0 | 0x05]))
            self.i2c.writeto(self.addr, bytearray([ord(char) & 0xF0 | 0x01]))
            self.i2c.writeto(self.addr, bytearray([(ord(char) << 4) & 0xF0 | 0x05]))
            self.i2c.writeto(self.addr, bytearray([(ord(char) << 4) & 0xF0 | 0x01]))

# Konfigurasi DHT22
dht_sensor = dht.DHT22(Pin(4))

# Konfigurasi I2C untuk LCD1602
i2c = I2C(0, scl=Pin(22), sda=Pin(21), freq=400000)
lcd = I2cLcd(i2c, 0x27, 2, 16)

# Konfigurasi Servo pada pin GPIO18
servo = PWM(Pin(18), freq=50)

# Fungsi untuk menggerakkan servo (0 derajat - 180 derajat)
def set_servo_angle(angle):
    # Hitung duty cycle berdasarkan sudut (0-180 derajat)
    minDuty = 40   # Duty cycle untuk 0 derajat
    maxDuty = 115  # Duty cycle untuk 180 derajat
    duty = int(minDuty + (angle / 180.0) * (maxDuty - minDuty))
    servo.duty(duty)

# Fungsi untuk menampilkan data pada LCD
def update_lcd(text1, text2):
    lcd.clear()
    lcd.putstr(text1)
    lcd.putstr(text2)

while True:
    try:
        # Membaca data dari sensor DHT22
        dht_sensor.measure()
        suhu = dht_sensor.temperature()
        kelembaban = dht_sensor.humidity()

        print(f"Suhu: {suhu}°C, Kelembaban: {kelembaban}%")

        # Tampilkan data suhu dan kelembaban pada LCD
        update_lcd(f"Suhu: {suhu}C", f"Kelembaban: {kelembaban}%")

        # Cek apakah kelembaban rendah (misal < 40%)
        if kelembaban < 40:
            # Tampilkan penyiraman pada LCD
            update_lcd("Penyiraman", "Aktif")
            print("Penyiraman Aktif!")

            # Menggerakkan servo ke sudut 90 derajat (aktif)
            set_servo_angle(90)
        else:
            # Servo dalam keadaan mati (sudut 0 derajat)
            set_servo_angle(0)
            update_lcd(f"Suhu: {suhu}C", f"Kelembaban: {kelembaban}%")

        time.sleep(2)

    except OSError as e:
        print("Gagal membaca sensor!")