//DANIELE SANTINI
//PROGRAMMA PER IL PROGETTO DI IRRIGAZIONE AUTOMATICA

/**  Richiamo le librerie necessarie  **/
#include <Wire.h>  //Includo la ibreria per il collegamento seriale I2C (necessario per il modulo Real Time Clock)
#include "RTClib.h"  //Liberia per gestire il Real Time Clock
#include <LiquidCrystal.h>  //Libreria per gestire lo schermo LCD
#include "LowPower.h"  //Libreria per gestire la modalità sleep (risparmio energia)

/**  Creo le variabili di funzionamento  **/
#define sensoreUmidita A5  //Pin del sensore di umidità del terreno
#define elettrovalvola 6  //Pin di collegamento verso la valvola (comandata tramite il circuito Arduino -> Transistor -> Relè -> Elettrovalvola)
#define LED 13
LiquidCrystal lcd(12,11,10,9,8,7);  //Pin di collegamento del LCD
RTC_DS1307 RTC;

/**  Creo le variabili globali per il programma  **/
int giorno, mese, anno, ore, minuti, secondi;
int umidita=0, sogliaUmidita=50, oraInizio=0, oraFine=5;
boolean rispEn=false;


void setup () {
  /**  Avvio la seriale, il collegamento I2C con il modulo Real Time Clock e l'LCD  **/
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  controlloRTC();
  RTC.sqw(0);
  lcd.begin(16,2);
  pinMode(elettrovalvola,OUTPUT);
  pinMode(LED,OUTPUT);

  /*Il programma parte con la modalità risparmio energia abilitata
   *Nella modalità risparmio energia disabilito la seriale, quindi non posso comunicare con la scheda via seriale
   *Quindi creo un periodo di 5 secondi all'avvio in cui è possibile disabilitare la mod. risparmio energia inviando "r" via seriale
   *Altrimenti continua con la mod. risparmio energetico e spegne la seriale
   */
  lcd.print("AVVIO...");
  delay(5000);
  controlloSeriale();
  lcd.setCursor(0,1);
  lcd.print("CALIBRAZIONE...");
}


void loop () {
  controlloRTC();
  if(! rispEn) controlloSeriale();
  tempo();
  stampaLCD();
  mediaUmidita();
  if(! rispEn) stampaSeriale();
    lcd.clear();
  lcd.setCursor(0,1);
  if(umidita<sogliaUmidita && ore>oraInizio && ore<oraFine){
    digitalWrite(elettrovalvola,HIGH);
    lcd.print("IRRIGANDO (");
    lcd.print(umidita);
    lcd.print("%)  ");
  }
  else{
    digitalWrite(elettrovalvola,LOW);
    lcd.print("UMIDITA': ");
    lcd.print(umidita);
    lcd.print("%   ");
  }
}


void controlloRTC(){  //Funzione che controlla se il modulo Real Time Clock funziona correttamente
  while (! RTC.isrunning()) {
    lcd.setCursor(0,0);
    lcd.print("RTC NON FUNZIONA");
    delay(2000);
    if(! rispEn) controlloSeriale();
  }
}


void controlloSeriale(){  //Funzione che controlla se è arrivato qualcosa via Seriale; in caso affermativo, esegue l'azione corrispondente al comando inviato
  if(Serial.available()>0){
    int y=Serial.read(), buf=Serial.available(), a[buf];
    for(int x=0; x<buf; x++) a[x]=Serial.read();
    switch(y){
      /* COMANDI INVIABILI VIA SERIALE:
       * q = Resetta il tempo al tempo nel momento in cui abbiamo caricato il programma dal PC l'ultima volta
       * w (seguito da un numero da 1 a 100) = Reimposta la percentuale di umidità sotto cui si apre la valvola al valore inviato
       * e = Stampa via seriale il valore attuale di umidità e la percentuale di umidità sotto cui si apre la valvola
       * r = Abilita/Disabilita la modalità risparmio energia
       * t (seguito da un numero da 1 a 24) = Reimposta l'ora di inizio della fascia di tempo in cui irrigare
       * y (seguito da un numero da 1 a 24) = Reimposta l'ora finale della fascia di tempo in cui irrigare
       */
      case(113):  //113 ASCII = q
      RTC.adjust(DateTime(__DATE__, __TIME__));
      Serial.println("ORARIO REIMPOSTATO");
      break;

      case(119):  //119 ASCII = w
      if(buf==1) sogliaUmidita= a[0]-48;  //48 ASCII = 0
      if(buf==2) sogliaUmidita= (a[0]-48)*10 + a[1]-48;
      if(buf>=3) sogliaUmidita= 100;
      Serial.print("NUOVA SOGLIA UMIDITA': ");
      Serial.print(sogliaUmidita);
      Serial.println("%");
      break;

      case(101):  //101 ASCII = e
      Serial.print("SOGLIA UMIDITA': ");
      Serial.print(sogliaUmidita);
      Serial.print("% - UMIDITA' ATTUALE: ");
      Serial.print(umidita);
      Serial.println("%");
      break;

      case(114): //114 ASCII = r
      rispEn=!rispEn;
      if(rispEn){
        Serial.println("SLEEP ABILITATO");
        delay(50);
        Serial.end();
      }
      else Serial.println("SLEEP DISABILITATO");
      break;

      case(116):  //116 ASCII = t
      if(buf==1) oraInizio= a[0]-48;
      if(buf==2) oraInizio= (a[0]-48)*10 + a[1]-48;
      break;

      case(121):  //121 ASCII = y
      if(buf==0) Serial.print("ERRORE, DEVI INSERIRE UN VALORE");
      if(buf==1) oraFine= a[0]-48;
      if(buf==2) oraFine= (a[0]-48)*10 + a[1]-48;
      break;

    default:	
      Serial.print("COMANDO SCONOSCIUTO (ASCII ");
      Serial.print(y);
      Serial.println(")");
    }
  }
}


void tempo(){  //Funzione che ricava data e ora dal modulo Real Time Clock
  DateTime now = RTC.now();
  giorno=now.day();
  mese=now.month();
  anno=now.year();
  ore=now.hour();
  minuti=now.minute();
  secondi=now.second();
}


void mediaUmidita(){  //Funzione che quando richiamata fa due misurazioni della umidita a 8 secondi di distanza e fa la media
  int umidita1=analogRead(sensoreUmidita);
  dormi();
  int umidita2=analogRead(sensoreUmidita);
  dormi();
  int umidita3=analogRead(sensoreUmidita);
  umidita=(umidita1+umidita2+umidita3)/3;
  umidita=map(umidita,0,512,0,100);  //Trasformo la media in un valore percentuale
}


void stampaSeriale(){  //Funzione che stampa via seriale data e ora ottenute con la funzione 'tempo' e umidità
  Serial.print(giorno);
  Serial.print("/");
  Serial.print(mese);
  Serial.print("/");
  Serial.print(anno);
  Serial.print(" ");
  Serial.print(ore);
  Serial.print(":");
  if(minuti<10) Serial.print("0");
  Serial.print(minuti);
  Serial.print(":");
  if(secondi<10) Serial.print("0");
  Serial.print(secondi);
  Serial.print(" - ");
  Serial.print(umidita);
  Serial.println("%");
}


void stampaLCD(){  //Funzione che stampa la prima riga sul display LCD (data e ora ottenute con la funzione 'tempo'), alla seconda provvederemo nella funzione principale
  lcd.setCursor(0,0);
  lcd.print(giorno);
  lcd.print('/');
  lcd.print(mese);
  lcd.print('/');
  lcd.print(anno);
  lcd.print(' ');
  lcd.print(ore);
  lcd.print(':');
  if(minuti<10) lcd.print("0");
  lcd.print(minuti);
}


void dormi(){  //Funzione che porta l'Arduino in modalità sleep o in delay ogni volta che viene richiamato 
  digitalWrite(LED,LOW);
  if(rispEn) {  //Se la mod. risparmio energia è abilitata porta la scheda in modalità sleep
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
  }
  else{  //Se la mod. risparmio energia è disabilitata crea solo un delay di 5 secondi
    lcd.setCursor(15,0);
    lcd.print("#");
    delay(5000);
  }
  digitalWrite(LED,HIGH);
}





