//* Fill-in your Template ID (only if using Blynk.Cloud) */
#define BLYNK_TEMPLATE_ID "TMPL3pyLBFl5l"
#define BLYNK_TEMPLATE_NAME "temp and humidity controller"
#define BLYNK_AUTH_TOKEN "7P4kplhd0mHE2svZ8gj5hX4aI4TeRKRQ"
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "verma ji";
char pass[] = "tu ja re";


#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <Preferences.h>
#include <SPI.h>
#include <Wire.h>
#include <DHT.h>
#include <AceButton.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

using namespace ace_button;
Preferences pref;

#define DHTPIN            15                                                                                                       //D23  pin connected with DHT
// Uncomment whatever type you're using!
#define DHTTYPE   DHT22     // DHT 22
//#define DHTTYPE DHT22   // DHT 22, AM2302, AM2321
//#define DHTTYPE DHT21   // DHT 21, AM2301

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Setpoint and setHumi values (in degrees Celsius)
float setTemp = 0;
float setHumi = 0;
float currentTemp = 0;
float currentHumi = 0;
float targettemp1 = 33;
float targettemp2 = 40;


// define the GPIO connected with Relays and Buttons
#define FAN1 18  //D18
#define FAN2 32  //D32
#define FAN3 33  //D33
#define Water1 19  //D19

#define ButtonPin1 13  //D25
#define ButtonPin2 26  //D26 
#define ButtonPin3 27  //D27

#define wifiLed   3   //D3

//Change the virtual pins according the rooms
#define VPIN_Mode           V1
#define VPIN_currentTemp    V2
#define VPIN_currentHumi    V3
#define VPIN_setTemp        V4
#define VPIN_setHumi        V5
#define VPIN_Heater         V6
#define VPIN_Humidifier     V7

// Relay and Mode State
bool FANState1 = LOW; //Define integer to remember the toggle state for heater
bool FANState2 = LOW;
bool FANState3 = LOW;
bool WATERState = LOW; //Define integer to remember the toggle state for Humidifier
bool modeState = LOW; //Define integer to remember the mode

int wifiFlag = 0;


char auth[] = BLYNK_AUTH_TOKEN;

ButtonConfig config1;
AceButton button1(&config1);
ButtonConfig config2;
AceButton button2(&config2);
ButtonConfig config3;
AceButton button3(&config3);

void handleEvent1(AceButton*, uint8_t, uint8_t);
void handleEvent2(AceButton*, uint8_t, uint8_t);
void handleEvent3(AceButton*, uint8_t, uint8_t);


BlynkTimer timer;
DHT dht22(DHTPIN, DHTTYPE);

// When App button is pushed - switch the state

BLYNK_WRITE(VPIN_Heater) {
  FANState1 = param.asInt();
  digitalWrite(FAN1, !FANState1);
  pref.putBool("Heater", FANState1);
}

BLYNK_WRITE(VPIN_Humidifier) {
  WATERState = param.asInt();
  digitalWrite(Water1, !WATERState);
  pref.putBool("Humidifier", WATERState);
}

BLYNK_WRITE(VPIN_Mode) {
  modeState = param.asInt();
  pref.putBool("Mode", modeState);
}

BLYNK_WRITE(VPIN_setTemp) {
  setTemp = param.asFloat();
  pref.putBool("setemp", setTemp);
}

BLYNK_WRITE(VPIN_setHumi) {
  setHumi = param.asFloat();
  pref.putBool("Humidity", setHumi);
}

void checkBlynkStatus() { // called every 2 seconds by SimpleTimer

  bool isconnected = Blynk.connected();
  if (isconnected == false) {
    wifiFlag = 1;
    Serial.println(" Disconnected");
    display.setTextSize(2);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(0, 2);
    digitalWrite(wifiLed, LOW);
  }
  if (isconnected == true) {
    wifiFlag = 0;
    Serial.println(" Connected");
    display.setTextSize(2);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(3, 2);
    display.println(" Connected");
    digitalWrite(wifiLed, HIGH);
  }
  display.display();
  //delay(1000);
}

BLYNK_CONNECTED() {
  // update the latest state to the server
  Blynk.virtualWrite(VPIN_Mode, modeState);
  Blynk.syncVirtual(VPIN_currentTemp);
  Blynk.syncVirtual(VPIN_currentHumi);
  Blynk.syncVirtual(VPIN_setTemp);
  Blynk.syncVirtual(VPIN_setHumi);
  Blynk.virtualWrite(VPIN_Heater, FANState1);
  Blynk.virtualWrite(VPIN_Heater, FANState2);
  Blynk.virtualWrite(VPIN_Heater, FANState3);
  Blynk.virtualWrite(VPIN_Humidifier, WATERState);

}

void setup()
{
  Serial.begin(115200);
  //Open namespace in read-write mode
  pref.begin("Relay_State", false);

  pinMode(FAN1, OUTPUT);
  pinMode(FAN2, OUTPUT);
  pinMode(FAN3, OUTPUT);
  pinMode(Water1, OUTPUT);
  pinMode(wifiLed, OUTPUT);

  pinMode(ButtonPin1, INPUT_PULLUP);
  pinMode(ButtonPin2, INPUT_PULLUP);
  pinMode(ButtonPin3, INPUT_PULLUP);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Don't proceed, loop forever
  }
  display.clearDisplay();
  display.setTextColor(SSD1306_WHITE);
  display.setTextSize(2);
  display.setCursor(15, 20);
  display.println("WELCOM");
  display.display();
  delay(2000);

  //During Starting all Relays should TURN OFF
  digitalWrite(FAN1, !FANState1);
  digitalWrite(FAN2, !FANState2);
  digitalWrite(FAN3, !FANState3);
  digitalWrite(Water1, !WATERState);

  dht22.begin();    // Enabling DHT sensor
  digitalWrite(wifiLed, LOW);

  config1.setEventHandler(button1Handler);
  config2.setEventHandler(button2Handler);
  config3.setEventHandler(button3Handler);

  button1.init(ButtonPin1);
  button2.init(ButtonPin2);
  button3.init(ButtonPin3);

  //Blynk.begin(auth, ssid, pass);
  WiFi.begin(ssid, pass);
  timer.setInterval(2000L, checkBlynkStatus); // check if Blynk server is connected every 2 seconds
  timer.setInterval(1000L, sendSensor); // Sending Sensor Data to Blynk Cloud every 1 second
  Blynk.config(auth);
  delay(1000);

  getRelayState(); // Get the last state of Relays and Set values of Temp & Humidity

  Blynk.virtualWrite(VPIN_Heater, FANState1);
  Blynk.virtualWrite(VPIN_Humidifier, WATERState);
  Blynk.virtualWrite(VPIN_setTemp, setTemp);
  Blynk.virtualWrite(VPIN_setHumi, setHumi);
}


void readSensor() {

  currentTemp = dht22.readTemperature();
  currentHumi = dht22.readHumidity();
  if (isnan(currentHumi) || isnan(currentTemp)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }
}

void sendSensor()
{
  readSensor();
  // You can send any value at any time.
  // Please don't send more that 10 values per second.
  Blynk.virtualWrite(VPIN_currentTemp, currentTemp);
  Blynk.virtualWrite(VPIN_currentHumi, currentHumi);
}

void getRelayState()
{
  //Serial.println("reading data from NVS");
  modeState = pref.getBool("Mode", 0);
  Blynk.virtualWrite(VPIN_Mode, modeState);
  delay(200);
  FANState1 = pref.getBool("Heater", 0);
  digitalWrite(FAN1, !FANState1);
  FANState2 = pref.getBool("Heater",0);
  digitalWrite(FAN2, !FANState2);
  FANState3 = pref.getBool("Heater",0);
  digitalWrite(FAN3, !FANState3);
  Blynk.virtualWrite(VPIN_Heater, FANState1);
  delay(200);
  WATERState = pref.getBool("Humidifier", 0);
  digitalWrite(Water1, !WATERState);
  Blynk.virtualWrite(VPIN_Humidifier, WATERState);
  delay(200);
  setTemp = pref.getBool("setemp", 0);
  Blynk.virtualWrite(VPIN_setTemp, setTemp);
  delay(200);
  setHumi = pref.getBool("Humidity", 0);
  Blynk.virtualWrite(VPIN_setHumi, setHumi);
  delay(200);
}


void DisplayData()  {
  display.clearDisplay();
  display.setTextSize(2);
  display.setCursor(2, 20);
  display.print(int(currentTemp));
  display.print((char)247);
  display.println("C");
  display.setCursor(60, 20);
  display.print(": ");
  display.print(int(currentHumi));
  display.println("%");

 if (WATERState== 1) {
  display.setTextSize(1);
  display.setCursor(5, 36);
  display.println("WATER ON");
  } else {
  display.setTextSize(1);
  display.setCursor(5, 36);
  display.println("WATER OFF");
  }
  display.setTextSize(2);
  display.setCursor(60, 35);
  display.print(": ");

if (FANState1== 1) {
  display.setTextSize(1);
  display.setCursor(70, 36);
  display.println("FAN1 ON");
} else if(FANState2== 1) {
  display.setTextSize(1);
  display.setCursor(70, 36);
  display.println("FAN2 ON");
} else if(FANState3== 1) {
  display.setTextSize(1);
  display.setCursor(70,36);
  display.println("FAN3 ON");
} else {
  display.setTextSize(1);
  display.setCursor(70, 36);
  display.println("FAN OFF");
}

  display.setTextSize(1);
  display.setCursor(0, 57);
  display.print("sTemp:");
  display.print(int(setTemp));
  display.print((char)247);
  display.println("C");
  display.setTextSize(1);
  display.setCursor(67, 57);
  display.print("sHumi:");
  display.print(int(setHumi));
  display.println("%");


if (modeState == 1) {
  {
    display.setTextSize(1);
    display.setCursor(20, 45);
    display.print("Automatic Mode");
  }
  if (currentTemp < setTemp) {
      FANState1 = 0;
      FANState2 = 0;
      FANState3 = 0;
      digitalWrite(FAN1, !FANState1);
      digitalWrite(FAN2, !FANState2);
      digitalWrite(FAN3, !FANState3);
      pref.putBool("Heater", FANState1);
      Serial.println("Heater OFF");
      Blynk.virtualWrite(VPIN_Heater, FANState1);
  } else if(currentTemp > targettemp2) {
      FANState1 = 0;
      FANState2 = 0;
      FANState3 = 1;
      digitalWrite(FAN1, !FANState1);
      digitalWrite(FAN2, !FANState2);
      digitalWrite(FAN3, !FANState3);
      pref.putBool("Heater", FANState3);
      Serial.println("Heater3 ON");
      Blynk.virtualWrite(VPIN_Heater, FANState1);
  } else if(currentTemp > targettemp1) {
      FANState1 = 0;
      FANState2 = 1;
      FANState3 = 0;
      digitalWrite(FAN1, !FANState1);
      digitalWrite(FAN2, !FANState2);
      digitalWrite(FAN3, !FANState3);
      pref.putBool("Heater", FANState2);
      Serial.println("Heater2 ON");
      Blynk.virtualWrite(VPIN_Heater, FANState2);
    } else if(currentTemp > setTemp) {
      FANState1 = 1;
      FANState2 = 0;
      FANState3 = 0;
      digitalWrite(FAN1, !FANState1);
      digitalWrite(FAN2, !FANState2);
      digitalWrite(FAN3, ! FANState3);
      pref.putBool("Heater1", FANState1);
      Serial.println("Heater1 ON");
      Blynk.virtualWrite(VPIN_Heater, FANState1);
    } else {
      FANState1 = 0;
      FANState2 = 0;
      FANState3 = 0;
      digitalWrite(FAN1, !FANState1);
      digitalWrite(FAN2, FANState2);
      digitalWrite(FAN3, !FANState3);
      pref.putBool("Heater",FANState1);
      Blynk.virtualWrite(VPIN_Heater, FANState1);
    }
     if (currentHumi < setHumi) {
      WATERState = 1;
      digitalWrite(Water1, !WATERState);
      Serial.println("Humidifier ON");
      pref.putBool("Humidifier", WATERState);
      Blynk.virtualWrite(VPIN_Humidifier, WATERState);
    } else {
      WATERState = 0;
      digitalWrite(Water1, !WATERState);
      Serial.println("Humidifier OFF");
      pref.putBool("Humidifier", WATERState);
      Blynk.virtualWrite(VPIN_Humidifier, WATERState);
    }
  } else {
    display.setTextSize(1);
    display.setCursor(32, 45);
    display.print("Manual Mode");
   }
  display.display();
}


void loop()
{
  Blynk.run();
  timer.run();
  DisplayData();
  button1.check();
  button2.check();
  button3.check();
}

void button1Handler(AceButton* button, uint8_t eventType, uint8_t buttonState) {
  Serial.println("Mode");
  switch (eventType) {
    case AceButton::kEventReleased:
      modeState = !modeState;
      pref.putBool("Mode", modeState);
      Blynk.virtualWrite(VPIN_Mode, modeState);
      break;
  }
}
void button2Handler(AceButton* button, uint8_t eventType, uint8_t buttonState) {
  Serial.println("Heater");
  switch (eventType) {
    case AceButton::kEventReleased:
      digitalWrite(FAN1, FANState1);
      digitalWrite(FAN2, FANState2);
      digitalWrite(FAN3, FANState3);
      FANState1 = !FANState1;
      FANState2 = !FANState2;
      FANState3 = !FANState3;
      pref.putBool("Heater", FANState1);
      Blynk.virtualWrite(VPIN_Heater, FANState1);
      break;
  }
}
void button3Handler(AceButton* button, uint8_t eventType, uint8_t buttonState) {
  Serial.println("Humidifier");
  switch (eventType) {
    case AceButton::kEventReleased:
      digitalWrite(Water1, WATERState);
      WATERState = !WATERState;
      pref.putBool("VPIN_Humidifier", WATERState);
      Blynk.virtualWrite(VPIN_Humidifier, WATERState);
      break;
  }
}
  
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
oled1:GND
oled1:VCC
oled1:SCL
oled1:SDA
dht1:VCC
dht1:SDA
dht1:NC
dht1:GND
led1:A
led1:C
led2:A
led2:C
led3:A
led3:C
led4:A
led4:C
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r