#include <ESP8266WiFi.h>
#include <FirebaseESP8266.h>
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

// Konfigurasi WiFi
const char* ssid = "Combat2024";
const char* password = "12345678";

// Konfigurasi Firebase
#define FIREBASE_HOST "https://jago-9a9a6-default-rtdb.firebaseio.com/"
#define FIREBASE_AUTH "Q3i1jDmc3Xh9UiUTaGUmOw4tVztV5TJ3INU9RoWN"

// NTP Client untuk mendapatkan waktu
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");

FirebaseData firebaseData;
FirebaseConfig config;
FirebaseAuth auth;

#define DHTPIN D5
#define RELAY_TEMP D3      // Relay untuk suhu (kipas)
#define RELAY_HUMIDITY D6  // Relay untuk kelembapan (lampu)
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2); // Pastikan alamat sesuai dengan modul yang digunakan

int ageInWeeks = 1; // Default, nanti diambil dari Firebase

// Variabel untuk mode kontrol
bool autoModeFan = true;   // Default: mode otomatis untuk kipas
bool autoModeLight = true; // Default: mode otomatis untuk lampu
bool fanStatus = false;    // Status kipas (ON/OFF)
bool lightStatus = false;  // Status lampu (ON/OFF)

// Variabel untuk pengaturan tampilan LCD
unsigned long lastDisplayToggle = 0;
bool showMainDisplay = true;  // Untuk mengganti tampilan LCD

// Variabel untuk reconnect
unsigned long lastReconnectAttempt = 0;
const unsigned long reconnectInterval = 30000; // 30 detik

// Variabel untuk menyimpan status koneksi WiFi sebelumnya
bool previousWiFiStatus = false;

// Fungsi untuk logging ke Firebase dengan timestamp
void logToFirebase(const String& path, const String& message) {
  String timestamp = getCurrentTimestamp();
  String logMessage = timestamp + ": " + message;
  
  // Kirim log ke Firebase, menggunakan setString untuk memperbarui entri
  Firebase.setString(firebaseData, path, logMessage);
}

// Fungsi untuk mendapatkan waktu dari NTP
String getCurrentTimestamp() {
  timeClient.update();
  return String(timeClient.getEpochTime());
}

// Variabel untuk memeriksa koneksi WiFi
unsigned long lastWiFiCheck = 0;
const unsigned long wifiCheckInterval = 2000; // 2 detik

// Fungsi untuk memeriksa dan memulihkan koneksi WiFi
void checkWiFiConnection() {
  if (WiFi.status() != WL_CONNECTED) {
    unsigned long currentMillis = millis();
    
    // Coba reconnect setiap interval tertentu
    if (currentMillis - lastReconnectAttempt >= reconnectInterval) {
      logToFirebase("/logs/wifi", "WiFi Disconnected. Attempting to Reconnect");
      
      // Matikan WiFi dan nyalakan kembali
      WiFi.disconnect();
      delay(1000);
      
      WiFi.begin(ssid, password);
      
      lastReconnectAttempt = currentMillis;
    }
    
    // Tambahkan log ketika WiFi terputus
    if (previousWiFiStatus) {
      logToFirebase("/logs/wifi", "WiFi Connection Failed");
      previousWiFiStatus = false;
    }
  } else {
    // Jika WiFi terhubung, periksa apakah statusnya berubah
    if (!previousWiFiStatus) {
      logToFirebase("/logs/wifi", "WiFi Connected Successfully");
      Serial.println("\nWiFi connected");
      previousWiFiStatus = true;
    }
  }
}

void setup() {
  Serial.begin(115200);
  
  // Inisialisasi pin relay
  pinMode(RELAY_TEMP, OUTPUT);
  pinMode(RELAY_HUMIDITY, OUTPUT);
  digitalWrite(RELAY_TEMP, HIGH); // Pastikan relay mulai dalam keadaan OFF
  digitalWrite(RELAY_HUMIDITY, HIGH);

  // Inisialisasi LCD dengan deteksi kesalahan
  logToFirebase("/logs/lcd", "LCD Initialization Started");
  
  // Coba inisialisasi LCD dengan timeout
  bool lcdInitSuccess = false;
  Wire.begin();
  
  // Periksa apakah LCD merespons
  Wire.beginTransmission(0x27); // Alamat I2C LCD
  byte error = Wire.endTransmission();
  
  if (error == 0) {
    // LCD ditemukan, coba inisialisasi
    lcd.init();
    lcd.backlight();
    lcd.clear();
    lcd.begin(16,2);
    lcd.print("Initializing...");
    lcdInitSuccess = true;
  }
  
  if (lcdInitSuccess) {
    logToFirebase("/logs/lcd", "LCD Ready and Initialized");
    Serial.println("LCD initialized successfully");
  } else {
    logToFirebase("/logs/lcd", "LCD Initialization Failed - Check Connections");
    Serial.println("LCD initialization failed! Check wiring (GND, VCC, SDA, SCL)");
  }
  
  // Inisialisasi WiFi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  
  // Tunggu koneksi WiFi
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }
  
  if (WiFi.status() == WL_CONNECTED) {
    logToFirebase("/logs/wifi", "WiFi Connected Successfully");
    Serial.println("\nWiFi connected");
    
    // Inisialisasi NTP Client
    timeClient.begin();
    timeClient.setTimeOffset(25200); // Offset untuk WIB (GMT+7)
  } else {
    logToFirebase("/logs/wifi", "WiFi Connection Failed");
    Serial.println("\nWiFi connection failed");
  }

  // Inisialisasi DHT
  dht.begin();
  logToFirebase("/logs/sensor", "DHT Sensor Initialized");

  // Konfigurasi Firebase
  config.host = FIREBASE_HOST;
  config.signer.tokens.legacy_token = FIREBASE_AUTH;

  Firebase.begin(&config, &auth);
  Firebase.reconnectWiFi(true);
  
  // Inisialisasi variabel kontrol di Firebase
  Firebase.setBool(firebaseData, "/control/fan/auto", autoModeFan);
  Firebase.setBool(firebaseData, "/control/light/auto", autoModeLight);
  Firebase.setBool(firebaseData, "/control/fan/status", fanStatus);
  Firebase.setBool(firebaseData, "/control/light/status", lightStatus);
}

void loop() {
  unsigned long currentMillis = millis();

  // Periksa koneksi WiFi setiap 2 detik
  if (currentMillis - lastWiFiCheck >= wifiCheckInterval) {
    checkWiFiConnection();
    lastWiFiCheck = currentMillis;
  }
  
  // Periksa koneksi LCD secara berkala
  checkLCDConnection();

  // Update NTP Client
  timeClient.update();

  // Baca sensor suhu dan kelembapan
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  // Periksa pembacaan sensor
  if (isnan(temperature) || isnan(humidity)) {
    logToFirebase("/logs/sensor", "Failed to Read from DHT Sensor");
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Sensor Error!");
    lcd.setCursor(0, 1);
    lcd.print("Check DHT sensor");
    delay(2000);
    return;
  } else {
    // Log pembacaan sensor berhasil (setiap 2 detik)
    static unsigned long lastSensorLog = 0;
    if (millis() - lastSensorLog > 2000) { // Log setiap 2 detik
      logToFirebase("/logs/sensor", "DHT Sensor Reading Successful");
      lastSensorLog = millis();
    }
  }

  // Ambil umur ayam dari Firebase
  if (Firebase.getInt(firebaseData, "/chicken_age")) {
    ageInWeeks = firebaseData.intData();
    Serial.print("Age: ");
    Serial.println(ageInWeeks);
  } else {
    Serial.print("Failed to get age from Firebase: ");
    Serial.println(firebaseData.errorReason());
    
    // Inisialisasi jika data belum ada
    if (firebaseData.errorReason() == "path not exist") {
      Firebase.setInt(firebaseData, "/chicken_age", 1);
      logToFirebase("/logs/system", "Initialized /chicken_age with default value 1");
    }
  }

  // Periksa mode kontrol (manual atau otomatis)
  checkControlMode();

  // Ganti tampilan LCD setiap 5 detik
  if (currentMillis - lastDisplayToggle >= 5000) {
    showMainDisplay = !showMainDisplay;
    lastDisplayToggle = currentMillis;
  }

  // Update tampilan LCD berdasarkan mode
  if (showMainDisplay) {
    updateMainDisplay(temperature, humidity);
  } else {
    updateModeDisplay();
  }

  // Kontrol suhu dan kelembapan berdasarkan mode
  if (autoModeFan) {
    // Mode otomatis untuk kipas (menggunakan fuzzy logic)
    controlTemperature(temperature);
  } else {
    // Mode manual untuk kipas
    if (fanStatus) {
      digitalWrite(RELAY_TEMP, LOW);  // Kipas ON
    } else {
      digitalWrite(RELAY_TEMP, HIGH); // Kipas OFF
    }
  }

  if (autoModeLight) {
    // Mode otomatis untuk lampu (menggunakan fuzzy logic)
    controlHumidity(humidity, temperature);
  } else {
    // Mode manual untuk lampu
    if (lightStatus) {
      digitalWrite(RELAY_HUMIDITY, LOW);  // Lampu ON
    } else {
      digitalWrite(RELAY_HUMIDITY, HIGH); // Lampu OFF
    }
  }

  // Kirim data ke Firebase
  Firebase.setFloat(firebaseData, "/sensor/temperature", temperature);
  Firebase.setFloat(firebaseData, "/sensor/Humidity", humidity);
  Firebase.setBool(firebaseData, "/relay/Kipas", digitalRead(RELAY_TEMP) == LOW);
  Firebase.setBool(firebaseData, "/relay/Lampu", digitalRead(RELAY_HUMIDITY) == LOW);

  delay(1000); // Tunggu 1 detik antara siklus
}

// Fungsi untuk tampilan utama (Temp, Hum, Age)
void updateMainDisplay(float temperature, float humidity) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Temp:");
  lcd.print(temperature, 1);
  lcd.print((char)223); // Simbol derajat
  lcd.print("C");

  lcd.setCursor(0, 1);
  lcd.print("Hum:");
  lcd.print(humidity, 1);
  lcd.print("% Age:");
  lcd.print(ageInWeeks);
  lcd.print("w");
}

// Fungsi untuk tampilan mode (Auto/Manual)
void updateModeDisplay() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Fan: ");
  lcd.print(autoModeFan ? "AUTO" : "MANUAL");
  lcd.print(" ");
  lcd.print(digitalRead(RELAY_TEMP) == LOW ? "ON" : "OFF");

  lcd.setCursor(0, 1);
  lcd.print("Light: ");
  lcd.print(autoModeLight ? "AUTO" : "MANUAL");
  lcd.print(" ");
  lcd.print(digitalRead(RELAY_HUMIDITY) == LOW ? "ON" : "OFF");
}

// Definisi fungsi fuzzy logic untuk kontrol suhu
void controlTemperature(float temp) {
  float minTemp, maxTemp, targetTemp;

  // Rentang suhu ideal berdasarkan umur ayam
  switch (ageInWeeks) {
    case 1: minTemp = 33; maxTemp = 35; targetTemp = 34; break;
    case 2: minTemp = 30; maxTemp = 33; targetTemp = 31.5; break;
    case 3: minTemp = 28; maxTemp = 30; targetTemp = 29; break;
    case 4: minTemp = 25; maxTemp = 28; targetTemp = 26.5; break;
    default: minTemp = 25; maxTemp = 28; targetTemp = 26.5;
  }

  // Menghitung derajat keanggotaan untuk berbagai kondisi suhu
  float veryLow = 0;     // Suhu sangat rendah (kondisi kritis)
  float tooLow = 0;      // Suhu terlalu rendah
  float optimal = 0;     // Suhu optimal
  float tooHigh = 0;     // Suhu terlalu tinggi
  float veryHigh = 0;    // Suhu sangat tinggi (kondisi kritis)
  
  // Keanggotaan "sangat rendah" - kondisi kritis
  if (temp < minTemp - 2) {
    veryLow = 1.0;  // Sangat rendah, kondisi kritis
  } else if (temp >= minTemp - 2 && temp < minTemp - 1) {
    veryLow = (minTemp - 1 - temp);  // Agak sangat rendah
    veryLow = constrain(veryLow, 0, 1);
  }
  
  // Keanggotaan "terlalu rendah"
  if (temp >= minTemp - 1.5 && temp < minTemp) {
    tooLow = (minTemp - temp) / 1.5;  // Agak rendah
    tooLow = constrain(tooLow, 0, 1);
  }
  
  // Keanggotaan "optimal"
  if (temp >= minTemp && temp <= maxTemp) {
    // Semakin dekat ke targetTemp, semakin optimal
    optimal = 1.0 - abs(temp - targetTemp) / ((maxTemp - minTemp) / 2.0);
    optimal = constrain(optimal, 0, 1);
  }
  
  // Keanggotaan "terlalu tinggi"
  if (temp > maxTemp && temp <= maxTemp + 1.5) {
    tooHigh = (temp - maxTemp) / 1.5;  // Agak tinggi
    tooHigh = constrain(tooHigh, 0, 1);
  }
  
  // Keanggotaan "sangat tinggi" - kondisi kritis
  if (temp > maxTemp + 2) {
    veryHigh = 1.0;  // Sangat tinggi, kondisi kritis
  } else if (temp > maxTemp + 1 && temp <= maxTemp + 2) {
    veryHigh = (temp - (maxTemp + 1)) / 1.0;  // Agak sangat tinggi
    veryHigh = constrain(veryHigh, 0, 1);
  }
  
  // Simpan status suhu untuk digunakan oleh fungsi controlHumidity
  bool isTempVeryCold = (veryLow > 0.3);
  bool isTempTooCold = (tooLow > 0.3);
  bool isTempVeryHot = (veryHigh > 0.3);
  
  // Kirim nilai fuzzy ke Firebase untuk monitoring
  Firebase.setFloat(firebaseData, "/fuzzy/temperature/veryLow", veryLow);
  Firebase.setFloat(firebaseData, "/fuzzy/temperature/tooLow", tooLow);
  Firebase.setFloat(firebaseData, "/fuzzy/temperature/optimal", optimal);
  Firebase.setFloat(firebaseData, "/fuzzy/temperature/tooHigh", tooHigh);
  Firebase.setFloat(firebaseData, "/fuzzy/temperature/veryHigh", veryHigh);
  
  // Keputusan berdasarkan derajat keanggotaan dan prioritas
  // Prioritas: Sangat tinggi > Sangat rendah > Terlalu tinggi > Optimal > Terlalu rendah
  if (veryHigh > 0.3) {  // Jika suhu sangat tinggi (kondisi kritis)
    digitalWrite(RELAY_TEMP, LOW);  // Kipas ON pada kecepatan maksimal
    // Log status ke Firebase
    Firebase.setString(firebaseData, "/status/temperature", "Sangat Tinggi - Kipas ON (Kritis)");
    Firebase.setBool(firebaseData, "/emergency/high_temperature", true);

  } else if (veryLow > 0.3) {  // Jika suhu sangat rendah (kondisi kritis)
    digitalWrite(RELAY_TEMP, HIGH);  // Kipas OFF
    // Nyalakan lampu untuk membantu meningkatkan suhu
    // Ini akan di-override oleh controlHumidity jika diperlukan
    digitalWrite(RELAY_HUMIDITY, LOW);  // Lampu ON untuk membantu meningkatkan suhu
    // Log status ke Firebase
    Firebase.setString(firebaseData, "/status/temperature", "Sangat Rendah - Kipas OFF, Lampu ON");
    Firebase.setBool(firebaseData, "/emergency/low_temperature", true);
    Firebase.setBool(firebaseData, "/emergency/high_temperature", false);

  } else if (tooHigh > 0.3) {  // Jika suhu terlalu tinggi
    digitalWrite(RELAY_TEMP, LOW);  // Kipas ON
    // Log status ke Firebase
    Firebase.setString(firebaseData, "/status/temperature", "Tinggi - Kipas ON");
    Firebase.setBool(firebaseData, "/emergency/low_temperature", false);
    Firebase.setBool(firebaseData, "/emergency/high_temperature", false);

  } else if (optimal > 0.7) {  // Jika suhu sangat optimal
    digitalWrite(RELAY_TEMP, HIGH);  // Kipas OFF
    // Log status ke Firebase
    Firebase.setString(firebaseData, "/status/temperature", "Optimal - Kipas OFF");
    Firebase.setBool(firebaseData, "/emergency/low_temperature", false);
    Firebase.setBool(firebaseData, "/emergency/high_temperature", false);

  } else if (tooLow > 0.3) {  // Jika suhu terlalu rendah
    digitalWrite(RELAY_TEMP, HIGH);  // Kipas OFF
    // Log status ke Firebase
    Firebase.setString(firebaseData, "/status/temperature", "Rendah - Kipas OFF");
    Firebase.setBool(firebaseData, "/emergency/low_temperature", true);
    Firebase.setBool(firebaseData, "/emergency/high_temperature", false);

  } else {
    // Kasus lain, gunakan pendekatan proporsional
    // Jika suhu mendekati batas atas rentang, nyalakan kipas
    float distanceToMax = maxTemp - temp;
    if (distanceToMax < 1.0) {
      digitalWrite(RELAY_TEMP, LOW);  // Kipas ON
      // Log status ke Firebase
      Firebase.setString(firebaseData, "/status/temperature", "Mendekati Tinggi - Kipas ON");
    } else {
      digitalWrite(RELAY_TEMP, HIGH);  // Kipas OFF
      // Log status ke Firebase
      Firebase.setString(firebaseData, "/status/temperature", "Normal - Kipas OFF");
    }
    Firebase.setBool(firebaseData, "/emergency/low_temperature", false);
    Firebase.setBool(firebaseData, "/emergency/high_temperature", false);
  }
}

// Definisi fungsi fuzzy logic untuk kontrol kelembapan
void controlHumidity(float humidity, float temperature) {
  float minHumidity, maxHumidity, targetHumidity;
  float minTemp, maxTemp;
  
  // Rentang kelembapan ideal berdasarkan umur ayam
  switch (ageInWeeks) {
    case 1: 
      minHumidity = 60; maxHumidity = 70; targetHumidity = 65.0; 
      minTemp = 33; maxTemp = 35;
      break;
    case 2: 
      minHumidity = 60; maxHumidity = 65; targetHumidity = 62.5; 
      minTemp = 30; maxTemp = 33;
      break;
    case 3: 
      minHumidity = 60; maxHumidity = 65; targetHumidity = 62.5; 
      minTemp = 28; maxTemp = 30;
      break;
    case 4: 
      minHumidity = 55; maxHumidity = 60; targetHumidity = 57.5; 
      minTemp = 25; maxTemp = 28;
      break;
    default: 
      minHumidity = 55; maxHumidity = 60; targetHumidity = 57.5;
      minTemp = 25; maxTemp = 28;
  }

  // Periksa apakah suhu terlalu rendah (kondisi darurat)
  bool isTemperatureEmergency = false;
  if (temperature < minTemp - 1.5) {
    isTemperatureEmergency = true;
  }

  // Menghitung derajat keanggotaan untuk berbagai kondisi kelembapan
  float veryLow = 0;     // Kelembapan sangat rendah (kondisi kritis)
  float tooLow = 0;      // Kelembapan terlalu rendah
  float optimal = 0;     // Kelembapan optimal
  float tooHigh = 0;     // Kelembapan terlalu tinggi
  float veryHigh = 0;    // Kelembapan sangat tinggi (kondisi kritis)
  
  // Keanggotaan "sangat rendah" - kondisi kritis
  if (humidity < minHumidity - 5) {
    veryLow = 1.0;  // Sangat rendah, kondisi kritis
  } else if (humidity >= minHumidity - 5 && humidity < minHumidity - 3) {
    veryLow = (minHumidity - 3 - humidity) / 2.0;  // Agak sangat rendah
    veryLow = constrain(veryLow, 0, 1);
  }
  
  // Keanggotaan "terlalu rendah"
  if (humidity >= minHumidity - 3 && humidity < minHumidity) {
    tooLow = (minHumidity - humidity) / 3.0;  // Agak rendah
    tooLow = constrain(tooLow, 0, 1);
  }
  
  // Keanggotaan "optimal"
  if (humidity >= minHumidity && humidity <= maxHumidity) {
    // Semakin dekat ke targetHumidity, semakin optimal
    optimal = 1.0 - abs(humidity - targetHumidity) / ((maxHumidity - minHumidity) / 2.0);
    optimal = constrain(optimal, 0, 1);
  }
  
  // Keanggotaan "terlalu tinggi"
  if (humidity > maxHumidity && humidity <= maxHumidity + 3) {
    tooHigh = (humidity - maxHumidity) / 3.0;  // Agak tinggi
    tooHigh = constrain(tooHigh, 0, 1);
  }
  
  // Keanggotaan "sangat tinggi" - kondisi kritis
  if (humidity > maxHumidity + 5) {
    veryHigh = 1.0;  // Sangat tinggi, kondisi kritis
  } else if (humidity > maxHumidity + 3 && humidity <= maxHumidity + 5) {
    veryHigh = (humidity - (maxHumidity + 3)) / 2.0;  // Agak sangat tinggi
    veryHigh = constrain(veryHigh, 0, 1);
  }
  
  // Kirim nilai fuzzy ke Firebase untuk monitoring
  Firebase.setFloat(firebaseData, "/fuzzy/humidity/veryLow", veryLow);
  Firebase.setFloat(firebaseData, "/fuzzy/humidity/tooLow", tooLow);
  Firebase.setFloat(firebaseData, "/fuzzy/humidity/optimal", optimal);
  Firebase.setFloat(firebaseData, "/fuzzy/humidity/tooHigh", tooHigh);
  Firebase.setFloat(firebaseData, "/fuzzy/humidity/veryHigh", veryHigh);
  
  // Keputusan berdasarkan derajat keanggotaan dan prioritas
  // Jika suhu dalam kondisi darurat, prioritaskan pemanasan
  if (isTemperatureEmergency) {
    digitalWrite(RELAY_HUMIDITY, LOW);  // Lampu ON untuk membantu meningkatkan suhu
    // Log status ke Firebase
    Firebase.setString(firebaseData, "/status/humidity", "Suhu Darurat - Lampu ON untuk Pemanasan");
    Firebase.setBool(firebaseData, "/emergency/low_humidity", false); // Reset emergency flag
    Firebase.setBool(firebaseData, "/emergency/high_humidity", false); // Reset emergency flag
    return; // Keluar dari fungsi, prioritaskan penanganan suhu
  }
  
  // Prioritas: Kelembapan sangat tinggi > Kelembapan sangat rendah > Terlalu tinggi > Optimal > Terlalu rendah
  if (veryHigh > 0.3) {  // Jika kelembapan sangat tinggi (kondisi kritis)
    digitalWrite(RELAY_HUMIDITY, LOW);  // Lampu ON untuk mengurangi kelembapan
    // Log status ke Firebase
    Firebase.setString(firebaseData, "/status/humidity", "Sangat Tinggi - Lampu ON (Kritis)");
    Firebase.setBool(firebaseData, "/emergency/high_humidity", true);
    Firebase.setBool(firebaseData, "/emergency/low_humidity", false);

  } else if (veryLow > 0.3) {  // Jika kelembapan sangat rendah (kondisi kritis)
    digitalWrite(RELAY_HUMIDITY, HIGH);  // Lampu OFF untuk mempertahankan kelembapan
    // Log status ke Firebase
    Firebase.setString(firebaseData, "/status/humidity", "Sangat Rendah - Lampu OFF");
    Firebase.setBool(firebaseData, "/emergency/low_humidity", true);
    Firebase.setBool(firebaseData, "/emergency/high_humidity", false);

  } else if (tooHigh > 0.4) {  // Jika kelembapan terlalu tinggi
    digitalWrite(RELAY_HUMIDITY, LOW);  // Lampu ON untuk mengurangi kelembapan
    // Log status ke Firebase
    Firebase.setString(firebaseData, "/status/humidity", "Tinggi - Lampu ON");
    Firebase.setBool(firebaseData, "/emergency/low_humidity", false);
    Firebase.setBool(firebaseData, "/emergency/high_humidity", false);

  } else if (optimal > 0.6) {  // Jika kelembapan optimal
    // Periksa juga suhu - jika suhu rendah, nyalakan lampu meskipun kelembapan optimal
    if (temperature < minTemp) {
      digitalWrite(RELAY_HUMIDITY, LOW);  // Lampu ON untuk membantu meningkatkan suhu
      // Log status ke Firebase
      Firebase.setString(firebaseData, "/status/humidity", "Optimal, Suhu Rendah - Lampu ON");
    }
    // Jika kelembapan mendekati batas atas rentang optimal, nyalakan lampu
    else if (humidity > targetHumidity + ((maxHumidity - minHumidity) / 4)) {
      digitalWrite(RELAY_HUMIDITY, LOW);  // Lampu ON
      // Log status ke Firebase
      Firebase.setString(firebaseData, "/status/humidity", "Optimal Tinggi - Lampu ON");
    } else {
      digitalWrite(RELAY_HUMIDITY, HIGH);  // Lampu OFF
      // Log status ke Firebase
      Firebase.setString(firebaseData, "/status/humidity", "Optimal - Lampu OFF");
    }
    Firebase.setBool(firebaseData, "/emergency/low_humidity", false);
    Firebase.setBool(firebaseData, "/emergency/high_humidity", false);

  } else if (tooLow > 0.3) {  // Jika kelembapan terlalu rendah
    // Periksa juga suhu - jika suhu sangat rendah, prioritaskan pemanasan
    if (temperature < minTemp - 1) {
      digitalWrite(RELAY_HUMIDITY, LOW);  // Lampu ON untuk membantu meningkatkan suhu
      // Log status ke Firebase
      Firebase.setString(firebaseData, "/status/humidity", "Rendah, Suhu Sangat Rendah - Lampu ON");
    } else {
      digitalWrite(RELAY_HUMIDITY, HIGH);  // Lampu OFF untuk mempertahankan kelembapan
      // Log status ke Firebase
      Firebase.setString(firebaseData, "/status/humidity", "Rendah - Lampu OFF");
    }
    Firebase.setBool(firebaseData, "/emergency/low_humidity", true);
    Firebase.setBool(firebaseData, "/emergency/high_humidity", false);

  } else {
    // Kasus lain, gunakan pendekatan proporsional
    // Periksa juga suhu - jika suhu rendah, nyalakan lampu
    if (temperature < minTemp) {
      digitalWrite(RELAY_HUMIDITY, LOW);  // Lampu ON untuk membantu meningkatkan suhu
      // Log status ke Firebase
      Firebase.setString(firebaseData, "/status/humidity", "Normal, Suhu Rendah - Lampu ON");
    }
    // Jika kelembapan mendekati batas atas, nyalakan lampu
    else if (humidity > maxHumidity - 1.5) {
      digitalWrite(RELAY_HUMIDITY, LOW);  // Lampu ON
      // Log status ke Firebase
      Firebase.setString(firebaseData, "/status/humidity", "Mendekati Tinggi - Lampu ON");
    } else {
      digitalWrite(RELAY_HUMIDITY, HIGH);  // Lampu OFF
      // Log status ke Firebase
      Firebase.setString(firebaseData, "/status/humidity", "Normal - Lampu OFF");
    }
    Firebase.setBool(firebaseData, "/emergency/low_humidity", false);
    Firebase.setBool(firebaseData, "/emergency/high_humidity", false);
  }
}

// Fungsi untuk memeriksa mode kontrol dari Firebase
void checkControlMode() {
  // Periksa mode kipas (otomatis/manual)
  if (Firebase.getBool(firebaseData, "/control/fan/auto")) {
    bool newAutoModeFan = firebaseData.boolData();
    if (newAutoModeFan != autoModeFan) {
      autoModeFan = newAutoModeFan;
    }
  }
  
  // Periksa mode lampu (otomatis/manual)
  if (Firebase.getBool(firebaseData, "/control/light/auto")) {
    bool newAutoModeLight = firebaseData.boolData();
    if (newAutoModeLight != autoModeLight) {
      autoModeLight = newAutoModeLight;
    }
  }
  
  // Jika dalam mode manual, ambil status dari Firebase
  if (!autoModeFan) {
    if (Firebase.getBool(firebaseData, "/control/fan/status")) {
      bool newFanStatus = firebaseData.boolData();
      if (newFanStatus != fanStatus) {
        fanStatus = newFanStatus;
      }
    }
  }
  
  if (!autoModeLight) {
    if (Firebase.getBool(firebaseData, "/control/light/status")) {
      bool newLightStatus = firebaseData.boolData();
      if (newLightStatus != lightStatus) {
        lightStatus = newLightStatus;
      }
    }
  }
}

// Tambahkan fungsi untuk memeriksa LCD secara berkala
void checkLCDConnection() {
  static unsigned long lastLCDCheck = 0;
  static bool lastLCDStatus = true;
  
  // Periksa LCD setiap 30 detik
  if (millis() - lastLCDCheck > 30000) {
    Wire.beginTransmission(0x27); // Alamat I2C LCD
    byte error = Wire.endTransmission();
    
    bool currentLCDStatus = (error == 0);
    
    // Jika status berubah, kirim log
    if (currentLCDStatus != lastLCDStatus) {
      if (currentLCDStatus) {
        // LCD terdeteksi kembali, jalankan proses inisialisasi lengkap
        logToFirebase("/logs/lcd", "LCD Connection Restored");
        logToFirebase("/logs/lcd", "LCD Initialization Started");
        
        // Coba inisialisasi LCD
        lcd.init(); // Panggil init() tanpa memeriksa nilai kembali
        lcd.backlight();
        lcd.clear();
        lcd.begin(16,2);
        lcd.print("Reconnected...");
        
        // Anggap inisialisasi berhasil jika kita sampai di sini
        logToFirebase("/logs/lcd", "LCD Ready and Initialized");
        Serial.println("LCD reinitialized successfully");
      } else {
        logToFirebase("/logs/lcd", "LCD Connection Lost - Check Wiring");
      }
      lastLCDStatus = currentLCDStatus;
    }
    
    lastLCDCheck = millis();
  }
}