<<<<<<< HEAD
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

#define AQUAGRA
//#define AQUAZOA

#ifdef AQUAGRA
  char auth[] = "_Fw7V6o4bPAovQ1idbetFcith6LmMnyh"; //220L
#elif AQUAZOA
  char auth[] = "oObIhJsLplCUAhCBfwyvpBF_n_N8oqJv"; //70L
#endif

char ssid[] = "Livebox-7C2C";
char pass[] = "566C61F61F9C925C9F3D7D79E6";

WidgetRTC rtc;
BlynkTimer timer;
WidgetTerminal terminal(V60);

//************************************************************************
//                Variable Global perso
//************************************************************************
#ifdef AQUAGRA
  #define RESERVE 1200
  #define LITRE 220
  #define FACTEURML 635 //Temps d'allumage de la pompe en ms pour distribuer 1ml
  #define RESERVEMIN 100
  #define STARTCa 16
  #define STARTKh 30
  #define STARTMg 7
#elif AQUAZOA
  #define RESERVE 450
  #define LITRE 70
  #define FACTEURML 200//todo //Temps d'allumage de la pompe en ms pour distribuer 1ml
  #define RESERVEMIN 50
  #define STARTCa 16
  #define STARTKh 30
  #define STARTMg 7
#endif

#define POMPE0 0
#define POMPE1 1
#define POMPE2 2
#define POMPE3 3

//nombre de ml a distribuer pour remonter de +1 (mg ou kh) par litre d'eau
#define FACTEUR0 0.0057 //FACTEUR CA
#define FACTEUR1 0.36 //0.36ml/L = +1KH
#define FACTEUR3 0.02 //FACTEUR MG

const int PINPOMPE0 = 16;
const int PINPOMPE1 = 5;
const int PINPOMPE2 = 4;
const int PINPOMPE3 = 0;

float Mesure0, Mesure1, Mesure2, Mesure3;
float ML0, ML1, ML2, ML3 ;
float Cible0, Cible1, Cible2, Cible3 ;
bool Auto0, Auto1, Auto2, Auto3 ;
float Reserve0, Reserve1, Reserve2, Reserve3 ;
float MLForce0, MLForce1, MLForce2, MLForce3 ;
int dist;
  
//************************************************************************
//                Fonction Seul
//************************************************************************
void Ft_Timer() {
  int Hmin = hour() * 60 + minute();  
  switch(Hmin){
  case 0: //Calcium
    dist=0;
        AutoDistribue0(ML0);
    break;
  case 360: //Calcium
    dist=1;
        AutoDistribue0(ML0);
    break;
  case 720: //Calcium
    dist=2;
        AutoDistribue0(ML0);
    break;
  case 1080: //Calcium
    dist=3;
    AutoDistribue0(ML0);
    break;
  case 90: //KH
  dist=0;
    AutoDistribue1(ML1);
    break;
  case 450: //KH
  dist=1;
    AutoDistribue1(ML1);
    break;
  case 810: //KH
  dist=2;
    AutoDistribue1(ML1);
    break;
  case 1170: //KH
  dist=3;
  AutoDistribue1(ML1);
    break;
  case 180: //mineral
  dist=0;
      AutoDistribue2(ML2);
    break;
  case 540: //mineral
  dist=1;
      AutoDistribue2(ML2);
    break;
  case 900: //mineral
  dist=2;
      AutoDistribue2(ML2);
    break;
  case 1260: //mineral
  dist=3;
    AutoDistribue2(ML2);
    break;
  case 270://mg
  dist=0;
  AutoDistribue3(ML3);
    break;
  case 630://mg
  dist=1;
  AutoDistribue3(ML3);
    break;
  case 990://mg
  dist=2;
  AutoDistribue3(ML3);
    break;
  case 1350://mg
  dist=3;
    AutoDistribue3(ML3);
    break;
  }
}

BLYNK_CONNECTED() {
  char message[30];
  sprintf(message, "\nnew Connection\n");
  terminal.print(message);
  terminal.flush();

  rtc.begin();

  Blynk.syncAll();
}

BLYNK_WRITE(V60){
  if (String("Ca") == param.asStr()){
    Blynk.virtualWrite(V3, STARTCa);
    ML0=STARTCa;
  }
  if (String("Kh") == param.asStr()){
    Blynk.virtualWrite(V13, STARTKh);
    ML1=STARTKh;
  }
  if (String("Mi") == param.asStr()){
    Blynk.virtualWrite(V23, (ML0+ML1)/2);
    ML2=(ML0+ML1)/2;
  }
  if (String("Mg") == param.asStr()){
    Blynk.virtualWrite(V33, STARTMg); 
    ML3=STARTMg;
  }
}


void setup(){

  //Pin Setup
  pinMode(PINPOMPE0, OUTPUT);
  pinMode(PINPOMPE1, OUTPUT);
  pinMode(PINPOMPE2, OUTPUT);
  pinMode(PINPOMPE3, OUTPUT);
  
  digitalWrite(PINPOMPE0, HIGH);
  digitalWrite(PINPOMPE1, HIGH);
  digitalWrite(PINPOMPE2, HIGH);
  digitalWrite(PINPOMPE3, HIGH);

  Blynk.begin(auth, ssid, pass, IPAddress(192, 168, 1, 18), 8081);
  
  setSyncInterval(10 * 60); // Sync interval in seconds (10 minutes)

  timer.setInterval(1000L*60, Ft_Timer);
}

void loop(){
  Blynk.run();
  timer.run();
}
//************************************************************************
//                Fonction Calcium
//************************************************************************

void AutoDistribue0(float ml){
  
  if (Auto0) {
    if(((ML0/4)*FACTEURML)>(1000*4)){
      Active0(ML0/4);
    }
    else if((((ML0/2)*FACTEURML)>(1000*2))&(dist==0|dist==2)){
      Active0(ML0/2);
      }
    else if (dist==0){
      Active0(ML0);
    }
  }
  else{
    Blynk.notify("Calcium est Arreter");
  }
}

void Active0(float ml) {
  digitalWrite(PINPOMPE0, LOW);
  delay(FACTEURML * ml);
  digitalWrite(PINPOMPE0, HIGH);
  Reserve0=Reserve0-ml;
  Blynk.virtualWrite(V4, Reserve0);
  char message[30];
  sprintf(message, "Distribution %.1fml de Calcium a %d:%d\n", ml,hour(),minute());
  terminal.print(message);
  terminal.flush();
  if(Reserve0<RESERVEMIN)
    Blynk.notify("Penser a remettre du Calcium");
}

//Mesure
BLYNK_WRITE(V0) {
  if(Mesure0==0){//Si nouvelle connection on recupere juste la valeur enregistrer sur le server
    Mesure0 = param.asFloat();
    return;
  }
  Mesure0 = param.asFloat();
  
  ML0  = ML0 + (((ML0/Mesure0)* Cible0 - ML0)/4.0);
  MLForce0 = (Cible0-Mesure0)*FACTEUR0*LITRE;

  
  if(MLForce0<0)
    MLForce0=0;
  
  ML2 = (ML1+ML0)/2.0;
  Blynk.virtualWrite(V23, ML2);
  Blynk.virtualWrite(V3, ML0);
  Blynk.virtualWrite(V7, MLForce0);
}

//Cible
BLYNK_WRITE(V1) {
  if(Cible0==0){//Si nouvelle connection on recupere juste la valeur enregistrer sur le server
    Cible0 = param.asFloat();
    return;
  }
  Cible0 = param.asFloat();
  ML0 = ML0 +(((ML0/Mesure0)* Cible0- ML0)/4.0);
  ML2 = (ML1+ML0)/2.0;
  
  Blynk.virtualWrite(V23, ML2);
  Blynk.virtualWrite(V3, ML0);
}

//En route
BLYNK_WRITE(V2) {
  if ( param.asInt()){
    Auto0 = true;
  }
  else{
    Auto0 = false;
  }
}

BLYNK_WRITE(V3){
  ML0=param.asFloat();
  Blynk.virtualWrite(V3, ML0);
}

BLYNK_WRITE(V4){
  Reserve0=param.asFloat();
  Blynk.virtualWrite(V4, Reserve0);
}


//RAZ Reserve
BLYNK_WRITE(V5){
  if(param.asInt()){
    Reserve0=RESERVE;
    Blynk.virtualWrite(V4, Reserve0);
  }
}

//Forcé4
BLYNK_WRITE(V6){
  if(param.asInt()){
    Active0(4.0);
  }
}

//NB/Forcé
BLYNK_WRITE(V7){
  MLForce0=param.asFloat();
}

//Forcé
BLYNK_WRITE(V8){
  if ( param.asInt()){
    Active0(MLForce0);
  }
}



//************************************************************************
//                Fonction KH
//************************************************************************

void AutoDistribue1(float ml){
  if (Auto1) {
    if(((ML1/4)*FACTEURML)>(1000*4)){
      Active1(ML1/4);
    }
    else if((((ML1/2)*FACTEURML)>(1000*2))&(dist==0|dist==2)){
      Active1(ML1/2);
      }
    else if (dist==0){
      Active1(ML1);
    }
  }
  else{
    Blynk.notify("KH est Arreter");
  }
}

void Active1(float ml) {
  digitalWrite(PINPOMPE1, LOW);
  delay(FACTEURML * ml);
  digitalWrite(PINPOMPE1, HIGH);
  Reserve1=Reserve1-ml;
  Blynk.virtualWrite(V14, Reserve1);
  char message[30];
  sprintf(message, "Distribution %.1fml de KH a %d:%d\n", ml,hour(),minute());
  terminal.print(message);
  terminal.flush();
  if(Reserve1<RESERVEMIN)
    Blynk.notify("Penser a remettre du KH");
}

//Mesure
BLYNK_WRITE(V10) {
    if(Mesure1==0){//Si nouvelle connection on recupere juste la valeur enregistrer sur le server
    Mesure1 = param.asFloat();
    return;
  }
  Mesure1 = param.asFloat();

  ML1  = ML1 + (((ML1/Mesure1)* Cible1 - ML1)/4.0);
  MLForce1 = (Cible1-Mesure1)*FACTEUR1*LITRE;
  if(MLForce1<0)
    MLForce1=0;
  
  ML2 = (ML1+ML0)/2.0;
  Blynk.virtualWrite(V23, ML2);
  Blynk.virtualWrite(V13, ML1);
  Blynk.virtualWrite(V17, MLForce1);
}

//Cible
BLYNK_WRITE(V11) {
      if(Cible1==0){//Si nouvelle connection on recupere juste la valeur enregistrer sur le server
    Cible1 = param.asFloat();
    return;
  }
  Cible1 = param.asFloat();
  ML1 = ML1 +(((ML1/Mesure1) * Cible1- ML1)/4.0);
  
  ML2 = (ML0+ML1)/2.0;
  
  Blynk.virtualWrite(V23, ML2);
  Blynk.virtualWrite(V13, ML1);
}

//En route
BLYNK_WRITE(V12) {
  if ( param.asInt()){
    Auto1 = true;
  }
  else{
    Auto1 = false;
  }
}

BLYNK_WRITE(V13){
  ML1=param.asFloat();
  Blynk.virtualWrite(V13, ML1);
}

BLYNK_WRITE(V14){
   Reserve1=param.asFloat();
  Blynk.virtualWrite(V14, Reserve1);
}


//RAZ Reserve
BLYNK_WRITE(V15){
  if(param.asInt()){
    Reserve1=RESERVE;
    Blynk.virtualWrite(V14, Reserve1);
  }
}

//Forcé4
BLYNK_WRITE(V16){
  if(param.asInt()){
    Active1(4.0);
  }
}

//NB/Forcé
BLYNK_WRITE(V17){
  MLForce1=param.asFloat();
}

//Forcé
BLYNK_WRITE(V18){
  if ( param.asInt()){
    Active1(MLForce1);
  }
}

//************************************************************************
//                Fonction Mineral
//************************************************************************

void AutoDistribue2(float ml){
  if (Auto2) {
    if(((ML2/4)*FACTEURML)>(1000*4)){
      Active2(ML2/4);
    }
    else if((((ML2/2)*FACTEURML)>(1000*2))&(dist==0|dist==2)){
      Active2(ML2/2);
      }
    else if (dist==0){
      Active2(ML2);
    }
  }
  else{
    Blynk.notify("Mineral est Arreter");
  }
}

void Active2(float ml) {
  digitalWrite(PINPOMPE2, LOW);
  delay(FACTEURML * ml);
  digitalWrite(PINPOMPE2, HIGH);
  Reserve2=Reserve2-ml;
  Blynk.virtualWrite(V24, Reserve2);
  char message[30];
  sprintf(message, "Distribution %.1fml de Mineral a %d:%d\n", ml,hour(),minute());
  terminal.print(message);
  terminal.flush();
  if(Reserve2<RESERVEMIN)
    Blynk.notify("Penser a remettre du Mineral");
}

//En route
BLYNK_WRITE(V22) {
  if ( param.asInt()){
    Auto2 = true;
  }
  else{
    Auto2 = false;
  }
}

BLYNK_WRITE(V23){
  ML2=param.asFloat();
  Blynk.virtualWrite(V23, ML2);
}

BLYNK_WRITE(V24){
  Reserve2=param.asFloat();
  Blynk.virtualWrite(V24, Reserve2);
}


//RAZ Reserve
BLYNK_WRITE(V25){
  if(param.asInt()){
    Reserve2=RESERVE;
    Blynk.virtualWrite(V24, Reserve2);
  }
}

//Forcé4
BLYNK_WRITE(V26){
  if(param.asInt()){
    Active2(4.0);
  }
}

//NB/Forcé
BLYNK_WRITE(V27){
  MLForce2=param.asFloat();
}

//Forcé
BLYNK_WRITE(V28){
  if ( param.asInt()){
    Active2(MLForce2);
  }
}

//************************************************************************
//                Fonction Magnesium
//************************************************************************

void AutoDistribue3(float ml){
  if (Auto3) {
    if(((ML3/4)*FACTEURML)>(1000*4)){
      Active3(ML3/4);
    }
    else if((((ML3/2)*FACTEURML)>(1000*2))&(dist==0|dist==2)){
      Active3(ML3/2);
      }
    else if (dist==0){
      Active3(ML3);
    }
  }
  else{
    Blynk.notify("Magnesium est Arreter");
  }
}

void Active3(float ml) {
  digitalWrite(PINPOMPE3, LOW);
  delay(FACTEURML * ml);
  digitalWrite(PINPOMPE3, HIGH);
  Reserve3=Reserve3-ml;
  Blynk.virtualWrite(V34, Reserve3);
  char message[30];
  sprintf(message, "Distribution %.1fml de Magnesium  a %d:%d\n", ml,hour(),minute());
  terminal.print(message);
  terminal.flush();
  if(Reserve3<RESERVEMIN)
    Blynk.notify("Penser a remettre du Magnesium");
}

//Mesure
BLYNK_WRITE(V30) {
        if(Mesure3==0){//Si nouvelle connection on recupere juste la valeur enregistrer sur le server
    Mesure3 = param.asFloat();
    return;
  }
  Mesure3 = param.asFloat();
  ML3  = ML3 + (((ML3/Mesure3)* Cible3 - ML3)/4.0);
  MLForce3 = (Cible3-Mesure3)*FACTEUR3*LITRE;
  if(MLForce3<0)
    MLForce3=0;

  Blynk.virtualWrite(V33, ML3);
  Blynk.virtualWrite(V37, MLForce3);
}

//Cible
BLYNK_WRITE(V31) {
  if(Cible3==0){//Si nouvelle connection on recupere juste la valeur enregistrer sur le server
    Cible3 = param.asFloat();
    return;
  }
  Cible3 = param.asFloat();
  ML3 = ML3 +(((ML3/Mesure3)* Cible3- ML3)/4.0);
  Blynk.virtualWrite(V23, ML2);
  Blynk.virtualWrite(V33, ML3);
}

//En route
BLYNK_WRITE(V32) {
  if ( param.asInt()){
    Auto3 = true;
  }
  else{
    Auto3 = false;
  }
}

BLYNK_WRITE(V33){
  ML3=param.asFloat();
  Blynk.virtualWrite(V33, ML3);
}

BLYNK_WRITE(V34){
  Reserve3=param.asFloat();
  Blynk.virtualWrite(V34, Reserve3);
}


//RAZ Reserve
BLYNK_WRITE(V35){
  if(param.asInt()){
    Reserve3=RESERVE;
    Blynk.virtualWrite(V34, Reserve3);
  }
}

//Forcé4
BLYNK_WRITE(V36){
  if(param.asInt()){
    Active3(4.0);
  }
}

//NB/Forcé
BLYNK_WRITE(V37){
  MLForce3=param.asFloat();
}

//Forcé
BLYNK_WRITE(V38){
  if ( param.asInt()){
    Active3(MLForce3);
  }
}
