#include <DHTesp.h>
#include <LiquidCrystal_I2C.h>
#include <ESP32Servo.h>

// khai báo chân kết nối
#define DHT_PIN  27  
#define LED_1 17    
#define LED_2 18
#define LED_3 4
#define button 14
#define RELAY_1 16
#define RELAY_2 19  
#define trigPin 25
#define echoPin 26   
#define servoPin 13

float prevTemperature = -100;  
int prevHumidity = -1;         
int prevServoAngle = -1;
bool prevButtonState = LOW;

int buttonStase;
DHTesp dht;
Servo myServo;

// Thời gian và khoảng cách đo được
long duration;
int distance;

// khai báo LCD
LiquidCrystal_I2C lcd(0x27, 20, 4);

void setup() 
{
 
 // tốc độ truyền terminal 
  Serial.begin(115200);
  
  // Cấu hình chân xuất cho LED
  pinMode(LED_1, OUTPUT);
  pinMode(LED_2, OUTPUT);
  pinMode(LED_3, OUTPUT);

  pinMode(button, INPUT);

  // Cau hinh relay 
  pinMode(RELAY_1, OUTPUT);
  digitalWrite(RELAY_1, LOW); // MUC CAO RLAY KHONG HOAT DONG
  pinMode(RELAY_2, OUTPUT);
  digitalWrite(RELAY_2, LOW);

  // Bật LED ban đầu ở trạng thái tắt
  digitalWrite(LED_1, LOW);
  digitalWrite(LED_2, LOW);
  digitalWrite(LED_3, LOW);

  // Khởi tạo cảm biến DHT22
  dht.setup(DHT_PIN, DHTesp::DHT22);

  // Khởi tạo màn hình LCD
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Starting...");

 // Thiết lập chân vào và ra cho cảm biến siêu âm
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);


  // Thiết lập servo
  myServo.attach(servoPin);

  //Serial.println("System Initialized");
}

void ReadingDHT22() 
{
  int h = dht.getHumidity();
  float t = dht.getTemperature();

  if (isnan(h) || isnan(t)) {
    lcd.setCursor(0, 0); 
    lcd.print("Error DHT22       ");  // In kèm khoảng trắng để xóa phần còn dư
    return;
  }

  // Chỉ cập nhật nhiệt độ nếu có thay đổi
  if (t != prevTemperature) {
    prevTemperature = t;
    lcd.setCursor(0, 0);
    lcd.print("T:");
    lcd.print(t);
    lcd.print("C   ");  // Thêm khoảng trắng để xóa ký tự cũ nếu giá trị nhỏ hơn
  }

  // Chỉ cập nhật độ ẩm nếu có thay đổi
  if (h != prevHumidity) {
    prevHumidity = h;
    lcd.setCursor(11, 0);
    lcd.print("H:");
    lcd.print(h);
    lcd.print("%   ");
  }

    // Điều khiển đèn LED dựa vào nhiệt độ và độ ẩm
  if (t > 30) 
  {
    digitalWrite(LED_1, HIGH); 
    delay(100);
    digitalWrite(LED_1, LOW);
    digitalWrite(RELAY_1, HIGH);
    //Serial.print("Turn on coldding.. ");
    // lcd.setCursor(0, 1);
    // lcd.print("ON cold");
  } 
  else 
  {
    digitalWrite(LED_1, LOW);
    digitalWrite(RELAY_1, LOW); 
    //Serial.print("Turn off coldding.. "); 
    // lcd.setCursor(0, 1);
    // lcd.print("OFF cold"); 
  }

  if ( h > 75) 
  {
    digitalWrite(LED_2, HIGH);
    delay(100);
    digitalWrite(LED_2, LOW);
    digitalWrite(RELAY_2, HIGH);
    //Serial.print("Turn on Humming.. ");
    // lcd.setCursor(9, 1);
    // lcd.print("ON Hum");   
  } 
  else 
  {
    digitalWrite(LED_2, LOW);
    digitalWrite(RELAY_2, LOW); 
    //Serial.print("Turn off Humming.. ");
    // lcd.setCursor(9, 1);
    // lcd.print("OFF Hum");     
  }
}



void loop() 
{
  
  ReadingDHT22();
  delay(1000);

   // Phát xung cho chân Triger
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  // Đo thời gian xung Echo
  duration = pulseIn(echoPin, HIGH);

  // Tính khoảng cách
  distance = duration * 0.034 / 2;

  // // In khoảng cách lên serial monitor
  // Serial.print("Khoang cach: ");
  // Serial.print(distance);
  // Serial.println(" cm");

  // Chuyển đổi khoảng cách thành góc servo (0-180 độ)
  int servoAngle = map(distance, 0, 200, 0, 180);

// Đảm bảo giá trị nằm trong khoảng 0-180
  servoAngle = constrain(servoAngle, 0, 180);  

  
  // Điều khiển servo và hiển thị trạng thái cửa
if (servoAngle != prevServoAngle) 
{
  prevServoAngle = servoAngle;
  myServo.write(servoAngle);

  lcd.setCursor(3, 1);
  if (servoAngle > 90) 
  {
    lcd.print("OPEN THE DOOR   ");
  } 
  else 
  {
    lcd.print("CLOSE THE DOOR  ");
  }
}

  //delay(10);

   buttonStase = digitalRead(button); 
if(buttonStase != prevButtonState) 
{
  prevButtonState = buttonStase;
  if(buttonStase == HIGH) 
  {
    digitalWrite(LED_3, HIGH);
    lcd.setCursor(5, 2);
    lcd.print("ON CLAIM  ");
  } 
  else 
  {
    digitalWrite(LED_3, LOW);
    lcd.setCursor(5, 2);
    lcd.print("OFF CLAIM ");
  }
}
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module