//  Adafruit io
//  Anemômetro
//  BME280  - pressão
//  DHT22   - temperatura e UR
//  DPM por PM
//  Bluetooth
//  Interrupt
//  IV
//  Esp8266
//  ETo - diário (com duas equações)
//  File sistem
//  Json 5.13.5
//  OTA
//  Google forms
//  NTP - fix
//  Pluviômetro - fix
//  PPT acumulada
//  Tpo - calculado
//  Telegram  -  Fast bot
//  Wifi

#include <Adafruit_MQTT_Client.h>
#include <WiFiClientSecure.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_MQTT.h>
#include <ESP8266WiFi.h>            // deve ser a 2.4.0 ou 2.4.1
#include <ESP8266mDNS.h>
#include <ArduinoOTA.h>
#include <NTPClient.h>              // NTP CLient Master (k)
#include <WiFiUdp.h>
#include <FastBot.h>
#include <DHTesp.h>
#include <math.h>                   // para calcular log
#include <Wire.h>
#include <FS.h>

#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883
#define AIO_USERNAME    "Azevedo"
#define AIO_KEY         "aio_gyYE56UfvXN3F14Su6slR"

#define pin_led       2       // 2 led indicador envio dados 
#define pin_rad       A0      // sensor iv
#define wind          14      // anemometro
#define pin_net       16      // led indicador conexão internet
#define pin_dht       12      // dht22
#define pluv          13      // pluviometro

IPAddress ip(192, 168, 0, 111);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);

WiFiClient clientt;

Adafruit_MQTT_Client mqtt(&clientt, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
Adafruit_BME280 bme;
WiFiClientSecure client_secure;
WiFiUDP udp;
FastBot bot;
DHTesp dht;

NTPClient ntpClient( udp, "europe.pool.ntp.org" , (-3 * 3600) , 60000 );

Adafruit_MQTT_Publish _t_atual     = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/t_atual"     , MQTT_QOS_1);
Adafruit_MQTT_Publish _ur_atual    = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/ur_atual"    , MQTT_QOS_1);
Adafruit_MQTT_Publish _vv_atual    = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/vv_atual"    , MQTT_QOS_1);
Adafruit_MQTT_Publish _r_atual     = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/r_atual"     , MQTT_QOS_1);
Adafruit_MQTT_Publish _p_atual     = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/p_atual"     , MQTT_QOS_1);
Adafruit_MQTT_Publish _chuva_atual = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/chuva_atual" , MQTT_QOS_1);
Adafruit_MQTT_Publish _eto         = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/eto"         , MQTT_QOS_1);
Adafruit_MQTT_Publish _chuva_dia   = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/chuva_dia"   , MQTT_QOS_1);
Adafruit_MQTT_Publish _vv_rajada   = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/vv_rajada"   , MQTT_QOS_1);
Adafruit_MQTT_Publish _dpm         = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/dpm"         , MQTT_QOS_1);

String angelo = "698671";

int last_day;
int other_day;

int day;
int month;
int year;
int hour;
int minute;
int second;

unsigned long tempo = 0;

float const perimetro   = 0.62832;
float const intervalo   = 10000;

bool estado   = false;
bool choveu   = false;
bool minu     = false;

String token = "2146552312:AAE8Ag9nuqKanHM_EPYHAaM-eUHHVI";

String textFix = "GET /forms/d/e/1FAIpQLSer7A1Xk-Cxa4d2AlBDSYVBWifMtFDesVxerKlRU9xdw/formResponse?ifq&entry.989374118=";
String data_hora = "";
String conteudo;
String msg = "";

String msg_eto = "Dado perdido, acesse-o pelo banco de dados em: https://io.adafruit.com/Azevedo/dashboards/estacao-esp8266-rc?kiosk=true";
String msg_dpm = msg_eto;

float tempo_total = 5;

float t_max_d = 0;
float t_min_d = 0;
float t_med_d = 0;
float p_max_d = 0;
float p_min_d = 0;
float p_med_d = 0;
float h_max_d = 0;
float h_min_d = 0;
float h_med_d = 0;
float rad_d   = 0;
float ppt_d   = 0;
float vv_d    = 0;

float dpm     = 0;
float eto     = 0;
float ppt     = 0;
float rad     = 0;
float rpm     = 0;
float p_max   = 0;
float p_min   = 0;
float p_med   = 0;
float t_max   = 0;
float t_min   = 0;
float t_med   = 0;
float h_max   = 0;
float h_min   = 0;
float h_med   = 0;
float vv_2m   = 0;
float vv_max  = 0;
float chuva   = 0;

float t_dpm = 0;
float h_dpm = 0;
float rpt_dpm = 0;

float acr = 0;
float tpo = 0;
float es  = 0;
float ea  = 0;

float v = 0;
float t = 0;
float p = 0;
float h = 0;
float r = 0;
float i = 0;
float d = 0;
float k = 0;

float chuva_millis = millis();

int erro = 0;

void inicia_arquivos();
void salva_dados();
void wind_speed();
void molhamento();
void gera_dado();
void writeFile();
void bluetooth();
//void ventando();
//void chovendo();
void telegram();
void mensura();
void evapo();
void date();

void IRAM_ATTR chovendo() {         // void IRAM_ATTR rotina(){}
  if ((millis() - chuva_millis) > 50) {
    ppt++;
    chuva_millis = millis();
  }
}

void setup()
{
  dht.setup(pin_dht, DHTesp::DHT22);
  Serial.begin(9600);
  SPIFFS.begin();
  Wire.begin();

  Serial.println("Connecting...");
  WiFi.mode(WIFI_STA);
  WiFi.begin("Erro", "vpxdj");
  //WiFi.begin("Vivo_4G", "al23");
  //WiFi.config(ip, gateway, subnet);

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

  Serial.println();
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());
  Serial.println(WiFi.localIP());
  Serial.println();

  bot.setToken(token);
  bot.attach(newMsg);

  ntpClient.begin();

  while (!ntpClient.update())
  {
    ntpClient.forceUpdate();
    delay(500);
  }

  String hora = ntpClient.getFormattedTime();
  String data = ntpClient.getFormattedDate();

  hour   = ntpClient.getHours();
  minute = ntpClient.getMinutes();
  second = ntpClient.getSeconds();

  year = (data.substring(0, 4)).toInt();
  month = (data.substring(5, 7)).toInt();
  day = (data.substring(8, 10)).toInt();

  last_day = day;

  ArduinoOTA.setHostname("Estacao_RC");

  // No authentication by default
  ArduinoOTA.setPassword("11189");

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_FS
      type = "filesystem";
    }

    // NOTE: if updating FS this would be the place to unmount FS using FS.end()
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();

  bme.begin(0x76);

  pinMode(pin_net, OUTPUT);
  pinMode(pin_led, OUTPUT);
  pinMode(wind, INPUT);
  pinMode(pluv, INPUT);

  digitalWrite(pin_net, HIGH);
  digitalWrite(pin_led, HIGH);

  tempo = millis();

  estado = digitalRead(wind);

  p = (bme.readPressure()) / 1000;
  t = dht.getTemperature();
  h = dht.getHumidity();

  p_max = p;
  p_min = p;

  t_max = t;
  t_min = t;

  h_max = h;
  h_min = h;

  erro = 0;

  File File_k = SPIFFS.open("/k.txt", "a");
  k = (readFile("/k.txt")).toFloat();
  File_k.close();

  if (k == 0) {
    inicia_arquivos();
  }
  attachInterrupt(digitalPinToInterrupt(pluv), chovendo, RISING);
  interrupts();
  bot.sendMessage("Estação iniciada com sucesso!", angelo);
}

void newMsg(FB_msg& msg) {

  Serial.println(msg.text);
  Serial.println(msg.chatID);

  if (msg.text.equalsIgnoreCase("status")) {
    t_max_d = (readFile("/t_max_d.txt")).toFloat();
    t_min_d = (readFile("/t_min_d.txt")).toFloat();
    p_max_d = (readFile("/p_max_d.txt")).toFloat();
    p_min_d = (readFile("/p_min_d.txt")).toFloat();
    h_max_d = (readFile("/h_max_d.txt")).toFloat();
    h_min_d = (readFile("/h_min_d.txt")).toFloat();
    rad_d   = (readFile("/rad_d.txt"  )).toFloat();
    ppt_d   = (readFile("/ppt_d.txt"  )).toFloat();
    vv_d    = (readFile("/vv_d.txt"   )).toFloat();
    dpm     = (readFile("/dpm.txt"    )).toFloat();
    k       = (readFile("/k.txt"      )).toFloat();

    String reply;

    reply = "Dados diários são: ";
    reply += "T. máx.: " + String(t_max_d, 2) + " ºC, ";
    reply += "T. mín.: " + String(t_min_d, 2) + " ºC, ";
    reply += "UR máx.: " + String(h_max_d, 2) + " %, ";
    reply += "UR mín.: " + String(h_min_d, 2) + " %, ";
    reply += "Rn: " + String((1.3 * 600 * rad_d / 1000000), 2) + " MJ/m2, ";
    reply += "VV: " + String(vv_d / k) + " m/s, ";
    reply += "Ppt: " + String(ppt_d) + " mm e ";
    reply += "DPM: " + String(dpm / 6) + " horas";

    bot.sendMessage(reply, msg.chatID);
  }
  if (msg.text.equalsIgnoreCase("atual")) {

    String reply;

    reply = "Última leitura foi: ";
    reply += "Temp.: " + String(t, 2) + " ºC, ";
    reply += "UR: " + String(h, 2) + " %, ";
    reply += "Pres.: " + String(p, 2) + " kPa, ";
    reply += "VV: " + String(v, 2) + " m/s, ";
    reply += "Rn: " + String(r, 0) + " W/m2 e ";
    reply += "Ppt: " + String(chuva, 2) + " mm";

    bot.sendMessage(reply, msg.chatID);
  }
  if (msg.text.equalsIgnoreCase("painel")) {

    String reply;

    reply = "Estado do painel: ";
    reply += "Temp.: " + String(bme.readTemperature(), 2) + " ºC e";
    reply += "UR: " + String(bme.readHumidity(), 2) + " % ";

    bot.sendMessage(reply, msg.chatID);
  }
  if (msg.text.equalsIgnoreCase("tpo")) {

    t = dht.getTemperature();
    h = dht.getHumidity();
    es  = 0.6108 * pow(10, ((7.5 * t) / (237.3 + t)));
    ea  = h * es / 100;
    double a = log10(ea / 0.611);
    tpo = (237.3 * a) / (7.5 - a);

    String reply;

    reply = "Ponto de orvalho: ";
    reply += "Temp. atual: " + String(t, 2) + " ºC, ";
    reply += "UR atual: " + String(h, 2) + " % e ";
    reply += "Temp. de PO: " + String(tpo, 2) + " ºC";

    bot.sendMessage(reply, msg.chatID);
  }
  /*
    if (msg.text.equalsIgnoreCase("reboot")) {

    bot.sendMessage("Reiniciando...", msg.chatID);
    ESP.restart();
    }
  */
  if (msg.text.equalsIgnoreCase("start")) {

    String reply;

    reply = "Os comandos disponíveis são: ";
    reply += "Atual (Para receber a ultima leitura); ";
    reply += "Status (Para receber os dados diários coletados); ";
    reply += "Painel (Para receber a condição de operação do controlador); ";
    reply += "Tpo (Para o cálculo da temperatura de ponto de orvalho); e ";
    reply += "Reboot (Para reiniciar o controlador)";

    bot.sendMessage(reply, msg.chatID);
  }
  if (msg.text.equalsIgnoreCase("erro")) {

    k = (readFile("/k.txt")).toFloat();
    float bug = (readFile("/erro.txt")).toFloat();
    float lei = (readFile("/leitura.txt")).toFloat();

    String reply;

    reply = "Relatório de erros: ";
    reply += "Pontos depositados: " + String(k, 0) + "; ";
    reply += "Leituras realizadas: " + String(lei, 0) + "; ";
    reply += "Número de erros: " + String(bug, 0) + "; ";
    reply += "Porcentagem de erros: " + String((100 * bug / lei), 4) + " %";
    Serial.println(reply);
    bot.sendMessage(reply, msg.chatID);
  }
  if (msg.text.equalsIgnoreCase("eto")) {
    bot.sendMessage(msg_eto, msg.chatID);
  }
  if (msg.text.equalsIgnoreCase("dpm")) {
    bot.sendMessage(msg_dpm, msg.chatID);
  }
  if (msg.text.equalsIgnoreCase("banco de dados")) {
    String reply;
    reply = "https://io.adafruit.com/Azevedo/dashboards/estacao-esp8266-rc?kiosk=true";
    bot.sendMessage(reply, msg.chatID);
  }
}

void loop()
{
  ArduinoOTA.handle();

  if (Serial.available() > 0) bluetooth();

  if (WiFi.status() != WL_CONNECTED) {

    WiFi.disconnect();
    delay(2000);
    //WiFi.begin("Vivo_4G", "abigail23");
    WiFi.begin("Erro", "vpxdj");
    //WiFi.reconnect();
    digitalWrite(pin_net, HIGH);
    Serial.println("Reconectando...");

    erro ++;

    float bug = (readFile("/erro.txt")).toFloat();
    bug ++;
    writeFile(String(bug), "/erro.txt");

    delay(5000);
    bot.setToken(token);
    bot.attach(newMsg);
  }
  if (WiFi.status() == WL_CONNECTED)
  {
    erro = 0;
    digitalWrite(pin_net, LOW);
  }

  if ((millis() - tempo) > intervalo )
  {
    tempo = millis();

    date();

    if (  minute == 0  or
          minute == 10 or
          minute == 20 or
          minute == 30 or
          minute == 40 or
          minute == 50 )    {

      minu = true;
    }

    else minu = false;

    mensura();
  }

  if (minu == true and i > 20) gera_dado();

  if (i > 120 or erro > 12) {
    Serial.println("Reiniciando...");
    digitalWrite(2, HIGH);
    gera_dado();
    ESP.restart();
  }

  if (digitalRead(wind) != estado)
  {
    rpm ++;
    estado = !estado;
  }

  delay(10);
}

void date()
{
  ntpClient.update();

  String hora = ntpClient.getFormattedTime();
  String data = ntpClient.getFormattedDate();

  hour   = ntpClient.getHours();
  minute = ntpClient.getMinutes();
  second = ntpClient.getSeconds();

  year = (data.substring(0, 4)).toInt();
  month = (data.substring(5, 7)).toInt();
  day = (data.substring(8, 10)).toInt();

  data_hora = String(day) + "/" + String(month) + "/" + String(year);
  data_hora += "-" + String(hour) + ":" + String(minute) + ":" + String(second);
}

void mensura()
{
  digitalWrite(pin_led, LOW);

  if (ppt != 0) {
    int valor = ppt;
    int resto = valor % 2;
    if (resto != 0) ppt ++;
  }

  chuva = chuva + (ppt * 0.125);

  p = (bme.readPressure()) / 1000;
  t = dht.getTemperature();
  h = dht.getHumidity();
  r = analogRead(pin_rad);

  r = r * (3300 / 1024);
  r = -0.0026 * r * r + 8.3299 * r - 5732;

  if (r < 0) r = 0;

  p_med   = p_med + p;
  t_med   = t_med + t;
  h_med   = h_med + h;
  rad     = rad   + r;

  if (p > p_max) p_max = p;
  if (p < p_min) p_min = p;
  if (t > t_max) t_max = t;
  if (t < t_min) t_min = t;
  if (h > h_max) h_max = h;
  if (h < h_min) h_min = h;

  wind_speed();

  float lei = (readFile("/leitura.txt")).toFloat();
  lei ++;
  writeFile(String(lei), "/leitura.txt");

  i = i + 1;

  Serial.println(data_hora);
  Serial.println("Temp: " + String(t, 2) + " ºC");
  Serial.println("UR:   " + String(h, 2) + " %");
  Serial.println("Pres: " + String(p, 2) + " kPa");
  Serial.println("VV:   " + String(v, 2) + " m/s");
  Serial.println("Rad:  " + String(r, 0) + " W/m2");
  Serial.println("Ppt:  " + String(chuva, 2) + " mm");
  Serial.println("Wifi status:  " + String(WiFi.status()));
  Serial.println("WL_Connected: " + String(WL_CONNECTED));
  Serial.println("Número erros: " + String(erro));
  Serial.println("Número loops: " + String(int(i)));
  Serial.print("IP: ");
  Serial.println(WiFi.localIP());
  Serial.println("_______________________________");

  telegram();

  ppt = 0;
  v   = 0;

  digitalWrite(pin_led, HIGH);
}

void gera_dado()
{
  p_med = p_med / i;
  t_med = t_med / i;
  h_med = h_med / i;
  rad   = rad   / i;
  vv_2m = vv_2m / i;
  chuva = chuva;

  molhamento();

  es  = 0.6108 * pow(10, ((7.5 * t_med) / (237.3 + t_med)));
  ea  = h_med * es / 100;

  double a = log10(ea / 0.611);

  tpo = (237.3 * a) / (7.5 - a);

  t_max_d = (readFile("/t_max_d.txt")).toFloat();
  t_min_d = (readFile("/t_min_d.txt")).toFloat();
  p_max_d = (readFile("/p_max_d.txt")).toFloat();
  p_min_d = (readFile("/p_min_d.txt")).toFloat();
  h_max_d = (readFile("/h_max_d.txt")).toFloat();
  h_min_d = (readFile("/h_min_d.txt")).toFloat();
  rad_d   = (readFile("/rad_d.txt"  )).toFloat();
  ppt_d   = (readFile("/ppt_d.txt"  )).toFloat();
  vv_d    = (readFile("/vv_d.txt"   )).toFloat();
  k       = (readFile("/k.txt"      )).toFloat();

  k ++;
  rad_d += rad;
  vv_d  += vv_2m;
  ppt_d += chuva;

  if (t_max_d < t_max) writeFile(String(t_max), "/t_max_d.txt");
  if (t_min_d > t_min) writeFile(String(t_min), "/t_min_d.txt");
  if (p_max_d < p_max) writeFile(String(p_max), "/p_max_d.txt");
  if (p_min_d > p_min) writeFile(String(p_min), "/p_min_d.txt");
  if (h_max_d < h_max) writeFile(String(h_max), "/h_max_d.txt");
  if (h_min_d > h_min) writeFile(String(h_min), "/h_min_d.txt");

  writeFile(String(ppt_d), "/ppt_d.txt");
  writeFile(String(rad_d), "/rad_d.txt");
  writeFile(String(vv_d ), "/vv_d.txt" );
  writeFile(String(k    ), "/k.txt"    );

  if (day != last_day) evapo();

  envia_dados();

  minu = false;

  i      = 0;
  p_med  = 0;
  t_med  = 0;
  h_med  = 0;
  rad    = 0;
  vv_2m  = 0;
  vv_max = 0;
  chuva  = 0;
  eto    = 0;
  tpo    = 0;

  p = (bme.readPressure()) / 1000;
  t = dht.getTemperature();
  h = dht.getHumidity();

  p_max = p;
  p_min = p;
  t_max = t;
  t_min = t;
  h_max = h;
  h_min = h;

  data_hora = "";
}

void envia_dados()
{
  if (client_secure.connect("docs.google.com", 443) == 1)
  {
    String toSend = textFix;
    toSend += data_hora;
    toSend += "&entry.1649831181=";
    toSend += t_max;
    toSend += "&entry.962530866=";
    toSend += t_min;
    toSend += "&entry.160641851=";
    toSend += t_med;
    toSend += "&entry.270651981=";
    toSend += h_max;
    toSend += "&entry.961586753=";
    toSend += h_min;
    toSend += "&entry.2114556470=";
    toSend += h_med;
    toSend += "&entry.783224836=";
    toSend += p_max;
    toSend += "&entry.16884545=";
    toSend += p_min;
    toSend += "&entry.1986859364=";
    toSend += p_med;
    toSend += "&entry.1797873380=";
    toSend += rad;
    toSend += "&entry.1731491394=";
    toSend += vv_2m;
    toSend += "&entry.395065476=";
    toSend += vv_max;
    toSend += "&entry.1605497456=";
    toSend += chuva;
    toSend += "&submit=Submit HTTP/1.1";

    client_secure.println(toSend);
    client_secure.println("Host: docs.google.com");
    client_secure.println();
    client_secure.stop();
    Serial.println("Dados enviados ao google");
  }

  else
  {
    Serial.println("Erro ao enviar dados ao google");
  }

  mqtt.connect();
  mqtt.processPackets(5000);

  _t_atual.publish(t_med);
  _ur_atual.publish(h_med);
  _vv_atual.publish(vv_2m);
  _r_atual.publish(rad);
  _p_atual.publish(p_med);
  _chuva_dia.publish(ppt_d);
  _vv_rajada.publish(vv_max);

  if (day != last_day)
  {
    _eto.publish(eto);
    last_day = day;
  }

  if (hour == 12 and minute == 0) {

    dpm = ((readFile("/dpm.txt")).toFloat()) / 6;

    if (dpm > 24) dpm = 24;
    _dpm.publish(dpm);

    t_dpm   = (readFile("/t_dpm.txt")).toFloat();
    h_dpm   = (readFile("/h_dpm.txt")).toFloat();
    rpt_dpm = (readFile("/rpt_dpm.txt")).toFloat();

    t_dpm /= rpt_dpm;
    h_dpm /= rpt_dpm;

    float t_critica   = 25;
    float h_critica   = 95;
    float dpm_critica = 12;

    float t_fator = t_dpm / t_critica;
    float h_fator = h_dpm / h_critica;
    float dpm_fator = dpm / dpm_critica;

    float risco = ((t_fator * 3) + (h_fator * 1) + (dpm_fator * 5)) / 9;

    msg_dpm = "A DPM foi de: " + String(dpm, 2) + " horas. ";
    msg_dpm += "Classificado com risco ";

    String reply;
    reply = "Boa tarde, a DPM foi de: " + String(dpm, 2) + " horas. ";
    reply += "O dia foi classificado com risco ";

    if (risco > 0.9) {
      reply   += "alto, ao progresso da sigatoka amarela na cultura da banana.";
      msg_dpm += "alto, ao progresso da sigatoka amarela na cultura da banana.";
    }
    if ((risco <= 0.9) and (risco >= 0.7)) {
      reply   += "médio, ao progresso da sigatoka amarela na cultura da banana.";
      msg_dpm += "médio, ao progresso da sigatoka amarela na cultura da banana.";
    }
    if (risco < 0.7) {
      reply   += "baixo, ao progresso da sigatoka amarela na cultura da banana.";
      msg_dpm += "baixo, ao progresso da sigatoka amarela na cultura da banana.";
    }

    bot.sendMessage(reply, angelo);

    writeFile(String(0), "/dpm.txt");
    writeFile(String(0), "/t_dpm.txt");
    writeFile(String(0), "/h_dpm.txt");
    writeFile(String(0), "/rpt_dpm.txt");
  }

  if (! _chuva_atual.publish(chuva)) {
    Serial.println("Falha ao enviar dados a adafruit.");
  }
  else
  {
    Serial.println("Dados enviados a adafruit");
  }

  mqtt.disconnect();
  Serial.println("_______________________________");

  tempo = millis();
}

void wind_speed()
{
  rpm = (10 * (rpm / 2)) / (10 - tempo_total);

  rpm = (rpm * 60) / (intervalo / 1000);

  v = ((4 * 3.14 * 147 * rpm) / 60) / 1000;

  if (v > vv_max) vv_max = v;

  vv_2m = vv_2m + v;
  rpm = 0;
}

void evapo()
{
  t_max_d = (readFile("/t_max_d.txt")).toFloat();
  t_min_d = (readFile("/t_min_d.txt")).toFloat();
  p_max_d = (readFile("/p_max_d.txt")).toFloat();
  p_min_d = (readFile("/p_min_d.txt")).toFloat();
  h_max_d = (readFile("/h_max_d.txt")).toFloat();
  h_min_d = (readFile("/h_min_d.txt")).toFloat();
  rad_d   = (readFile("/rad_d.txt"  )).toFloat();
  vv_d    = (readFile("/vv_d.txt"   )).toFloat();
  k       = (readFile("/k.txt"      )).toFloat();

  const float pi = 3.1415;
  const float albedo = 0.23;
  const float c_sb = 4.903 / 1000000000;

  float latitude = -0.3964;
  float altitude = 457;
  float dia_ano = (month - 1) * 30 + day;

  rad_d = 1.3 * 600 * rad_d / 1000000;
  //rad_d = 1.3 * rad_d / (k * 11.6);

  t_med_d = (t_max_d + t_min_d) / 2;
  p_med_d = (p_max_d + p_min_d) / 2;

  vv_d /= k;

  float t_max_k = t_max_d + 273.16;
  float t_min_k = t_min_d + 273.16;

  float c_psi = 0.000665 * p_med_d;
  float e0_tmax = 0.6108 * exp((17.27 * t_max_d) / (t_max_d + 237.3));
  float e0_tmin = 0.6108 * exp((17.27 * t_min_d) / (t_min_d + 237.3));
  float e0_tmed = 0.6108 * exp((17.27 * t_med_d) / (t_med_d + 237.3));
  float es = (e0_tmax + e0_tmin) / 2;
  float ea = (e0_tmin * (h_max_d / 100) + e0_tmax * (h_min_d / 100)) / 2;
  float delta = (4098 * e0_tmed) / sq(t_med_d + 237.3);
  float dr = 1 + 0.033 * cos((2 * pi / 365) * dia_ano);
  float dec_sol = 0.4093 * sin(((2 * pi / 365) * dia_ano) - 1.405);
  float w_sol = acos((-tan(latitude)) * (tan(dec_sol)));
  float ra = 37.586 * dr * (w_sol * sin(latitude) * sin(dec_sol) + cos(latitude) * cos(dec_sol) * sin(w_sol));
  float rso = (0.75 + (2 / 100000) * altitude) * ra;
  float roc = (1 - albedo) * rad_d;
  float rol = -c_sb * ((pow(t_max_k, 4) + pow(t_min_k, 4)) / 2) * (0.34 - 0.14 * sqrt(ea)) * (1.35 * (rad_d / rso) - 0.35);
  float rn = roc + rol;
  float g = 0;

  eto = (0.408 * delta * (rn - g) + c_psi * (900 / (t_med_d + 273.3)) * vv_d * (es - ea)) / (delta + c_psi * (1 + 0.34 * vv_d));
  //eto = (0.408 * delta * (rn - g) + c_psi * (37 / (t_med_d + 273.3)) * vv_d * (es - ea)) / (delta + c_psi * (1 + 0.34 * vv_d));
  //eto = (0.408 * delta * (rn - g) + c_psi * (6.2 / (t_med_d + 273.3)) * vv_d * (es - ea)) / (delta + c_psi * (1 + 0.34 * vv_d));

  Serial.println();
  Serial.println("A evapotranspiração foi: " + String(eto, 2) + " mm");
  Serial.println();

  if (eto < 0) eto = 0;

  dpm     = (readFile("/dpm.txt")).toFloat();
  t_dpm   = (readFile("/t_dpm.txt")).toFloat();
  h_dpm   = (readFile("/h_dpm.txt")).toFloat();
  rpt_dpm = (readFile("/rpt_dpm.txt")).toFloat();

  inicia_arquivos();

  writeFile(String(dpm), "/dpm.txt");
  writeFile(String(t_dpm), "/t_dpm.txt");
  writeFile(String(h_dpm), "/h_dpm.txt");
  writeFile(String(rpt_dpm), "/rpt_dpm.txt");

  String reply;
  reply = "Boa noite, a evapotranspiração foi " + String(eto, 2) + " mm";
  bot.sendMessage(reply, angelo);

  msg_eto = "A evapotranspiração foi " + String(eto, 2) + " mm";
}

String readFile(String arquivo) {
  File rFile = SPIFFS.open(arquivo, "r");

  conteudo = rFile.readStringUntil('\r'); //desconsidera '\r\n'

  return conteudo;
  rFile.close();
}

void writeFile(String valor, String arquivo) {

  File rFile = SPIFFS.open(arquivo, "w+");
  rFile.println(valor);
  rFile.close();
}

void inicia_arquivos()
{
  p = (bme.readPressure()) / 1000;
  t = dht.getTemperature();
  h = dht.getHumidity();

  SPIFFS.format();

  writeFile(String(0), "/leitura.txt");
  writeFile(String(t), "/t_max_d.txt");
  writeFile(String(t), "/t_min_d.txt");
  writeFile(String(p), "/p_max_d.txt");
  writeFile(String(p), "/p_min_d.txt");
  writeFile(String(h), "/h_max_d.txt");
  writeFile(String(h), "/h_min_d.txt");
  writeFile(String(0), "/rad_d.txt");
  writeFile(String(0), "/ppt_d.txt");
  writeFile(String(0), "/vv_d.txt");
  writeFile(String(0), "/erro.txt");
  writeFile(String(0), "/dpm.txt");
  writeFile(String(0), "/k.txt");

  writeFile(String(0), "/t_dpm.txt");
  writeFile(String(0), "/h_dpm.txt");
  writeFile(String(0), "/rpt_dpm.txt");
}

void bluetooth()
{
  msg = Serial.readStringUntil('*');

  if (msg.equalsIgnoreCase("reboot"))
  {
    Serial.println("Reiniciando controlador...");
    //ESP.restart();
  }

  if (msg.equalsIgnoreCase("status"))
  {
    t_max_d = (readFile("/t_max_d.txt")).toFloat();
    t_min_d = (readFile("/t_min_d.txt")).toFloat();
    p_max_d = (readFile("/p_max_d.txt")).toFloat();
    p_min_d = (readFile("/p_min_d.txt")).toFloat();
    h_max_d = (readFile("/h_max_d.txt")).toFloat();
    h_min_d = (readFile("/h_min_d.txt")).toFloat();
    rad_d   = (readFile("/rad_d.txt"  )).toFloat();
    ppt_d   = (readFile("/ppt_d.txt"  )).toFloat();
    vv_d    = (readFile("/vv_d.txt"   )).toFloat();
    dpm     = (readFile("/dpm.txt"    )).toFloat();
    k       = (readFile("/k.txt"      )).toFloat();

    Serial.println("T max: " + String(t_max_d) + " ºC");
    Serial.println("T min: " + String(t_min_d) + " ºC");
    Serial.println("P max: " + String(p_max_d) + " hPa");
    Serial.println("P min: " + String(p_min_d) + " hPa");
    Serial.println("U max: " + String(h_max_d) + " %");
    Serial.println("U min: " + String(h_min_d) + " %");
    Serial.println("Rad: "   + String(1.3 * rad_d / (k * 11.6))   + " MJ/m2");
    Serial.println("VV x: "  + String(vv_d / k)  + " m/s");
    Serial.println("PPT : "  + String(ppt_d)     + " mm / dia");
    Serial.println("DPM : "  + String(dpm / 6)   + " horas");
    Serial.println("K: "     + String(k) + " leituras");
    Serial.println("_______________________________");
  }

  if (msg.equalsIgnoreCase("reset"))
  {
    inicia_arquivos();
    Serial.println("Arquivos resetados!");
    Serial.println("_______________________________");
  }
  if (msg.equalsIgnoreCase("bme"))
  {
    Serial.println("Temp: " + String(bme.readTemperature()) + " ºC");
    Serial.println("UR: " + String(bme.readHumidity()) + " %");
    Serial.println("Press: " + String((bme.readPressure()) / 1000) + " kPa");
    Serial.println("_______________________________");
  }
  if (msg.equalsIgnoreCase("tpo"))
  {
    t = dht.getTemperature();
    h = dht.getHumidity();

    es  = 0.6108 * pow(10, ((7.5 * t) / (237.3 + t)));
    ea  = h * es / 100;

    double a = log10(ea / 0.611);

    tpo = (237.3 * a) / (7.5 - a);

    Serial.println("es: "  + String(es));
    Serial.println("ea: "  + String(ea));
    Serial.println("log: " + String(a));

    Serial.println("Temp: " + String(t)   + " ºC");
    Serial.println("T_po: " + String(tpo) + " ºC");
    Serial.println("UR: "   + String(h)   + " %");
    Serial.println("_______________________________");
  }
  if (msg.equalsIgnoreCase("/io"))
  {
    Serial.println("Enviando dados...");
    gera_dado();
  }
}

void molhamento() {

  acr = 0;

  if (chuva > 0) {
    acr = 1;
    choveu = true;
  }
  else if (choveu == true) {
    acr = 1;
    choveu = false;
  }
  else {

    float d_     = 0.07;       // área da folha artificial, em m2
    float zc_    = 3;          // altura da cultura, em m
    float rn_    = rad - 25;   // W / m2 / s        (-35)
    float t_     = t_med;      // C
    float ur_    = h_med;      // %
    float vv_    = vv_2m;      // m/s
    float ppt_   = chuva;      // mm
    float es_    = 0;          // kPa
    float ea_    = 0;          // kPa
    float delta_ = 0;          // kPa / C
    float rb_    = 0;
    float ra_    = 0;
    float vv_f_  = 0;
    float LE_    = 0;

    es_     = 0.6108 * pow(10, ((7.5 * t_) / (237.3 + t_)));
    ea_     = ur_ * es_ / 100;
    delta_  = (4098 * es_) / sq(t_ + 237.3);
    rb_     = (307 * sqrt(d_ / vv_)) / 2;
    vv_f_   = (0.4 * vv_) / log((2 - 0.65 * zc_) / (0.13 * zc_));
    ra_     = log((2 - 0.65 * zc_) / (0.13 * zc_)) / (0.4 * vv_f_);

    float a_ = -(delta_ * rn_ + (1200 * (es_ - ea_) / (ra_ + rb_)));
    float b_ = delta_ * 0.64;

    LE_ = a_ / b_;

    if (LE_ > 0) {
      acr = 1;
    }
  }

  if (acr > 0) {
    dpm = (readFile("/dpm.txt")).toFloat();
    dpm = dpm + acr;

    writeFile(String(dpm), "/dpm.txt");

    t_dpm   = (readFile("/t_dpm.txt")).toFloat();
    h_dpm   = (readFile("/h_dpm.txt")).toFloat();
    rpt_dpm = (readFile("/rpt_dpm.txt")).toFloat();

    t_dpm = t_dpm + t_med;
    h_dpm = h_dpm + h_med;
    rpt_dpm ++;

    writeFile(String(t_dpm), "/t_dpm.txt");
    writeFile(String(h_dpm), "/h_dpm.txt");
    writeFile(String(rpt_dpm), "/rpt_dpm.txt");
  }

  String txt = "";

  if (acr > 0) {
    txt = "Houve molhamento foliar!";
  }
  else {
    txt = "Não houve molhamento foliar!";
  }
  Serial.println(txt);
  Serial.println("_______________________________");
}

void telegram() {

  float time_loop = millis();

  bot.tick();

  tempo_total = (millis() - time_loop) / 1000;
  Serial.println("Tempo de loop: " + String(tempo_total, 2) + " s");
  Serial.println("_______________________________");
}
