#include <Wire.h>
#include <RTClib.h>


RTC_DS1307 RTC;

boolean debug=true;
int ledA = 10; //Sortie PWM n°1
int ledJ = 11; //Sortie PWM n°2
int pMaxA = 127; //Puissance max de la rampe qui fait l'aube et l'Aurore entre 0 et 255
int pMaxJ = 127; //Puissance max de la rampe qui fait le jour maxi entre 0 et 255
int aube = 20; //Durée de l'aube en minutes
int crepuscule = 20; //Durée de l'aurore en minutes
uint8_t heureAllumageSemaine=13;
uint8_t minuteAllumageSemaine=0;
uint8_t heureExtinctionSemaine=22;
uint8_t minuteExtinctionSemaine=0;
uint8_t heureAllumageWE=10;
uint8_t minuteAllumageWE=0;
uint8_t heureExtinctionWE=22;
uint8_t minuteExtinctionWE=0;
DateTime horraires[7]; //tableau qui contient l'horraire des changement d'état du jour. Mis à jor par fonction Horraires
long pas[3];//tableau contenant les pas d'incrémentation. Mis à jour par fonction horraires
byte etat;
int niveauA;
int niveauJ;
long lastLoop;
long lastDebug;

void convert(const DateTime& now) {
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
}  

void Horraires(const DateTime& date) {
  //y=date.year();
  uint8_t  heureAllumage;
  uint8_t minuteAllumage;
  uint8_t heureExtinction;
  uint8_t minuteExtinction;
  if (date.dayOfWeek()<6 && date.dayOfWeek()>0) {
    heureAllumage=heureAllumageSemaine;
    minuteAllumage=minuteAllumageSemaine;
    heureExtinction=heureExtinctionSemaine;
    minuteExtinction=minuteExtinctionSemaine;
  }
  else {
    heureAllumage=heureAllumageWE;
    minuteAllumage=minuteAllumageWE;
    heureExtinction=heureExtinctionWE;
    minuteExtinction=minuteExtinctionWE;
  }
  horraires[0]=DateTime(date.year(),date.month(),date.day(),0,0,0); //borne 0 le jour à minuit
  horraires[6]=horraires[0].get()+86400L; // borne 6 24h après
  horraires[1]=DateTime(date.year(),date.month(),date.day(),heureAllumage,minuteAllumage,0); //borne 1 Levé du jour réglé par utilisateur
  horraires[2]=horraires[1].get()+aube*60L; // borne 2 levée du jour + temps aube réglé par utilisateur
  horraires[5]=DateTime(date.year(),date.month(),date.day(),heureExtinction,minuteExtinction,0); //borne 5 heure d'extinction réglé par utilisateur
  horraires[4]=horraires[5].get()-crepuscule*60L; //borne 4 Début du crepuscule (extinction réglé moins durée réglée
  horraires[3]=horraires[2].get()+(horraires[4].get()-horraires[2].get())/2; //borne 3 milieu du jour.Fin de la montée lente du jour et début descente lente
  
  pas[0]=(float(aube)*60/pMaxA)*1000;
  pas[1]=(float(horraires[4].get()-horraires[2].get())/float(pMaxJ*2))*1000;
  pas[2]=(float(crepuscule)*60/pMaxA)*1000;
  
  if (debug==true) {
    Serial.print("Now : ");
    Serial.print(date.get());
    Serial.print(" soit :");
    convert(date.get());
    Serial.print("\n");
    Serial.print("Jour n°");
    Serial.print(date.dayOfWeek());
    Serial.print("\n");
    for (int i=0;i<=6;i++) {
      Serial.print("horraires");
      Serial.print(i);
      Serial.print(" : ");
      Serial.print(horraires[i].get());
      Serial.print(" soit : ");
      convert(horraires[i]);
      Serial.print("\n");
    }
    
    for (int i=0;i<=2;i++) {
      Serial.print("Pas");
      Serial.print(i);
      Serial.print(" :");
      Serial.print(pas[i]);
      Serial.print("\n");
    }
    Serial.print("\n");
}
}

void Etat(const DateTime& date) {
  
  if (date.get()>=horraires[0].get() && date.get()<horraires[1].get()) {
    etat=0;
    niveauA=0;
    niveauJ=0;
  }
  else if (date.get()>=horraires[1].get() && date.get()<horraires[2].get()) {
    etat=1;
    niveauA=(date.get()-horraires[1].get())/aube;
    niveauJ=0;
  }
  else if (date.get()>=horraires[2].get() && date.get()<horraires[3].get()) {
    etat=2;
    niveauA=pMaxA;
    niveauJ=int((float((date.get()-horraires[2].get()))/float((horraires[3].get()-horraires[2].get())))*float(pMaxJ));
  }
  else if (date.get()>=horraires[3].get() && date.get()<horraires[4].get()) {
    etat=3;
    niveauA=pMaxA;
    niveauJ=int((float((horraires[4].get()-date.get()))/float((horraires[4].get()-horraires[3].get())))*float(pMaxJ));
  }
  else if (date.get()>=horraires[4].get() && date.get()<horraires[5].get()) {
    etat=4;
    niveauJ=0;
    niveauA=(date.get()-horraires[5].get())/crepuscule;
  }
  else if (date.get()>=horraires[5].get() && date.get()<horraires[6].get()) {
    etat=5;
    niveauJ=0;
    niveauA=0;
  }
  if (debug==true) {
    Serial.print("Etat : ");
    Serial.print(etat);
    Serial.print("\n");
    Serial.print("NiveauA : ");
    Serial.print(niveauA);
    Serial.print("\n");
    Serial.print("NiveauJ : ");
    Serial.print(niveauJ);
    Serial.print("\n\n");
  }
}


void setup () {
  pinMode(ledA, OUTPUT); //Sortie PWM n°1
  pinMode(ledJ, OUTPUT); //Sortie PWM n°1
  /*digitalWrite(ledA,HIGH); //Mis à 0 sortie 1 (commande en sink)
  delay(3000);*/
  digitalWrite(ledA,LOW);
  digitalWrite(ledJ,LOW); //Mis à 0 sortie 2 (commande en sink)
  Wire.begin();
  RTC.begin();
  RTC.adjust(DateTime(__DATE__, __TIME__));
  if (debug) {
    Serial.begin(9600); //Initialisation com pour debug
    lastDebug=0;
  }
  DateTime now=RTC.now();
  Horraires(now);
  Etat(now);
  analogWrite(ledA,niveauA);
  analogWrite(ledJ,niveauJ);
  lastLoop=0;
  
}

void loop () {
  long now=millis();
  long diff=now-lastLoop;
  long diffDebug=now-lastDebug;
  //diff=millis()-lastLoop;
  switch (etat) {
    case 0:
        if (diff>=30000) {
          if (RTC.now().get()>=horraires[1].get()) {
            etat=1;
            lastLoop=now;
          }
        }
        break;
    case 1:
        
        if (niveauA<pMaxA && diff>=pas[0]) {
          niveauA++;
          analogWrite(ledA,niveauA);
          lastLoop=now;

        }
        else if (niveauA==pMaxA && diff>=pas[0]) {
          analogWrite(ledA,niveauA);
          etat=2;
          lastLoop=now;
        }
        break;
        
     case 2:
         
         if (niveauJ<pMaxJ && diff>=pas[1]) {
           niveauJ++;
           analogWrite(ledJ,niveauJ);
           lastLoop=now;
         }
         else if (niveauJ==pMaxJ && diff>=pas[1]) {
           analogWrite(ledJ,niveauJ);
           etat=3;
           lastLoop=now;
         }
         break;
      
     case 3:
         
         if (niveauJ>0 && diff>=pas[1]) {
           niveauJ--;
           analogWrite(ledJ,niveauJ);
           lastLoop=now;
         }
         else if (niveauJ==0 && diff>=pas[1]) {
           analogWrite(ledJ,niveauJ);
           etat=4;
           lastLoop=now;
         }
         break;
         
     case 4:
         
         if (niveauA>0 && diff>=pas[2]) {
           niveauA--;
           analogWrite(ledA,niveauA);
           lastLoop=now;
         }
         else if (niveauA==0 && diff>=pas[2]) {
           analogWrite(ledA,niveauA);
           etat=5;
           lastLoop=now;
         }
         break;
     
     case 5:
         if (diff>=30000) {
           if (RTC.now().get()>=horraires[6].get()) {
             Horraires(RTC.now());
             etat=0;
             lastLoop=now;
           }
         }
         break;
  }
  
  if (debug==true) {
    if (diffDebug>=30000) {
    convert(now);
    Serial.print("Etat : ");
    Serial.print(etat);
    Serial.print("\n");
    Serial.print("Millis :");
    Serial.print(millis());
    Serial.print("\n");
    Serial.print("Diff : ");
    Serial.print(diff);
    Serial.print("\n");
    Serial.print("NiveauA : ");
    Serial.print(niveauA);
    Serial.print("\n");
    Serial.print("niveauJ : ");
    Serial.print(niveauJ);
    Serial.print("\n\n");
    lastDebug=now;
    }
  }
  

           
 }