#define BLYNK_TEMPLATE_ID "TMPL5LLhQ1jB8"
#define BLYNK_TEMPLATE_NAME "Smart Environmental Monitoring System"

#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <BlynkSimpleEsp32.h> 

#define DHTPIN 23            // Pin where the DHT22 is connected
#define DHTTYPE DHT22        // DHT 22 (AM2302)
#define OLED_RESET -1        // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_WIDTH 128     // OLED display width, in pixels
#define SCREEN_HEIGHT 64     // OLED display height, in pixels
#define OLED_ADDR   0x3C     // OLED display I2C address (usually 0x3C or 0x3D)
#define LED_PIN 25           // LED connected to GPIO25
#define BUZZER_PIN 26        // Buzzer connected to GPIO26
#define BUZZER_CHANNEL 0     // PWM channel for the buzzer


DHT dht(DHTPIN, DHTTYPE);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, 
OLED_RESET, OLED_ADDR);

const char* ssid = "Wokwi-GUEST"; // WiFi SSID
const char* password = ""; // WiFi Password
const char* auth = "yXjELfg_12kq3truPRZltDf8Hbw5vFCA";
const char* mqtt_server = "broker.hivemq.com";     // MQTT Broker address
const int mqtt_port = 1883;                        // MQTT Port
WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() {
  Serial.println("Connecting to WiFi..");
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("\nWiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP32Client")) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  dht.begin();

  pinMode(LED_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);

  ledcSetup(BUZZER_CHANNEL, 2000, 8);  // Setup PWM for the buzzer
  ledcAttachPin(BUZZER_PIN, BUZZER_CHANNEL);  // Attach the buzzer pin to the PWM channel

  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    Serial.println("SSD1306 allocation failed");
    for(;;); // Don't proceed, loop forever
  }
  display.clearDisplay();
  display.display();

  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);

  Blynk.begin(auth, ssid, password);  // Initialize Blynk with authentication token
}

void loop() {
  Blynk.run();  // Run Blynk to handle communication
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  String Status ="Normal Condition";

  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
    display.clearDisplay();
    display.setCursor(0,0);
    display.println("Sensor read error!");
    display.display();
    return;
  }
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.print(" °C, Humidity: ");
  Serial.print(h);
  Serial.println(" %");
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("Temp: " + String(t) + " C");
  display.println("Hum: " + String(h) + " %");
  display.display();
  // Send temperature and humidity values to Blynk
  Blynk.virtualWrite(V1, t); // Send temperature value to virtual pin V1
  Blynk.virtualWrite(V2, h); // Send humidity value to virtual pin V2

  String temperature = "temperature " + String(t);
  String humidity = "humidity " + String(h);
  client.publish("outTopic/temp", temperature.c_str());
  client.publish("outTopic/hum", humidity.c_str());

  if (t >25 || h > 40) { // Threshold temperature or humidity to trigger the warning
    digitalWrite(LED_PIN, HIGH); // Turn on the LED
    ledcWrite(BUZZER_CHANNEL, 125); // Activate the buzzer
    delay(500); // Buzzer on for 500 milliseconds
    ledcWrite(BUZZER_CHANNEL, 0); // Turn off the buzzer
    Status ="Danger Condition";
    
    delay(500); // Buzzer off for 500 milliseconds
  } else {
    digitalWrite(LED_PIN, LOW); // Turn off the LED
    ledcWrite(BUZZER_CHANNEL, 0); // Ensure buzzer is off
    Status ="Normal Condition";
  }
  Blynk.virtualWrite(V3, Status); // Send status value to virtual pin V3
  delay(2000); // Delay for 2 seconds before next reading
}
$abcdeabcde151015202530354045505560fghijfghij