#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>

// MQTT settings
const char* mqtt_server = "test.mosquitto.org";
const int mqtt_port = 1883;
const char* mqtt_topic = "tempdata";

// Add your WiFi credentials
const char* ssid = "Wokwi-GUEST";
const char* pass = "";

const char* mqtt_client_id = "airquality";

WiFiClient espClient; // Use WiFiClient for an unsecured connection
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];

// DHT sensor
#define DHTPIN 2
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

// LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Potentiometer pin
const int potPin = 34;

// LED pin
const int ledPin = 4;

float lastTemperature = 0.0;
float lastHumidity = 0.0;
int lastGasValue = 0;

void sendData() {
  // Read temperature and humidity from the DHT22 sensor
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();
  int gasValue = analogRead(potPin);

  // Log changes in temperature
  if (temperature != lastTemperature) {
    Serial.print("Temperature changed: ");
    Serial.println(temperature);
    lastTemperature = temperature;
    publishToMQTT("temperature", String(temperature));
  }

  // Log changes in humidity
  if (humidity != lastHumidity) {
    Serial.print("Humidity changed: ");
    Serial.println(humidity);
    lastHumidity = humidity;
    publishToMQTT("humidity", String(humidity));
  }

  // Log changes in gas value
  if (gasValue != lastGasValue) {
    Serial.print("Gas Value changed: ");
    Serial.println(gasValue);
    lastGasValue = gasValue;
    publishToMQTT("gasValue", String(gasValue));
  }

  // Create a JSON document
  const size_t capacity = JSON_OBJECT_SIZE(3);
  DynamicJsonDocument doc(capacity);
  doc["temperature"] = temperature;
  doc["humidity"] = humidity;
  doc["gasValue"] = gasValue;

  // Serialize JSON to a string
  String jsonString;
  serializeJson(doc, jsonString);

  // Publish JSON payload to MQTT
  client.publish(mqtt_topic, jsonString.c_str());
}

void publishToMQTT(const char* parameter, const String& value) {
  String topic = String(mqtt_topic) + "/" + parameter;
  String mqttMessage = String("{\"" + String(parameter) + "\": " + value + "}");
  client.publish(topic.c_str(), mqttMessage.c_str());
}

void displayMessage(String line1, String line2, int delayTime = 2000) {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(line1);
  lcd.setCursor(0, 1);
  lcd.print(line2);
  delay(delayTime);
}

void connectWiFiAndMQTT() {
  // Connect to Wi-Fi
  Serial.println("Connecting to Wi-Fi");
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED) {
    delay(250);
    Serial.print(".");
  }
  Serial.println("\nConnected to Wi-Fi");

  // Connect to MQTT
  client.setServer(mqtt_server, mqtt_port);
  Serial.println("Connecting to MQTT");
  int attempts = 0;
  while (!client.connected()) {
    Serial.print(".");
    if (client.connect(mqtt_client_id)) {
      Serial.println("\nConnected to MQTT");
      client.subscribe(mqtt_topic);
    } else {
      int rc = client.state();
      Serial.print("Failed, rc=");
      Serial.print(rc);
      Serial.println(" Trying again in 1 second");
      delay(1000);  // Reduce delay between connection attempts
      attempts++;
      if (attempts > 5) {
        Serial.println("Failed to connect to MQTT. Exiting.");
        break;
      }
    }
  }
}

void setup() {
  Serial.begin(115200);
  lcd.init();
  lcd.backlight();
  dht.begin();
  pinMode(ledPin, OUTPUT);
  connectWiFiAndMQTT();
  sendData();
}

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

  client.loop();

  long now = millis();
  if (now - lastMsg > 5000) {
    lastMsg = now;
    sendData();
  }

  // Read temperature and humidity from the DHT22 sensor
  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  // Read gas value from the potentiometer
  int gasValue = analogRead(potPin);

  // Determine air level based on the specified conditions
  String airLevel;

  // Check temperature and humidity conditions = airLevel 
  if ((temperature >= 22 && temperature <= 30) && (humidity > 30 && humidity < 60)) {
    airLevel = "Good";
  } else if ((temperature >= 30 && temperature <= 40) && (humidity >= 60 && humidity <= 70)) {
    airLevel = "Normal";
  } else {
    airLevel = "Bad";
  }

  // Determine gas level based on the criteria
  String gasLevel;

  if (gasValue >= 0 && gasValue <= 1364) {
    gasLevel = "Good";
  } else if (gasValue >= 1365 && gasValue <= 2730) {
    gasLevel = "Normal";
  } else {
    gasLevel = "Bad"; 
  }

  // Determine air quality based on the criteria
  String airQuality;

  if ((airLevel == "Good" || airLevel == "Normal") && (gasLevel == "Good" || gasLevel == "Normal")) {
    airQuality = "Good Air Quality";
  } else {
    airQuality = "Bad Air Quality";
  }

  // DISPLAY AREA TO SCREEN

  // Display temperature and humidity on the LCD
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Temp: " + String(temperature) + " C");
  lcd.setCursor(0, 1);
  lcd.print("Humidity: " + String(humidity) + " %");
  delay(2000); // Display temperature and humidity for 2 seconds

  // Display air level on the LCD
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Air Level: " + airLevel);
  delay(2000); // Display air level for 2 seconds

  // Display gas level and gas value on the LCD
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Gas Level: " + gasLevel);
  lcd.setCursor(0, 1);
  lcd.print("Gas Value: " + String(gasValue));
  delay(2000); // Display gas level and value for 2 seconds

  // Display air quality on the LCD
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Air Quality: ");
  lcd.setCursor(0, 1);
  lcd.print(airQuality);
  delay(2000); // Display air quality for 2 seconds   

  // Control the LED based on air quality
  if (airQuality == "Bad Air Quality") {
    digitalWrite(ledPin, HIGH); // Turn on the LED
    Serial.println("LED ON");  // Print LED state to Serial console
    Serial.println();
  } else {
    digitalWrite(ledPin, LOW); // Turn off the LED
    Serial.println("LED OFF"); // Print LED state to Serial console
    Serial.println();
  }
}
$abcdeabcde151015202530fghijfghij