#include <NTPClient.h>  //libreria necessaria per ottenere data e ora da un Server NTP
#include <WiFiUdp.h>    //libreria per utilizzare il protocollo UDP  sulla porta 123 del Server NTP
#include <ESP8266WebServer.h>
#include <DHT.h>      //libreria necessaria per utilizzare il sensore DHT11
#define sensorePin D1 // pin di ESP8266 NodeMCU collegato all'uscita (pin OUT) del sensore DHT1
#define tipoDHT DHT11 
/* definisce il tipo di sensore della famiglia DHT:  in questo caso viene selezionato DHT11 
* ma esistono sono altri sensori quali DHT21 e DHT22 
*/
DHT dht(sensorePin,tipoDHT);  //Istanzia l'oggetto dht della classe DHT    
// Configurazione WiFI: impostazione delle credenziali di rete
const char* ssid = "XXXXXXXX";        //Inserire qui l'SSID
const char* password = "yyyyyyyy"; //Inserire qui la password WiFi
/* Configurazione IP statico/fisso della scheda ESP8266. Occorre utilizzare un indirizzo IP disponibile 
 * nella rete locale, il gateway corrispondente e la subnet mask
 * Qui, ad esempio ho utilizzato l'IP 192.168.1.200
*/
IPAddress IP_ESP8266(192, 168, 1, 200);
IPAddress IP_gateway(192, 168, 1, 1);
IPAddress subnet_mask(255, 255, 0, 0);
//
ESP8266WebServer server(80);
/* Dichiara l'oggetto server della libreria ESP8266WebServer. Il costruttore di questo oggetto prende come  
 * parametro la porta  80 (predefinita per HTTP) dove il server si pone in ascolto
 */
WiFiUDP ntpUDP;   //Istanzia l'oggetto ntpUDP della classe WiFiUDP   
NTPClient timeClient(ntpUDP, "pool.ntp.org");// Definisce l'oggetto timeClient per recuperare data e ora dal Server NTP
float t;          //temperatura
float h;          //umidità    
String dataora;   //data e ora della misura del sensore
//Array dei mesi per scrivere la data nel formato gg mese aa es 7 maggio 2021 
String mesi[12]={"gennaio", "febbraio", "marzo", "aprile", "maggio", "giugno", "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"};
//
//
void setup() 
{
    // apre una connessione seriale. A scopo di debug inviamo alcuni messaggi al monitor seriale  
 
    pinMode(sensorePin, INPUT); 
    dht.begin(); //inizializza l'oggetto dht
    Serial.begin(115200);
    delay(1000);
    Serial.println(ssid);
    //con il metodo WiFi.config() configura la scheda ESP8266 conl'IP statico sopra impostato
    if (!WiFi.config(IP_ESP8266, IP_gateway, subnet_mask)) 
    {
        Serial.println("Errore nella configurazione");
    }
    WiFi.begin(ssid, password);//Inizializza le impostazioni di rete della libreria WiFi
    delay(1000);
    Serial.println(WiFi.status());
    while (WiFi.status()!= WL_CONNECTED) 
    {
        delay(500);
        Serial.print(".");
    }
    Serial.println("");
    Serial.println("Connesso alla rete WIFI");
    Serial.println(IP_ESP8266);
    /*
     * Per gestire le richieste HTTP in arrivo, dobbiamo specificare quale codice eseguire quando viene 
     * raggiunto un determinato URL. Per fare ciò, usiamo il metodo on. Questo metodo accetta due parametri. 
     * Il primo è un percorso URL e il secondo è il nome della funzione che vogliamo eseguire quando viene raggiunto quell'URL.
     */
    server.begin(); // inizializzazione del Server Web. Comincia ad "ascoltare" le richieste HTTP
    delay(200); 
    Serial.println("Web Server HTTP in funzione");
    server.on("/", handle_OnConnect);
    /*
     * quando l'oggetto server riceve una richiesta HTTP sul percorso root ( / ) viene eseguita la funzione
     * handle_OnConnect (potremmo chiamarla anche in altro modo)
     */ 
    server.onNotFound(handle_NotFound);
    timeClient.begin();// inizializzazione dell'NTPClient timeClient
    timeClient.setTimeOffset(7200); //7200 secondi 
    //l'offset tiene conto della differenza oraria dell'Italia rispetto ad UTC (2 ore) quando in Italia vige l'ora legale
 }
//
//
void loop() 
{
    /*
     * recupero data e ora dal server NTP. A volte l'NTPClient recupera la data "1 gennaio1970"
     * forzando l'aggiornamento questo non accade
     */
    while(!timeClient.update()) 
    {
      timeClient.forceUpdate();
 
    }
  server.handleClient(); // rimane in ascolto sulla porta 80 per le richieste dei clients  
  delay(1000);
}
//
//
void handle_OnConnect() 
{
    // faccio 3 letture in modo che i valori letti dal sensore, che non è velocissimo, si stabilizzino 
    for(int i=0;i<3;i++)
    { 
        h = dht.readHumidity();     // Lettura dell'umidità  
        t = dht.readTemperature();  // Lettura della temperatura in gradi Celsius 
        delay(200);
    } 
    String tt=timeClient.getFormattedTime();
    unsigned long epoch = timeClient.getEpochTime();
    //dal valore di epoch si ricavano giorno, mese ed anno
    struct tm *ptm = gmtime ((time_t *)&epoch); 
    int gg = ptm->tm_mday;
    int mm = ptm->tm_mon+1;
    String mese=mesi[mm-1];
    int aa = ptm->tm_year+1900;
    dataora = "Misura del "+String(gg) + " " + mese + " " + String(aa)+"  "+tt;
    if (isnan(h) || isnan(t))  //Verifica se  si presenta un errore di lettura   
    {  
          Serial.println("Errore di lettura...");  
          h=0.0;
          t=0.0;
    }    
    String s="Umidità= "+String(h)+"     Temperatura="+String(t);
    Serial.println(dataora);
    Serial.println(s);
    server.send(200, "text/html", SendHTML(t,h,dataora));  
    //invia  lo stato 200, cioè l'ok, e una pagina Web, costruita nella funzione SendHTML(), al client/browser 
}
 
void handle_NotFound(){
  server.send(404, "text/plain", "Non trovato!!");
   //invia lo stato 404, cioè l'errore "not found", e un semplice messaggio di errore al client/browser 
} 
 
/*
 * risposta al client/browser con il codice HTML che costruisce la pagina web per visualizzare 
 * data e ora della misura, temperatura ed umidità rilevate dal sensore
 */
String SendHTML(float temperatura,float umidita,String dataoramisura)
{
  String s = "<!DOCTYPE html> <html>\n";
  s +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
  s +="<title>Server Web ESP8266 NodeMCU</title>\n";
  s +="<style>html {text-align: center;background-color:#fffff0}\n";
  s +="h2 {color: #000080;margin-top:30px;}\n";
  s +="p {font-size: 24px;margin-bottom: 10px;}\n";
  s +="</style>\n";
  s +="</head>\n";
  s +="<body>\n";
  s +="<h2>ESP8266 NodeMCU<br/>Server Web</h2><br/>\n";
  s+=dataoramisura;
  s +="<p>Temperatura: ";
  s+=temperatura;
  s+=" gradi</p>";
  s +="<p>Umidit&agrave;: ";
  s+=umidita;
  s +="%</p>";
  s +="</body>\n";
  s +="</html>\n";
  return s;
}