#include "DHTesp.h"
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "time.h"

const int    SSL_PORT      = 443;                           
const char*  HTTP_METHOD   = "PATCH ";                          
const char*  FIREBASE_HOST = "test-esp32-fba01-default-rtdb.asia-southeast1.firebasedatabase.app"; 
const String FIREBASE_AUTH = "W2LSm9ml907NFUetSvFFM5FZfU6req70hK2uXGLl";                      
const String FIREBASE_PATH = "/ESP32-SensorNode-Device"; 

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 28800;
const int   daylightOffset_sec = 0;

// create GPIO variables
#define soilMoisture_pin  34
#define photoResistor_pin 35
#define dht_pin           32
#define pump_pin 15
#define fan_pin 5
#define light_pin 18

// define oled settings
#define SCREEN_WIDTH      128
#define SCREEN_HEIGHT     64
#define SCREEN_ADDRESS    0x3c
#define OLED_RESET        4

// create I/O device object
//DHT dht(dht_pin, DHT11);
DHTesp dht;
Adafruit_SSD1306 oled(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
  // initialize serial communication at 115200 bits per second:
  Serial.begin(115200);


  // Initiate the Wi-Fi connection
  WiFi.begin("Wokwi-GUEST", "", 6);

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

  // Init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

  // Print some information of the Wi-Fi network
  Serial.print("\nConnected to the ");
  Serial.println((String) WiFi.SSID() + " network");
  Serial.print("[*] RSSI: ");
  Serial.println((String) WiFi.RSSI() + " dB");
  Serial.print("[*] ESP32 IP: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  // initialize digital pins as output.
  pinMode(fan_pin, OUTPUT); //FAN
  pinMode(light_pin, OUTPUT); //LIGHT
  pinMode(pump_pin, OUTPUT); //PUMP    

  // initialize DHT sensor
  dht.setup(dht_pin, DHTesp::DHT22);

  // check if the OLED has been initialized
  if (!oled.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("OLED screen failed to initialize!"));
    for (;;);
  }

  // display Adafruit splash screen.
  oled.display();
  delay(2000);
}

void loop() {
  // Create Wi-Fi secure client object
  WiFiClientSecure client;

  // Allows for 'insecure' connections. It turns off certificate and/or fingerprint checking
  client.setInsecure();

  Serial.print("Connecting to ");
  Serial.println(FIREBASE_HOST);

  // Create TLS (Transport Layer Security) connections
  if (!client.connect(FIREBASE_HOST, SSL_PORT)) {
    Serial.println("Connection failed");
    return;
  }  

  // Time
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }

  char month[10];
  strftime(month,10, "%B", &timeinfo);
  char date_of_month[3];
  strftime(date_of_month,3, "%d", &timeinfo);
  char year[5];
  strftime(year,5, "%Y", &timeinfo);
  char hour[3];
  strftime(hour,3, "%H", &timeinfo);
  char minute[3];
  strftime(minute,3, "%M", &timeinfo);
  char second[3];
  strftime(second,3, "%S", &timeinfo);
  
  String timestamp = String(month)+" "+ String(date_of_month)+" "+String(year)+" "+String(hour)+":"+String(minute)+":"+String(second);

  String plant_mood;
  String fan_control;
  String light_control;
  String pump_control;
  
  // read relative humidity from DHT11 sensor
  int humidity = dht.getHumidity();

  // read temperature (degress Fahrenheit) from DHT11 sensor
  float temperature = dht.getTemperature();

  // check if any reads failed; try to read again.
  if (isnan(humidity) || isnan(temperature)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  if (humidity > 40 ||  temperature > 75){
    digitalWrite(fan_pin, HIGH);
    fan_control= "true";
    
  }
  else{
    digitalWrite(fan_pin, LOW);
    fan_control = "false";
  }

  // read the ADC value on soil moisture sensor (ADC2_CH0).
  int soilMoistureValue = analogRead(soilMoisture_pin);

  // read soil moisture content from ADC value
  String soilMoistureContent;
  if (soilMoistureValue <= 4095 && soilMoistureValue > 3400) {
    soilMoistureContent = "hanged";
    digitalWrite(pump_pin, LOW);
    pump_control = "false";
  }
  if (soilMoistureValue < 3400 && soilMoistureValue > 3000) {
    soilMoistureContent = "dry";
    digitalWrite(pump_pin, HIGH);
    pump_control = "true";
  }
  if (soilMoistureValue < 3200 && soilMoistureValue > 2500) {
    soilMoistureContent = "moist";
    digitalWrite(pump_pin, HIGH);
    pump_control = "true";
  }
  if (soilMoistureValue < 2500) {
    soilMoistureContent = "wet";
    pump_control = "false";
    digitalWrite(pump_pin, LOW);
  }

  // read the ADC value on light sensor (ADC2_CH9).
  int photoResistorValue = analogRead(photoResistor_pin);

  // read sun light brightness from ADC value
  String sunLight;
  if (photoResistorValue <= 4095 && photoResistorValue > 3000) {
    sunLight = "bright";
    digitalWrite(light_pin, LOW);
    light_control = "false";
  }
  if (photoResistorValue < 3000 && photoResistorValue > 2000) {
    sunLight = "dim";
    digitalWrite(light_pin, HIGH);
    light_control = "true";
  }
  if (photoResistorValue < 2000) {
    sunLight = "dark";
    digitalWrite(light_pin, HIGH);
    light_control = "true";
  }

  if (digitalRead(light_pin) == HIGH || digitalRead(fan_pin) == HIGH || digitalRead(pump_pin) == HIGH){
    plant_mood = "sad T_T";
  }
  else{
    plant_mood = "happy ^_^";
  }

  int waterUse = random(0, 100);
  float powerUse = random(200, 500);

  // Create HTTPS URL
  String HTTP_URL = FIREBASE_PATH + ".json?auth=" + FIREBASE_AUTH;

  // Create HTTP body in JSON (JavaScript Object Notation) format
  String HTTP_BODY1 = "{\"DT\":\"" + timestamp + "\"," + 
  "\"Temperature\":" + temperature  + "," + 
  "\"Humidity\":" + humidity + "," + 
  "\"Sunlight\":\"" + sunLight + "\"," + 
  "\"SoilMoisture\":\"" + soilMoistureContent + "\"," + 
  "\"WaterPumpState\":" + pump_control + "," + 
  "\"FanState\":" + fan_control + "," + 
  "\"GrowingLightState\":" + light_control + "," + 
  "\"WaterConsumption\":" + waterUse  + "," + 
  "\"PowerConsumption\":" + powerUse  + "," + 
  "\"PlantMood\":\"" + plant_mood + "\"}" ;

  // Send HTTP request header
  client.println(HTTP_METHOD + HTTP_URL + " HTTP/1.1");
  client.println("Host: " + String(FIREBASE_HOST));
  client.println("Connection: close");
  client.println("Content-Length: " + String(HTTP_BODY1.length()));
  client.println();
  client.println(HTTP_BODY1);

  // Read response from server and print them to Serial monitor
  while (client.connected()) {
    String response = client.readStringUntil('\n');
    Serial.println(response);
    if (response == "\r") {
      // Exit loop
      break;
    }
  }

  // Print response body content
  while (client.available()) {
    char response_body = client.read();
    Serial.print(response_body);
  }
  Serial.println();
  Serial.println("-------------------------------------------");

  // Disconnect to Firebase before to reconnect it for new request
  client.stop();

  // plot data to Serial plotter.
  Serial.print("D/T:");
  Serial.print(timestamp);
  Serial.print(",");
  
  Serial.print("Temperature(°C):");
  Serial.print(temperature);
  Serial.print(",");

  Serial.print("Humidity(%):");
  Serial.print(humidity);
  Serial.print(",");

  Serial.print("Soil_Moisture:");
  Serial.print(soilMoistureValue);
  Serial.print(",");

  Serial.print("Light_Brightness:");
  Serial.print(photoResistorValue);
  Serial.print("\n");

  Serial.print("Plant_Mood:");
  Serial.print(plant_mood);
  Serial.print("\n");  

  // print data to OLED display.
  oled.clearDisplay();                // clear display
  oled.setTextSize(1);                // text size
  oled.setTextColor(WHITE);           // text color
  oled.setCursor(0, 0);               // set position to display

  oled.print("D/T:");            // text to display
  oled.print(timestamp);               // value to display
  oled.print("\n");                   // next line
    
  oled.print("Temperature:");         // text to display
  oled.print(temperature);            // value to display
  oled.drawCircle(104, 2, 2, WHITE);  // degrees symbol to display
  oled.print(" F");                   // unit to display
  oled.print("\n");                   // next line

  oled.print("Humidity:");            // text to display
  oled.print(humidity);               // value to display
  oled.print("%");                    // unit to display
  oled.print("\n");                   // next line

  oled.print("Soil Moisture:");       // text to display
  oled.print(soilMoistureContent);    // value to display
  oled.print("\n");                   // next line

  oled.print("Sun Light:");           // text to display
  oled.print(sunLight);               // value to display
  oled.print("\n");

  oled.print("Plant Mood:");           // text to display
  oled.print(plant_mood);               // value to display
  oled.display();                     // show on OLED
  delay(1000);
}
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
dht1:VCC
dht1:SDA
dht1:NC
dht1:GND
ldr1:VCC
ldr1:GND
ldr1:DO
ldr1:AO
pot1:VCC
pot1:SIG
pot1:GND
led1:A
led1:C
oled1:GND
oled1:VCC
oled1:SCL
oled1:SDA
led2:A
led2:C
led3:A
led3:C
r1:1
r1:2
r2:1
r2:2
r3:1
r3:2