//Progetto realizzato da Andrea Beghin
//Stazione_fulmini_Esp8266_v1.2
//https://www.andreabeghin.it/

#include <SPI.h>                  //per il traferimento dei dati via SPI
#include <AS3935.h>               //per gestire il sensore AS3935
#include <ESP8266WiFi.h>          //per gestire WifiClientSecure (collegamento a www.nome_sito.it)
#include <WiFiClient.h>           //per gestire la connessione alla rete Wifi
#include "SafeString.h"           //per gestire le stringhe

//dati per la connessione alla rete Wifi                  
const char* MY_SSID = "nome_rete_wifi";                    
const char* MY_PWD = "password_rete_wifi";

//dati per la connessione ad www.nome_sito.it
const char* host = "www.nome_sito.it";
const uint16_t port = 443;  

//dichiarazione variabili
createSafeString(urlvariabile, 200);                //oggetto SafeString di lunghezza 200 caratteri
createSafeString(urlcaricamento, 250);              //oggetto SafeString di lunghezza 250 caratteri

//dati sensore fulmini AS3935
int valore_calibrazione;              //valore calibrazione
void printAS3935Registers();          //funzione che rileva e stampa i parametri del sensore (rumore di fondo, spike rejection, soglia di controllo)
byte SPItransfer(byte sendByte);      //funzione che si occupa del traferimento dei dati via SPI
void AS3935Irq();                     //funzione che verifica se ci sono disturbi o fulmini e causa l'interrupt
                                                      
AS3935 AS3935(SPItransfer,D2,D1);     //primo parametro: funzione per il trasferimento dei dati via SPI     
                                      //secondo parametro: pin CS collegato alla scheda
                                      //terzo parametro: pin IRQ collegato alla scheda

//variabili per i tempi di ciclo per l'invio dei dati
unsigned long tempo_start_invio_dati;
unsigned long intervallo_invio_dati;  

//variabili rilevamento sensore
float numero_fulmini;           //numero fulmini rilevati 
float distanza_fulmini;         //distanza fulmini
float disturbi_rilevati;        //numero disturbi rilevati


void setup()
{
  //inizializzazione delle variabili rilevamento sensore
  numero_fulmini = 0;           //numero fulmini rilevati 
  distanza_fulmini = 0;         //distanza fulmini
  disturbi_rilevati = 0;        //numero disturbi rilevati  

  //settaggio dei tempi di ciclo per l'invio dei dati
  tempo_start_invio_dati = millis();
  intervallo_invio_dati = 600000;      //effettuiamo l'invio dei dati ogni 600 secondi (10 minuti) 

  //connessione Wifi
  connectWifi();
  
  //setup sensore fulmini AS3935
  SPI.begin();
  SPI.setDataMode(SPI_MODE1);
  SPI.setClockDivider(SPI_CLOCK_DIV16);
  SPI.setBitOrder(MSBFIRST);
  AS3935.reset();                             //ripristina tutti i valori di registro interni ai valori predefiniti
  delay(100);
  AS3935.setOutdoors();                       //setta il sensore per il funzionamento all'esterno
  AS3935.registerWrite(AS3935_NF_LEV,2);      //scrive 2 nel Noise Level register 
  
  valore_calibrazione=AS3935.registerRead(AS3935_TUN_CAP);        //il range è compreso tra 0 e 15

  AS3935.enableDisturbers();      //attiva la rilevazione dei disturbi, è possibile disattivare questa funzione con disableDisturbers()
  printAS3935Registers();         //rileva e stampa i parametri del sensore (rumore di fondo, spike rejection, soglia di controllo)
  
  attachInterrupt(digitalPinToInterrupt(D1), AS3935Irq, RISING);  
  //usare interrupt significa che non serve controllare lo stato del pin continuamente, lo fa il chip da solo
}


void loop()
{ 

  if ((millis()-tempo_start_invio_dati) > intervallo_invio_dati){

    tempo_start_invio_dati = millis();
    
    //collegamento all'host www.nome_sito.it
    WiFiClientSecure client;
    client.setInsecure();       //non si utilizzano certificati di sicurezza

    //verifica se il collegamento non è andato a buon fine
    if (!client.connect(host, port)) {
      delay(5000);
      return;
    }

    //se la connessione all'host www.nome_sito.it è avvenuta 
    if (client.connected()) {

      if (numero_fulmini != 0) {          //verifica se numero_fulmini è diverso da 0 per non effettuare una divisione per 0
        distanza_fulmini = distanza_fulmini / numero_fulmini;
      } else {
        distanza_fulmini = 0;
      }

      urlvariabile = "numero_fulmini=";
      urlvariabile += numero_fulmini;
      urlvariabile += "&distanza_fulmini=";
      urlvariabile += distanza_fulmini;
      urlvariabile += "&disturbi_rilevati=";
      urlvariabile += disturbi_rilevati;
  
      urlcaricamento = "GET /aggiungi_fulmini.php?"; 
      urlcaricamento += urlvariabile;
      urlcaricamento += " HTTP/1.1";

      //invio url all'host www.nome_sito.it per il salvataggio dei dati sul database mysql
      client.println(urlcaricamento);
      client.println("Host: www.nome_sito.it");
      client.println("Access-Control-Allow-Origin: *");
      client.println("Connection: close");
      client.println();
      
      delay(500);             //delay fondamentale altrimenti a volte chiude la connessione prima che la pagina sia stata correttamente interrogata
     
      client.stop();
    }
    
    //azzeramento delle variabili per il prossimo ciclo di rilevamento
    numero_fulmini=0;         
    distanza_fulmini=0;
    disturbi_rilevati=0;

  }
}


void printAS3935Registers()
{
  int noiseFloor = AS3935.getNoiseFloor();
  int spikeRejection = AS3935.getSpikeRejection();
  int watchdogThreshold = AS3935.getWatchdogThreshold();
}


byte SPItransfer(byte sendByte)
{
  return SPI.transfer(sendByte);
}


ICACHE_RAM_ATTR void AS3935Irq()                    
{
  //appena leggiamo l'interrupt, il pin IRQ diventa LOW
  int irqSource = AS3935.interruptSource();   //restituisce bit 0: livello rumore troppo alto
                                              //            bit 2: rilevato disturbo
                                              //            bit 3: rilevato fulmine

  if (irqSource & 0b0100){                    //rilevato disturbo 
    disturbi_rilevati=disturbi_rilevati+1;    //aumenta di 1 il contatore dei disturbi rilevati
  }  
    
  if (irqSource & 0b1000){                    //rilevato fulmine
    int distanza_fulmine = AS3935.lightningDistanceKm();    //determina la distanza del fulmine in km
      
    if (distanza_fulmine < 41 && distanza_fulmine > 0)      //40 km è la distanza di rilevamento massima
    {
      numero_fulmini= numero_fulmini+1;                     //aumenta di 1 il contatore dei fulmini rilevati
      distanza_fulmini=distanza_fulmini+distanza_fulmine;   //somma tutte le distanze dei fulmini rilevati per fare al termine del ciclo una media
    }
  }
}


//funzione per la connessione alla rete wifi
void connectWifi()
{
  WiFi.begin(MY_SSID, MY_PWD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
  }
}    