#include <WiFi.h>
#include <PubSubClient.h>
#include "DHTesp.h"
#include <NTPClient.h> //to take time
#include <WiFiUdp.h>
#include <ESP32Servo.h>
#include <Wire.h>

#define DHT_PIN 12
#define BUZZER 5
#define LDR_LEFT 32
#define LDR_RIGHT 33
#define SERVOMOTOR 4

#define NTP_SERVER     "pool.ntp.org"
#define UTC_OFFSET     3600*5.5
#define UTC_OFFSET_DST 0

DHTesp dhtSensor;

WiFiClient espClient;
PubSubClient mqttClient(espClient);

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP);

char tempAr[6];
char ldrLeftArr[4];
char ldrRightArr[4];

Servo servo;

bool isScheduledON= false;
unsigned long scheduledOnTime;

int t_off = 30;
float gamma_i = 0.75;

void setup() {

  Serial.begin(115200);
  setupWiFi();
  setupMqtt();

  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);

  timeClient.begin();
  timeClient.setTimeOffset(UTC_OFFSET);  

  servo.attach(SERVOMOTOR);
  pinMode(BUZZER, OUTPUT);
  digitalWrite(BUZZER,LOW);
}

void loop() {
  if(!mqttClient.connected()){
    Serial.println("Reconnecting to MQTT Broker");
    connectToBroker();
  }
  mqttClient.loop();


  updateTemperature();
  Serial.println(tempAr);
  mqttClient.publish("ENTC-KC-TEMP", tempAr);

  checkSchedule();
  delay(100);
  
  updateLDR();

  mqttClient.publish("ENTC-LIGHT-L-KC", ldrLeftArr);
  //delay(50);
  mqttClient.publish("ENTC-LIGHT-R-KC", ldrRightArr);
  //delay(50);
}


void buzzerOn(bool on){
  if (on){
    tone(BUZZER,256);

  }else{
    noTone(BUZZER);
  }
}

void setupMqtt(){
  mqttClient.setServer("test.mosquitto.org",1883);
  mqttClient.setCallback(receiveCallback);
}

void receiveCallback(char* topic,byte* payload, unsigned int length){
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");

  char payloadCharAr[length];
  Serial.print("Message Received: ");
  for (int i=0; i<length; i++){
    Serial.print((char)payload[i]);
    payloadCharAr[i]=(char)payload[i];
  }
  Serial.println();
  if (strcmp(topic, "ENTC-KC-MAIN-ON-OFF")==0){
    buzzerOn(payloadCharAr[0]=='1');
  }else if(strcmp(topic, "ENTC-KC-SCH-ON")==0){
    if(payloadCharAr[0]=='N'){
      isScheduledON = false;
    }else{
      isScheduledON = true;
      scheduledOnTime=atol(payloadCharAr);
    }
  }else if(strcmp(topic, "SERVO-ADJUSTMENTS-MIN_ANGLE")==0) {
    t_off = String(payloadCharAr).toInt();
  }else if(strcmp(topic, "SERVO-ADJUSTMENTS-CF")==0) {
    gamma_i = String(payloadCharAr).toFloat();
  }
}
void connectToBroker(){
  while (!mqttClient.connected()){
    Serial.print("Attempting MQTT connection...");
    if(mqttClient.connect("ESP32- 12345645454")){
      Serial.println("MQTT connected ");
      mqttClient.subscribe("ENTC-KC-MAIN-ON-OFF");
      mqttClient.subscribe("ENTC-KC-SCH-ON");
      mqttClient.subscribe("SERVO-ADJUSTMENTS-MIN_ANGLE");
      mqttClient.subscribe("SERVO-ADJUSTMENTS-CF");

      //subscribe
    }else{
      Serial.print("Failed to connect to the MQTT Broker");
      Serial.print(mqttClient.state());
      delay(5000);
    }
  }
}

void updateTemperature(){
  TempAndHumidity data = dhtSensor.getTempAndHumidity();
  String(data.temperature,2).toCharArray(tempAr,6);
}

void setupWiFi(){
  Serial.println();
  Serial.print("Connecting to WiFi");
  WiFi.begin("Wokwi-GUEST", "", 6);
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
    Serial.print(".");
  }
  Serial.println(" Connected!");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}


unsigned long getTime(){
  timeClient.update();
  return timeClient.getEpochTime();
}

void checkSchedule(){
  if(isScheduledON){
    unsigned long currentTime = getTime();
    if (currentTime > scheduledOnTime ){
      buzzerOn(true);
      isScheduledON= false;
      mqttClient.publish("ENTC-KC-MAIN-ON-OFF-ESP","1");
      mqttClient.publish("ENTC-KC-SCH-ESP-ON","0");

      Serial.println("Scheduled ON");
    }
  }
}

void updateLDR() {
  float lsv = analogRead(LDR_LEFT) * 1.00;
  float rsv = analogRead(LDR_RIGHT) * 1.00;
  
  float lsv_cha = (float)(lsv - 4063.00)/(32.00-4063.00);
  float rsv_cha = (float)(rsv - 4063.00)/(32.00-4063.00);

  updateAngle(lsv_cha,rsv_cha);

  String(lsv_cha).toCharArray(ldrLeftArr,4);
  String(rsv_cha).toCharArray(ldrRightArr,4);
}

void updateAngle(float lsv, float rsv){
  //calculating position of servo motor
  float max_I = lsv;
  float D = 1.5;

  if(rsv > max_I){
    max_I = rsv;
    D = 0.5;
  }

  int theta = t_off * D + (180 - t_off) * max_I * gamma_i;
  theta = min(theta,180);
  servo.write(theta);
}
$abcdeabcde151015202530354045505560fghijfghij
esp:VIN
esp:GND.2
esp:D13
esp:D12
esp:D14
esp:D27
esp:D26
esp:D25
esp:D33
esp:D32
esp:D35
esp:D34
esp:VN
esp:VP
esp:EN
esp:3V3
esp:GND.1
esp:D15
esp:D2
esp:D4
esp:RX2
esp:TX2
esp:D5
esp:D18
esp:D19
esp:D21
esp:RX0
esp:TX0
esp:D22
esp:D23
bz1:1
bz1:2
r3:1
r3:2
dht1:VCC
dht1:SDA
dht1:NC
dht1:GND
ldr1:VCC
ldr1:GND
ldr1:DO
ldr1:AO
ldr2:VCC
ldr2:GND
ldr2:DO
ldr2:AO
servo1:GND
servo1:V+
servo1:PWM