#include <WiFi.h>
#include "PubSubClient.h"
#include "DHTesp.h"
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <DHT.h>

// --- Cấu hình ---
#define DHT_PIN 4
#define DHT_TYPE DHT22
#define LCD_SDA 21
#define LCD_SCL 22
#define LDR_PIN 34
#define PIR_PIN 25
#define LED_LOSUOI 26
#define LED_DIEUHOA 27
#define LED_REM 32
#define LED_DEN 33
#define LED_DENNgoai 14
#define LED_CUA 12

// WiFi và MQTT
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;
const char* MQTT_ID = "c5afa5ae-d3a0-48b7-b850-92015a281909";
WiFiClient espClient;
PubSubClient client(espClient);

// Chủ đề MQTT
const char* topicTempHumidity = "Iot/Nhietdoam";
const char* topicLightStatus = "Iot/Rem";
const char* topicMotionStatus = "Iot/Den";
const char* topicOutdoorLight = "Iot/DenNgoai";
const char* topicDoorStatus = "Iot/Cua";
const char* topicControl = "Iot/Control";  // Chủ đề nhận lệnh từ MQTT

// Cảm biến DHT
DHTesp dhtSensor;
DHT dht(DHT_PIN, DHT_TYPE);

// LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Biến ngưỡng và trạng thái
float tempThresholdLow = 18.0;
float tempThresholdHigh = 30.0;
int lightThreshold = 800;
int timeoutLight = 10000; // Thời gian chờ cho đèn
unsigned long lastMotionTime = 0;
unsigned long tempLowStartTime = 0;
unsigned long tempHighStartTime = 0;
unsigned long tempWaitTime = 5000; // Thời gian chờ mặc định (5 giây)

// Kết nối WiFi
void WIFIConnect() {
  Serial.println("Đang kết nối tới WiFi: Wokwi-GUEST");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("WiFi đã kết nối, IP: ");
  Serial.println(WiFi.localIP());
}

// Kết nối MQTT
void MQTT_Reconnect() {
  while (!client.connected()) {
    Serial.println("Đang kết nối lại MQTT...");
    if (client.connect(MQTT_ID)) {
      Serial.println("Đã kết nối MQTT thành công");
      client.subscribe(topicControl);  // Đăng ký nhận lệnh từ MQTT
    } else {
      Serial.print("Kết nối MQTT thất bại, lỗi: ");
      Serial.println(client.state());
      delay(5000);
    }
  }
}


// Gửi thông báo qua MQTT
void sendMQTT(const char* topic, String payload) {
  if (!client.connected()) {
    Serial.println("MQTT không kết nối, đang thử lại...");
    MQTT_Reconnect();
  }
  if (client.publish(topic, payload.c_str())) {
    Serial.print("Gửi thành công: ");
    Serial.println(payload);
  } else {
    Serial.println("Gửi thất bại!");
  }
}


// Xử lý dữ liệu từ MQTT
void handleControl(char* topic, byte* payload, unsigned int length) {
  String message = "";
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
  }
  Serial.print("Lệnh nhận được từ MQTT: ");
  Serial.println(message);

  // Xử lý lệnh bật/tắt thiết bị
  if (message.startsWith("set_wait_time:")) {
    String waitTimeStr = message.substring(14);
    tempWaitTime = waitTimeStr.toInt() * 1000;
    sendMQTT("Iot/Response", "Thời gian chờ đã cập nhật");
  } else if (message == "bat_lo_suoi") {
    digitalWrite(LED_LOSUOI, HIGH);
    sendMQTT("Iot/Response", "Lò sưởi đã bật");
  } else if (message == "tat_lo_suoi") {
    digitalWrite(LED_LOSUOI, LOW);
    sendMQTT("Iot/Response", "Lò sưởi đã tắt");
  } else if (message == "bat_dieu_hoa") {
    digitalWrite(LED_DIEUHOA, HIGH);
    sendMQTT("Iot/Response", "Điều hòa đã bật");
  } else if (message == "tat_dieu_hoa") {
    digitalWrite(LED_DIEUHOA, LOW);
    sendMQTT("Iot/Response", "Điều hòa đã tắt");
  } else if (message == "mo_cua") {
    digitalWrite(LED_CUA, HIGH);
    sendMQTT("Iot/Response", "Cửa đã mở");
  } else if (message == "dong_cua") {
    digitalWrite(LED_CUA, LOW);
    sendMQTT("Iot/Response", "Cửa đã đóng");
  } else if (message == "bat_den") {
    digitalWrite(LED_DENNgoai, HIGH);
    sendMQTT("Iot/Response", "Cửa đã mở");
  } else if (message == "tat_den") {
    digitalWrite(LED_DENNgoai, LOW);
    sendMQTT("Iot/Response", "Cửa đã đóng");
  }
}

// Xử lý nhiệt độ và độ ẩm
void handleTemperatureHumidity() {
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  if (isnan(temperature) || isnan(humidity)) {
    Serial.println("Lỗi đọc cảm biến DHT!");
    return;
  }

  // Hiển thị lên LCD
  lcd.setCursor(0, 0);
  lcd.printf("Nhiet do: %.1f C", temperature);
  lcd.setCursor(0, 1);
  lcd.printf("Do am: %.1f %%", humidity);

  // Kiểm tra nhiệt độ thấp
  if (temperature < tempThresholdLow) {
    if (tempLowStartTime == 0) {
      tempLowStartTime = millis();
    }
    if (millis() - tempLowStartTime > tempWaitTime) {
      digitalWrite(LED_LOSUOI, HIGH);
      lcd.setCursor(0, 2);
      lcd.print("Nhiet do Thap");
      lcd.setCursor(0, 3);
      lcd.print("Bat lo suoi...");
      delay(3000);
      digitalWrite(LED_LOSUOI, LOW);
      tempLowStartTime = 0;
    }
  } else if (temperature > tempThresholdHigh) {
    if (tempHighStartTime == 0) {
      tempHighStartTime = millis();
    }
    if (millis() - tempHighStartTime > tempWaitTime) {
      digitalWrite(LED_DIEUHOA, HIGH);
      lcd.setCursor(0, 2);
      lcd.print("Nhiet do Cao");
      lcd.setCursor(0, 3);
      lcd.print("Bat dieu hoa...");
      delay(3000);
      digitalWrite(LED_DIEUHOA, LOW);
      tempHighStartTime = 0;
    }
  } else {
    lcd.setCursor(0, 2);
    lcd.print("Nhiet do Binh");
    lcd.setCursor(0, 3);
    lcd.print("Thuong...");
  }

  // Gửi qua MQTT
  String tempHumPayload = String("{\"temperature\":") + temperature + ", \"humidity\":" + humidity + "}";
  sendMQTT(topicTempHumidity, tempHumPayload);
}

// Xử lý ánh sáng và rèm
void handleLight() {
  int lightValue = analogRead(LDR_PIN);
  if (lightValue > lightThreshold) {
    digitalWrite(LED_REM, HIGH);
    digitalWrite(LED_DENNgoai, LOW);
    sendMQTT(topicLightStatus, "Ánh sáng cao, rèm đã đóng");
    sendMQTT(topicOutdoorLight, "Đèn ngoài đã tắt");
  } else {
    digitalWrite(LED_REM, LOW);
    digitalWrite(LED_DENNgoai, HIGH);
    sendMQTT(topicLightStatus, "Ánh sáng thấp, rèm đã mở");
    sendMQTT(topicOutdoorLight, "Đèn ngoài đã bật");
  }
}

// Xử lý chuyển động
void handleMotion() {
  bool motionDetected = digitalRead(PIR_PIN);
  if (motionDetected) {
    digitalWrite(LED_DEN, HIGH);
    lastMotionTime = millis();
    sendMQTT(topicMotionStatus, "Phát hiện chuyển động, bật đèn");
  }

  if (millis() - lastMotionTime > timeoutLight) {
    digitalWrite(LED_DEN, LOW);
    sendMQTT(topicMotionStatus, "Không có chuyển động, tắt đèn");
  }
}

void setup() {
  Serial.begin(115200);
  WIFIConnect();
  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(handleControl);  // Đặt hàm callback cho MQTT

  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
  dht.begin();
  lcd.init();
  lcd.backlight();

  pinMode(LDR_PIN, INPUT);
  pinMode(PIR_PIN, INPUT);
  pinMode(LED_LOSUOI, OUTPUT);
  pinMode(LED_DIEUHOA, OUTPUT);
  pinMode(LED_REM, OUTPUT);
  pinMode(LED_DEN, OUTPUT);
  pinMode(LED_DENNgoai, OUTPUT);
  pinMode(LED_CUA, OUTPUT);

  digitalWrite(LED_LOSUOI, LOW);
  digitalWrite(LED_DIEUHOA, LOW);
  digitalWrite(LED_REM, LOW);
  digitalWrite(LED_DEN, LOW);
  digitalWrite(LED_DENNgoai, LOW);
  digitalWrite(LED_CUA, LOW);
}

void loop() {
  if (!client.connected()) {
    MQTT_Reconnect();
  }
  client.loop();

  Serial.println("Xử lý nhiệt độ và độ ẩm...");
  handleTemperatureHumidity();
  Serial.println("Xử lý ánh sáng...");
  handleLight();
  Serial.println("Xử lý chuyển động...");
  handleMotion();

  delay(1000);
}