#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>

#define inKolektor    A0
#define inZapnuti     A1
#define inVypnuti     A2
int inPrepinac6 = 6;
int inPrepinac7 = 7;
int outLedA3_otvirani = A3;
int outLedD5_zavirani = 5;
int outLed2_rozmraz = 2;    
int outLed3_auto = 3;
int outLed4_otevren = 4;
int outLed13_prehrati = 13;
int outCerpPrehrati8 = 8;
int outCerpObeh11 = 11;
int outVentilZavren9 = 9;
int outVentilOtevren10 = 10;
const int inTeplomerBojler12 = 12;

int kolektorVal = 0;
int kolektorTep;
int bojlerTep;
int rozdilTeploty = 0;

int zapnutiVal = 0;
int vypnutiVal = 0;
int zapnutiHod = 0;
int vypnutiHod = 0;

boolean prepinacAuto = false;
boolean prepinacRozmraz = false;
boolean prepinacOtevren = false;
boolean ventilOtevren = false;
boolean ventilSeOtvira = false;
boolean ventilZavren = false;
boolean ventilSeZavira = false;
boolean cerpadloObehZaple = false;
boolean cerpadloPrehratiZaple = false;

unsigned long currentMillis;
unsigned long currentMereniCerpadlo;
unsigned long ventilStartOtevreni;
unsigned long ventilStartUzavreni;
const unsigned long delkaChoduVentilu = 30000;
//const unsigned long delka8hMillis = 28800000;  // (60 min * 60 000) * 8
//const unsigned long delka12hMillis = 43 200 000;  // (60 min * 60 000) * 12
const unsigned long delka12hMillis = 300000;  // (5 min * 60 000) * 8
unsigned long cerpadloStart;
unsigned long currentCerpadlo;
unsigned long celkemCerpadlo;  // jak dlouho bezelo cerpadlo (v dobe mereni)
unsigned long celkemMereniCerpadlo; // doba kdy se mereni cas chodu cerpadla
unsigned long soucasnyBehCerpadlo;  // doba souvisleho behu cerpadla (pak se pridava do 'celkemCerpadlo' )


//dallas
OneWire oneWireDS(inTeplomerBojler12);
DallasTemperature senzoryDS(&oneWireDS);

// Set the LCD address to 0x27 for a 20 chars and 4 line display
LiquidCrystal_I2C lcd(0x27, 20, 4);


void setup() {
  Serial.begin(9600);
  
  //pinMode(poruchaLED, OUTPUT);
  //pinMode(inTlacStart,INPUT_PULLUP);
  //pinMode(inTlacReset,INPUT_PULLUP);
  //pinMode(inImpuls,INPUT);    //pinMode(inImpuls,INPUT);

  pinMode(inPrepinac6, INPUT_PULLUP);
  pinMode(inPrepinac7, INPUT_PULLUP);
  pinMode(outLedA3_otvirani, OUTPUT);
  pinMode(outLedD5_zavirani, OUTPUT);
  pinMode(outLed2_rozmraz, OUTPUT);
  pinMode(outLed3_auto, OUTPUT);
  pinMode(outLed4_otevren, OUTPUT);
  pinMode(outLed13_prehrati, OUTPUT);
  pinMode(outCerpPrehrati8, OUTPUT);
  pinMode(outCerpObeh11, OUTPUT);
  pinMode(outVentilZavren9, OUTPUT);
  pinMode(outVentilOtevren10, OUTPUT);
  
  digitalWrite(outLed2_rozmraz, LOW);
  digitalWrite(outLed3_auto, LOW);
  digitalWrite(outLed4_otevren, LOW);
  digitalWrite(outLed13_prehrati, LOW);
  digitalWrite(outCerpPrehrati8, LOW);
  digitalWrite(outCerpObeh11, HIGH);
  digitalWrite(outVentilZavren9, LOW);
  digitalWrite(outVentilOtevren10, LOW);
  digitalWrite(outLedA3_otvirani, LOW);
  digitalWrite(outLedD5_zavirani, LOW);

  // zapnutí komunikace knihovny s teplotním čidlem
  senzoryDS.begin();
  
  // initialize the LCD
  //wokwi
  //lcd.init(); 
  //lcd.backlight();
  // wokwi
  //lcd.begin();      // run
  lcd.init();      // 
  lcd.backlight();  // run
  //lcd.clear();
  zobrazHodnoty();
  
}

void loop() {
  zobrazHodnoty();

  if (celkemMereniCerpadlo != 0 ) {
     currentMereniCerpadlo = millis();
     if ((unsigned long)(currentMereniCerpadlo - celkemMereniCerpadlo) >= delka12hMillis) {
      celkemMereniCerpadlo =0;
      celkemCerpadlo = 0;
     }
  
  }

  kolektorVal = analogRead(inKolektor);
  zapnutiVal = analogRead(inZapnuti);
  vypnutiVal = analogRead(inVypnuti);

  kolektorTep = map(kolektorVal, 0, 1023, 0, 100);
  zapnutiHod = map(zapnutiVal, 0, 1023, 5, 20);
  vypnutiHod = map(vypnutiVal, 0, 1023, 2, 10);

  ///// wokwi
  const float BETA = 3950;
  kolektorTep = 1 / (log(1 / (1023. / kolektorVal - 1)) / BETA + 1.0 / 298.15) - 253.15;
  
  int kolektorVal2 = analogRead(A7);
  bojlerTep = 1 / (log(1 / (1023. / kolektorVal2 - 1)) / BETA + 1.0 / 298.15) - 253.15;
  //// wokwi
  
  // načtení informací ze všech připojených čidel na daném pinu
  senzoryDS.requestTemperatures();

  //bojlerTep = senzoryDS.getTempCByIndex(0); // run
  
  
  int prepinac6Val = digitalRead(inPrepinac6);
  int prepinac7Val = digitalRead(inPrepinac7);

  // automat D6=1 D7=1
  if (prepinac6Val == 1 && prepinac7Val == 1 && prepinacAuto == false) {
    prepinacAuto = true;
    prepinacRozmraz = false;
    prepinacOtevren = false;
    digitalWrite(outLed2_rozmraz, LOW);
    digitalWrite(outLed3_auto, HIGH);
    digitalWrite(outLed4_otevren, LOW);
  }
  
  // manual D6=0 D7=1 (otevren ventil)
  if (prepinac6Val == 0 && prepinac7Val == 1 && prepinacOtevren == false) {
    prepinacAuto = false;
    prepinacRozmraz = false;
    prepinacOtevren = true;
  }

  // rozmrazovani D6=1 D7=0
  if (prepinac6Val == 1 && prepinac7Val == 0 && prepinacRozmraz == false) {
    prepinacAuto = false;
    prepinacRozmraz = true;
    prepinacOtevren = false;
  }
    Serial.print(" beh: ");
    Serial.print(millis() - celkemMereniCerpadlo);
    Serial.print(" celk: ");
    Serial.println(celkemCerpadlo+soucasnyBehCerpadlo);

  /// Automatika
  if (prepinacAuto == true) {
    //prehrati....
    if (bojlerTep >= 85 && cerpadloPrehratiZaple == false) {
      // prehrati - zacatek
      digitalWrite(outCerpObeh11, HIGH);  //cerpadlo obeh-vypni
      cerpadloObehZaple = false;
      celkemCerpadlo += soucasnyBehCerpadlo;
      soucasnyBehCerpadlo = 0;
      // zavrit ventil, pokud je otevreny
      if (ventilOtevren == true && ventilSeZavira == false) {
        digitalWrite(outVentilZavren9, HIGH);
        ventilSeZavira = true;
        ventilStartUzavreni = millis(); 
      }

      digitalWrite(outLed3_auto, LOW);       // LED vypni
      digitalWrite(outLed13_prehrati, HIGH); // LED sviti
      digitalWrite(outCerpPrehrati8, HIGH);  // zapni cerpadlo

      cerpadloPrehratiZaple = true;
    }

    // zavirani ventilu
    if (ventilSeZavira == true) {
      doZavreniVentilu();
    }

    if (bojlerTep < 80 && cerpadloPrehratiZaple == true) {
      // prehrani - konec
      digitalWrite(outLed3_auto, HIGH);     //LED sviti
      digitalWrite(outLed13_prehrati, LOW); //LED vypni      
      digitalWrite(outCerpPrehrati8, LOW);  //cerpadlo vypni

      cerpadloPrehratiZaple = false;
    } 
    //prehrati....

    // automatika, pokud neni prehrati
    if (cerpadloPrehratiZaple == false) {
      // otevri ventil
      if (kolektorTep >= bojlerTep-2) {
        // kdyz je ventil zavreny => zacatek otvirani ventilu
        if ((ventilOtevren == false || ventilSeZavira == true ) && ventilSeOtvira == false) {
          //?? pokud se zavira => tak cekej 2s a pak signal na otevreni
          if (ventilSeZavira == true) {
            //Serial.println("Ventil se 2sss");
            digitalWrite(outVentilZavren9, LOW);
            ventilSeZavira = false;
            delay(2000);
          } 
          digitalWrite(outVentilOtevren10, HIGH);
          ventilSeOtvira = true;
          ventilStartOtevreni = millis(); 
        }
        //otvirani ventilu
        if (ventilSeOtvira == true) {
          //Serial.println("Ventil +++ otvirani");
          doOtevreniVentilu();
        }
      }
      
      // zavri ventil
      if (kolektorTep <= bojlerTep-4) {
        // zavrit ventil, pokud je otevreny
        if ((ventilOtevren == true || ventilSeOtvira == true ) && ventilSeZavira == false) {
          //pokud se otevira => tak cekej 2s
          if (ventilSeOtvira == true) {
            //Serial.println("Ventil se otvira a ma se zavirat");
            digitalWrite(outVentilOtevren10, LOW);
            ventilSeOtvira = false;
            delay(2000);
          }  
          digitalWrite(outVentilZavren9, HIGH);
          ventilSeZavira = true;
          ventilStartUzavreni = millis(); 
        }
        // zavirani ventilu
        if (ventilSeZavira == true) {
          //Serial.println("Ventil --- zavirani");
          doZavreniVentilu();
        }
      }

      // cerpadlo - rozdil teplot
      // kolektor je vetsi nez bojler
      if (kolektorTep > bojlerTep) {
        rozdilTeploty = kolektorTep - bojlerTep;
        // rozdil teplot je versi nez.... => zapli cerpadlo
        if (rozdilTeploty >= zapnutiHod && cerpadloObehZaple == false) {
          // cekani na uplne otevreni ventilu + spusteni cerpadla
          if (ventilSeOtvira == true) {
            // spusteni cerpadla po 10s
            if (cerpadloObehZaple == false) {
              doCerpPoVentil();
            }
          } else {
            digitalWrite(outCerpObeh11, LOW); //zapni
            cerpadloObehZaple = true;
            cerpadloStart = millis();
          }
        }
        // rozdil teplot je mensi nez ... => vypni cerpadlo
        if (rozdilTeploty <= vypnutiHod && cerpadloObehZaple == true) {
            digitalWrite(outCerpObeh11, HIGH); //vypni
            cerpadloObehZaple = false;
            celkemCerpadlo += soucasnyBehCerpadlo;
            soucasnyBehCerpadlo = 0;
        }
        
      } else {
        // stop cerpadlo 
        digitalWrite(outCerpObeh11, HIGH); //vypni
        cerpadloObehZaple = false;
        celkemCerpadlo += soucasnyBehCerpadlo;
        soucasnyBehCerpadlo = 0;
      } // cerpadlo - rozdil teplot ...
     
      if (cerpadloObehZaple == true) {
        currentCerpadlo = millis();
        soucasnyBehCerpadlo = (currentCerpadlo - cerpadloStart);
        if (celkemCerpadlo == 0 && celkemMereniCerpadlo == 0 ) {
          celkemMereniCerpadlo = millis();  // start mereni doby chodu cerpadla
        }
      }


    } //automatika, pokud neni prehrati ....

  }  // konec automatika

  // rozmrazovani
  if (prepinacRozmraz == true) {
    digitalWrite(outLed2_rozmraz, HIGH);
    digitalWrite(outLed3_auto, LOW);
    digitalWrite(outLed4_otevren, LOW);

    if ((ventilOtevren == false || ventilSeZavira == true ) && ventilSeOtvira == false) {
      //?? pokud se zavira => tak cekej 2s a pak signal na otevreni
      if (ventilSeZavira == true) {
        digitalWrite(outVentilZavren9, LOW);
        ventilSeZavira = false;
        delay(2000);
      } 
      digitalWrite(outVentilOtevren10, HIGH);
      ventilSeOtvira = true;
      ventilStartOtevreni = millis(); 
    }

    //kdyz je ventil otevreny => zapni cerpadlo
    if (ventilOtevren == true) {
      Serial.println("01 je otevren");
      digitalWrite(outCerpObeh11, LOW); // obehove ceroadlo - zapni
      cerpadloObehZaple = true;
    }

    // cekani na uplne otevreni ventilu + spusteni cerpadla
    if (ventilSeOtvira == true) {
      Serial.println("02 se otvira");
      doOtevreniVentilu();
      // spusteni cerpadla po 10s
      if (cerpadloObehZaple == false) {
        Serial.println("03 ");
        doCerpPoVentil();
      }
    }
      
  } // konec rozmrazovani

  // manual (ventil otevren)
  if (prepinacOtevren == true) {
    digitalWrite(outLed2_rozmraz, LOW);
    digitalWrite(outLed3_auto, LOW);
    digitalWrite(outLed4_otevren, HIGH);
    digitalWrite(outCerpObeh11, HIGH);  // vypnout obehove cerpadlo
    cerpadloObehZaple = false;
    celkemCerpadlo += soucasnyBehCerpadlo;
    soucasnyBehCerpadlo = 0;

    // kdyz je ventil zavreny => zacatek otvirani ventilu
    if ((ventilOtevren == false || ventilSeZavira == true ) && ventilSeOtvira == false) {
      //?? pokud se zavira => tak cekej 2s a pak signal na otevreni
      if (ventilSeZavira == true) {
        digitalWrite(outVentilZavren9, LOW);
        ventilSeZavira = false;
        delay(2000);
      } 
      digitalWrite(outVentilOtevren10, HIGH);
      ventilSeOtvira = true;
      ventilStartOtevreni = millis(); 
    }

    // cekani na uplne otevreni ventilu
    if (ventilSeOtvira == true) {
      doOtevreniVentilu();
    }
  } // konec manual (ventil otevren)
  
}

void doOtevreniVentilu() {
  currentMillis = millis();
  if ((unsigned long)(currentMillis - ventilStartOtevreni) >= delkaChoduVentilu) {
    //ukonci otvirani
    digitalWrite(outVentilOtevren10, LOW);  
    ventilOtevren = true;
    ventilSeOtvira = false;
  }  
}

void doZavreniVentilu() {
  currentMillis = millis();
  //Serial.println(currentMillis - ventilStartUzavreni);
  if ((unsigned long)(currentMillis - ventilStartUzavreni) >= delkaChoduVentilu) {
    //ukonci zavirani
    digitalWrite(outVentilZavren9, LOW);  
    ventilOtevren = false;
    ventilSeZavira = false;
  }  
}

void doCerpPoVentil() {
  currentMillis = millis();
  if ((unsigned long)(currentMillis - ventilStartOtevreni) >= 10000) {
    //zapni obehove cerpadlo
    digitalWrite(outCerpObeh11, LOW); //zapni
    cerpadloObehZaple = true;
    cerpadloStart = millis();
  }  
}

void zobrazHodnoty() {
  delay(500);
  //lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Solary:");
  lcd.setCursor(7, 0);
  lcd.print("   ");
  lcd.setCursor(7, 0);
  lcd.print(kolektorTep);
  
  lcd.setCursor(13, 0);
  lcd.print("Zap:");
  lcd.setCursor(17, 0);
  lcd.print("   ");
  lcd.setCursor(17, 0);
  lcd.print(zapnutiHod);
  ////
  lcd.setCursor(0, 1);
  lcd.print("Bojler:");
  lcd.setCursor(7, 1);
  lcd.print("   ");
  lcd.setCursor(7, 1);
  lcd.print(bojlerTep);

  lcd.setCursor(13, 1);
  lcd.print("Vyp:");
  lcd.setCursor(17, 1);
  lcd.print("   ");
  lcd.setCursor(17, 1);
  lcd.print(vypnutiHod);
  ////
  lcd.setCursor(0, 2);
  lcd.print("Ventil:");
  lcd.setCursor(7, 2);
  lcd.print("   ");
  lcd.setCursor(7, 2);
  if (ventilSeOtvira == true) {
    lcd.print("+++");
  } else if (ventilSeZavira == true)  {
    lcd.print("---");
  } else if (ventilOtevren == true)  {
   lcd.print("ON");
  } else {
   lcd.print("OFF");
  }

  ////
  lcd.setCursor(0, 3);
  lcd.print("Cerpadlo:");
  lcd.setCursor(9, 3);
  lcd.print("   ");
  lcd.setCursor(9, 3);
  if (cerpadloObehZaple == true) {
    lcd.print("ON");
  } else {
    lcd.print("OFF");
  }
  

  lcd.setCursor(13, 3);
  lcd.print("Cas:");
  lcd.setCursor(17, 3);
  lcd.print("   ");
  lcd.setCursor(17, 3);
  lcd.print((celkemCerpadlo+soucasnyBehCerpadlo)/60000);
  ////
}
Zel-D10-VentOtevirani
Cer-D9-VentZavirani
Zel-D11-CerpObeh
Rozmr-D2
Auto-D3
Otev-D4
Prehrati-D13
Zlu-D8-Prehrati
TeplKol
TepBojler
zapnuti
vypnuti