#include <LiquidCrystal.h>
#include <DHT.h>

// Define the pins to be used
#define GREEN_LED 4
#define YELLOW_LED 3
#define RED_LED 2
#define PIEZZO 1
#define DHTPIN 13  
#define DHTTYPE DHT22 // Defines the type of DHT sensor as DHT22
DHT dht(DHTPIN, DHTTYPE); // Creates an instance of the DHT sensor
#define RS 7
#define E 6
#define D4 12
#define D5 10
#define D6 9
#define D7 8
#define LDR A0
LiquidCrystal lcd(RS, E, D4, D5, D6, D7); // Creates an instance of the LCD

// Define the variables
unsigned long lastUpdateTime = 0;
const int MIN_BRIGHTNESS = 33;
const int MAX_BRIGHTNESS = 50;
const int MIN_TEMPERATURE = 10;
const int MAX_TEMPERATURE = 15;
const int MIN_HUMIDITY = 50;
const int MAX_HUMIDITY = 70;

// Defines the icons to be displayed on the LCD
byte humidityIcon[8] = {B00100, B00100, B01010, B01010, B10001, B10001, B10001, B01110,};
byte temperatureIcon[8] = {B00100, B01010, B01010, B01110, B01110, B11111, B11111, B01110,};
byte lightIcon[8] = {B10001, B01110, B11111, B01110, B10001, B00000, B00000, B00000,};
byte airplaneIcon1[8] = {B00000, B00000, B00001, B00011, B11111, B00011, B00001, B00000,};
byte airplaneIcon2[8] = {B00000, B00000, B10000, B11000, B11111, B11000, B10000, B00000,};

void setup() {
  // Configures the pins as output or input
  pinMode(GREEN_LED, OUTPUT);
  pinMode(YELLOW_LED, OUTPUT);
  pinMode(RED_LED, OUTPUT);
  pinMode(LDR, INPUT);
  // Starts the serial communication
  Serial.begin(115200);
  Serial.println(F("Printing values!"));
  // Starts the DHT22 sensor
  dht.begin();
  // Starts the LCD with 16 columns and 2 lines
  lcd.begin(16, 2);
  // Creates custom characters for the LCD
  lcd.createChar(0, humidityIcon); 
  lcd.createChar(1, temperatureIcon); 
  lcd.createChar(2, lightIcon); 
  lcd.createChar(3, airplaneIcon1); 
  lcd.createChar(4, airplaneIcon2); 
  // Displays an initial animation on the LCD
  for (int positionCounter = 0; positionCounter < 13; positionCounter++) {
    lcd.clear();
    lcd.setCursor(positionCounter, 0);
    lcd.write(byte(3)); 
    lcd.setCursor(positionCounter + 1, 0);
    lcd.write(byte(4)); 
    lcd.setCursor(positionCounter, 1);
    lcd.print("PCD's CodeX");
    delay(500); 
  }
  lcd.clear();
}

void loop() {
  // Checks if 5 seconds have passed since the last update
  if (millis() - lastUpdateTime >= 5000) {
    lastUpdateTime = millis();
    // Reads the brightness, temperature, and humidity
    int brightness = analogRead(LDR);
    int temperature = dht.readTemperature();
    int humidity = dht.readHumidity();
    // Maps these values to a scale of 0 to 100
    int brightnessPercentage = map(brightness, 0, 1023, 0, 100);
    int mappedTemperature = map(temperature, 0, 100, 0, 100);
    int mappedHumidity = map(humidity, 0, 100, 0, 100);
    // Checks if the DHT22 sensor reading was successful
    if (isnan(temperature) || isnan(humidity)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }
    // Prints the brightness, humidity, and temperature information on the serial monitor
    Serial.print(F("Brightness: "));
    Serial.print(brightnessPercentage);
    Serial.print(F(", Humidity: "));
    Serial.print(mappedHumidity);
    Serial.print(F("%,  Temperature: "));
    Serial.print(mappedTemperature);
    Serial.println(F("°C "));
    // Calls the function to turn off all LEDs
    turnOffLEDs();
    // Calls the function to update the system status based on the read values
    updateStatus(brightnessPercentage, mappedTemperature, mappedHumidity);
  }
}
// Function to turn off all LEDs
void turnOffLEDs() {
  digitalWrite(GREEN_LED, LOW);
  digitalWrite(YELLOW_LED, LOW);
  digitalWrite(RED_LED, LOW);
}
// Function to update the system status based on the read values
void updateStatus(int brightness, int temperature, int humidity) {
  if (brightness <= MIN_BRIGHTNESS && temperature >= MIN_TEMPERATURE && temperature <= MAX_TEMPERATURE && humidity >= MIN_HUMIDITY && humidity <= MAX_HUMIDITY) {
    Serial.println("Conditions for green LED active"); 
    digitalWrite(GREEN_LED, HIGH);
    updateLCD(temperature, humidity, brightness);
  } 
  else if (temperature >= 1 && temperature < 9 || temperature >= 16 && temperature < 30 || brightness >= 34 && brightness < 50 || humidity >= 40 && humidity < 49 || humidity >= 71 && humidity < 80) {
    Serial.println("Conditions for yellow LED active"); 
    digitalWrite(YELLOW_LED, HIGH);
    updateLCD(temperature, humidity, brightness);
    tone(PIEZZO, 1000);
    delay(1000);
  }   
  else {
    Serial.println("Conditions for red LED active"); 
    digitalWrite(RED_LED, HIGH);
    updateLCD(temperature, humidity, brightness);
    tone(PIEZZO, 1000);
    delay(1000);
  }
}
// Function to update the LCD display
void updateLCD(int temperature, int humidity, int brightness) {
  lcd.clear();
  
  // Sets the position of the icons on the second line of the LCD
  lcd.setCursor(0, 1);
  lcd.write(byte(1)); // Temperature icon
  lcd.print(":");
  lcd.setCursor(2, 1);
  lcd.print(int(temperature)); // Temperature value

  lcd.setCursor(6, 1);
  lcd.write(byte(0)); // Humidity icon
  lcd.print(":");
  lcd.setCursor(8, 1);
  lcd.print(int(humidity)); // Humidity value

  lcd.setCursor(12, 1);
  lcd.write(byte(2)); // Light icon
  lcd.print(":");
  lcd.setCursor(14, 1);
  lcd.print(int(brightness)); // Brightness value

 // Checks the temperature and displays the corresponding message
lcd.setCursor(0, 0);
lcd.print("                "); // Clears the line
lcd.setCursor(0, 0);
if (temperature < MIN_TEMPERATURE) {
  lcd.print("Low Temp:");
  lcd.print(int(temperature));
  tone(PIEZZO, 1000, 2000); // Adds buzzer sound
  delay(2000);
} else if (temperature > MAX_TEMPERATURE) {
  lcd.print("High Temp:");
  lcd.print(int(temperature));
  tone(PIEZZO, 1000, 2000); // Adds buzzer sound
  delay(2000);
} else {
  lcd.print("Temp ok:");
  lcd.print(int(temperature));
  delay(2000);
}

// Checks the humidity and displays the corresponding message
lcd.setCursor(0, 0);
lcd.print("                "); // Clears the line
lcd.setCursor(0, 0);
if (humidity < MIN_HUMIDITY) {
  lcd.print("Low Humidity:");
  lcd.print(int(humidity));
  tone(PIEZZO, 1000, 2000); // Adds buzzer sound
  delay(2000);
} else if (humidity > MAX_HUMIDITY) {
  lcd.print("High Humidity:");
  lcd.print(int(humidity));
  tone(PIEZZO, 1000, 2000); // Adds buzzer sound
  delay(2000);
} else {
  lcd.print("Humidity ok:");
  lcd.print(int(humidity));
  delay(2000);
}

// Checks the brightness and displays the corresponding message
lcd.setCursor(0, 0);
lcd.print("                "); // Clears the line
lcd.setCursor(0, 0);
if (brightness < MIN_BRIGHTNESS) {
  lcd.print("Light ok:");
  lcd.print(int(brightness));
  delay(2000);
} else if (brightness > MIN_BRIGHTNESS && brightness <= MAX_BRIGHTNESS) {
  lcd.print("Medium Light:");
  lcd.print(int(brightness));
  tone(PIEZZO, 1000, 2000); // Adds buzzer sound
  delay(2000);
} else {
  lcd.print("High Light:");
  lcd.print(int(brightness));
  tone(PIEZZO, 1000, 2000); // Adds buzzer sound
  delay(2000);
  }
}
$abcdeabcde151015202530354045505560fghijfghij