/**
   ESP32 + DHT22 Example for Wokwi
   
   https://wokwi.com/arduino/projects/322410731508073042
*/
#include <WiFi.h>
#include "DHTesp.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

#include <stdio.h>
#include <stdbool.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <esp_err.h>
#include <HCSR04.h>

/************************* WiFi Access Point ***************************/
#define WLAN_SSID "Wokwi-GUEST"
#define WLAN_PASS ""
/************************* Adafruit.io Setup ***************************/
#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883                   // use 8883 for SSL
#define AIO_USERNAME    "Joab_Urbano"
#define AIO_KEY         "aio_mVdl92oNiSTLQxiTKRH3ixlxcOgu"

/************ Global State ************/
#define DHT_PIN 15
#define LED_PIN 13

#define ECHO_GPIO 12
#define TRIGGER_GPIO 14
#define bombPin 27

unsigned int duracao = 0; // Armazenar o tempo em m segundos do sensor de ultrasom
unsigned int distanciaCM=0; // Armazenar a distância do sensor de ultrasom


DHTesp dhtSensor;

//Criando ESP8266 classe WiFiClient para conectar ao MQTT server.
WiFiClient client;

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_USERNAME, AIO_KEY);

/****************************** Feeds ***************************************/

//Ajeitar os feeds e olhar como checar o botão
Adafruit_MQTT_Publish temp = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/temperatura");
Adafruit_MQTT_Publish hmdt = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/humidade");
Adafruit_MQTT_Publish altura = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/ultrasom");
Adafruit_MQTT_Publish bomba1 = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/teste");

// Setup a feed called 'onoff' for subscribing to changes to the ON/OFF button
Adafruit_MQTT_Subscribe onoffbtn = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/led", MQTT_QOS_1);

// Função para conectar e reconectar MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect(){
  int8_t ret;
  // Stop if already connected.
  if (mqtt.connected()){
    return;
  }
  Serial.print("Connecting to MQTT... ");
  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0){ // connect will return 0 for connected
    Serial.println(mqtt.connectErrorString(ret));
    Serial.println("Retrying MQTT connection in 10 seconds...");
    mqtt.disconnect();
    delay(10000);
    retries--;
    if (retries == 0) {
      // basically die and wait for WDT to reset me
      while (1);
    }
  }
  Serial.println("MQTT Conectado!");
}

// Botão
void onoffcallback(char *data, uint16_t len) {
  Serial.print("Bomba de limpeza: ");
  if (strcmp(data, "ON") == 0) {
    Serial.println("Ligada");
    digitalWrite(LED_PIN, HIGH);
  } else {
    Serial.println("Desligada");
    digitalWrite(LED_PIN, LOW);
  }
}

//Conexão wi-fi
void setup() {
  int dis = 97;
  Serial.begin(115200);
  pinMode(ECHO_GPIO, INPUT); 
  pinMode(TRIGGER_GPIO, OUTPUT);
  pinMode(bombPin, OUTPUT);

  pinMode(LED_PIN, OUTPUT);
  dhtSensor.setup(DHT_PIN, DHTesp::DHT22);
  delay(10);

  Serial.println(F("Adafruit MQTT demo"));

  //Conectando o WiFi
  Serial.print("Conectando a");
  Serial.println(WLAN_SSID);

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

  // Set the callback function to be called when feed's message arrives
  onoffbtn.setCallback(onoffcallback);
  
  // Setup MQTT subscription for time feed.
  mqtt.subscribe(&onoffbtn);
}

unsigned long lastMsg = 0;

void loop(){
  int b1 = 0;
   digitalWrite(TRIGGER_GPIO,HIGH);//Eleva o sinal do Trigger 

  delayMicroseconds(10);//Por 10 Microsegundos

  digitalWrite(TRIGGER_GPIO,LOW); //Abaixando sinal do trigger

  //Armazena o valor em microsegundos que foi lido

  duracao=pulseIn(ECHO_GPIO,HIGH);
  distanciaCM=duracao*0.01719445; //convertendo para centimetros

  //verificando a distância para ativar/desativar a bomba
  if(distanciaCM >= 65){
    digitalWrite(bombPin,HIGH);
    b1 = 1;
  }
  else if(distanciaCM <= 50){
    digitalWrite(bombPin,LOW);
    b1 = 0;
  }
  int dis = 145 - distanciaCM;
  // Ensure the connection to the MQTT server is alive (this will make the first
  // connection and automatically reconnect when disconnected).  See the MQTT_connect
  // function definition further below.
  MQTT_connect();

  mqtt.processPackets(10000);
  

  if(! mqtt.ping()) {
    mqtt.disconnect();
  }
  
  // Publicação nos feeds
  unsigned long now = millis();
  if (now - lastMsg > 10000){
    lastMsg = now;
    TempAndHumidity data = dhtSensor.getTempAndHumidity();
    Serial.println("----------");
    Serial.println("Temperature: " + String(data.temperature, 1) + "°C");
    Serial.println("Humidade: " + String(data.humidity, 0) + "%");
    Serial.println("Altura da água: " + String(dis) + "cm");
    char strTemperature[20], strHumidity[20];
    sprintf(strTemperature, "%.1f", data.temperature);
    sprintf(strHumidity, "%.0f", data.humidity);

    altura.publish(dis);
    temp.publish(strTemperature);
    hmdt.publish(strHumidity);

    if(b1 == 1){
      bomba1.publish("Bomba Ligada");
    }
    else{
      bomba1.publish("Bomba Desligada");
    }
  }
}