#include <WiFi.h>
#include "PubSubClient.h"
#include <DallasTemperature.h>
#include <OneWire.h>
#include "DHTesp.h"

const int DHT_PIN = 15;

DHTesp dhtSensor;


int sensorPin = 4; //temperature
OneWire oneWire (sensorPin);  // creates the OneWire object using a specific pin
DallasTemperature sensor (&oneWire);

const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqttServer = "broker.hivemq.com";
int port = 1883;

const int relayPin = 18; // Define the pin for the relay

WiFiClient espClient;
PubSubClient client(espClient);

int pirState = LOW;
int lastPirState = LOW;
const int pirPin = 5;
const int ldrPin = 34;
const int ledPin = 2;

void setup() {
  Serial.begin(115200);
  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
  pinMode(ledPin, OUTPUT);
  pinMode(relayPin, OUTPUT);
  pinMode(ldrPin, INPUT);       // Set relay pin as output

  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  client.setServer(mqttServer, port);
  client.setCallback(callback);
}

void loop() {
  client.loop();
  check_motion_and_light();
  sensor.requestTemperatures();
  float temp = sensor.getTempCByIndex(0);
  Serial.print("Temperature: ");
  Serial.print(temp);
  Serial.println("ºC");

  TempAndHumidity  data = dhtSensor.getTempAndHumidity();
  Serial.println("Temp: " + String(data.temperature, 2) + "°C");
  Serial.println("Humidity: " + String(data.humidity, 1) + "%");
  Serial.println("---");
  delay(2000);

/*
  if (client.connected()) {
    client.publish("temp", String(data.temperature).c_str());
    delay(2000);
    //client.publish("humidity", String(data.humidity).c_str());  // Publish the temperature
  } else {
    Serial.println("MQTT not connected. Cannot send temperature.");
  }

  if (client.connected()) {
    
    client.publish("humidity", String(data.humidity).c_str());  // Publish the temperature
    delay(2000);
  } else {
    Serial.println("MQTT not connected. Cannot send humidity.");
  }
*/
  if (client.connected()) {
    String tempValue = String(data.temperature) + "°C";
    client.publish("temp", tempValue.c_str());
    delay(2000);
  } else {
    Serial.println("MQTT not connected. Cannot send temperature.");
  }

  if (client.connected()) {
      String humidityValue = String(data.humidity)+"%";
      client.publish("humidity", humidityValue.c_str());
      delay(2000);
    } else {
      Serial.println("MQTT not connected. Cannot send humidity.");
  }



}

void check_motion_and_light() {
  pirState = digitalRead(pirPin);
  if (pirState != lastPirState) {
    if (pirState == HIGH) {
      Serial.println("Motion detected!");
      if (client.connected()) {
        client.publish("motion", "Motion detected!");  
      } else {
        Serial.println("MQTT not connected. Cannot send motion detection message.");
      }
      // Turn on the relay when motion is detected
      digitalWrite(relayPin, HIGH);
    } else {
      // Turn off the relay when no motion is detected
      digitalWrite(relayPin, LOW);
    }
    lastPirState = pirState;
  }

  int ldrValue = analogRead(ldrPin);
  Serial.print("LDR Sensor Value: ");
  Serial.println(ldrValue);

  // Publish LDR sensor value to MQTT
  if (client.connected()) {
    client.publish("LDR", String(ldrValue).c_str());
  } else {
    Serial.println("MQTT not connected. Cannot send LDR sensor value.");
  }

  delay(500);

  if (!client.connected()) {
    mqttReconnect();
  }
}

void mqttReconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    long r = random(1000);
    char clientId[50];
    sprintf(clientId, "ESP32Client-%ld", r);
    if (client.connect(clientId)) {
      Serial.println("connected");
      client.publish("LDR", "photoresistor is working");
      client.subscribe("control"); 
      client.subscribe("control/relay"); 
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void callback(char* topic, byte* message, unsigned int length) {
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  String stMessage;
  for (int i = 0; i < length; i++) {
    Serial.print((char)message[i]);
    stMessage += (char)message[i];
  }
  Serial.println();

  if (String(topic) == "control") {
    Serial.print("Received control message: ");
    Serial.println(stMessage);
    
    if (stMessage == "led_on") {
      digitalWrite(ledPin, HIGH); // Turn on the LED
    } else if (stMessage == "led_off") {
      digitalWrite(ledPin, LOW); // Turn off the LED
    }
  }

  if (String(topic) == "control/relay") {
    Serial.print("Received control message for relay: ");
    Serial.println(stMessage);
    
    if (stMessage == "open") {
      digitalWrite(relayPin, HIGH); // Turn on the relay
    } else if (stMessage == "close") {
      digitalWrite(relayPin, LOW); // Turn off the relay
    }
  }
}
NOCOMNCVCCGNDINLED1PWRRelay Module