//https://create.arduino.cc/projecthub/electropeak/using-1602-lcd-keypad-shield-w-arduino-w-examples-e02d95
#include <Arduino.h>
#include <Adafruit_Sensor.h>
#include <LiquidCrystal.h>
#include <DHT.h>
#include <Streaming.h>

#define     ALLAPOT         Serial<<"    >T(3) : "<<termoszJel<<"      CS(7) : " <<digitalRead(CSIGA)<< "     VENTI :  \n"

const uint8_t  PARAM_SZAM  = 16;           // paraméterek száma 
const uint8_t  TERMOSZT    =  2;           // láb  a termosztáthoz
const uint32_t SOHA        =4294967295;   // végtelen idő. Ha egy időpont nem érdekes, ezt kapja,


#define     SOHA           4294967295     // végtelen idő. Ha egy időpont nem érdekes, ezt kapja,
#define     VENTI_KESES    400            // Ne csigával egyszerre induljon
#define     CSIGABE        1              //A csiga erre indul el [0/1]
#define     CSIGAKI        !CSIGABE       //A CSIGABE ellentettje
#define     TERMOSZBE      0              // A termosz fűtést kér
#define     TERMOSZKI      !TERMOSZBE     // Termosz kikapcsolást kér
uint8_t     termoszJel      ;             //A Termoszláb értéke (0/1);
uint8_t     termoszMult    =255;          //A Termoszláb előző értéke ;
uint32_t    ventiGyorsLesz =0;            //be/kikapcsolási időpontok  (millis)
uint32_t    ventiLassuLesz =SOHA;
uint32_t    csigaBeLesz    =0;            //időpont Millis()
uint32_t    csigaKiLesz    =0;            //Időpont Millis
uint32_t    most;                         //aktuális idő  (millis)
uint32_t    csigamegy;                    //Menetidő TATRTAMA [ms]
uint32_t    csigaszunet;
String      melegit_e;
uint32_t    kov_Olvas=0;                  // legközelebbi adatolvasási időpont
volatile uint32_t nyomva  =SOHA;          //mikor nyomták meg a gombot? 
bool        kepzar=false;        

//LCD lábak 
  const int pin_RS = 8;
  const int pin_EN = 9;
  const int pin_d4 = 4;
  const int pin_d5 = 5;
  const int pin_d6 = 6;
  const int pin_d7 = 7;
  const int pin_BL = 10;
LiquidCrystal lcd( pin_RS,  pin_EN,  pin_d4,  pin_d5,  pin_d6,  pin_d7);

enum gombok {ENTER,LEFT,DOWN,UP,RIGHT};
enum szint  {FOKEP,MENU,ALLITO};
szint     menu_Szint=FOKEP;

typedef struct {
  uint8_t   oszl;               //oszlop a főképen
  uint8_t   sor;                //sor  a főképen
  uint8_t   lab;                //Mikrokontroller láb száma
  int16_t   oszto;              //kiírás nagyságrendje
  uint8_t   irhato_e;           //fix-vagy írható?
  char      txt[17];            //megnevezés
  char      egyseg[4];          //Mértékegység
} param;
// 12334567890123456 KezdőképAlapállapot
//╔════════════════╗  Jelmagyarázat:
//║79°45%12s 40 198║   |előre:79°|ventifűt:45%pwm||adagszünet_Füt:12|adagidő:0,4 mp|Kémény:198°
//║61 28%30  65 -10║   |visszaág:61°|VEntitart28%pwm||adagszünet_tart:30 Szivattyú be:65°|Külső:-10° |
//╚════════════════╝
char kepsor[4][17]=           //Az LCD kép mintája
{ "00 00%00s 00\"000",        //Sor0
  "00 00 00  00 000",         //Sor1

  "Ld 000 SzivKi 00",         //Sor2 Egyelőre nincs használva
  "000 p-re_megy00",          //Sor3
};
//       x, érték, oszl, sor, lab,oszto, irhato, txt        , egység
const param X[PARAM_SZAM]= //                0123456789012345
      { {/*   78,*/  4,   0,  10,  1,    1, "PWM % futes:"   ,"%" },//PWM% Fűtéskor
        {/*   35,*/  4,   1,  10,  1,    1, "PWM % Tuz.tart:","%" },//PWM% Tűztartáskor
        {/*11000,*/  7,   0,  13,  1000, 1, "Cs.szunet fut:" ,"ms"},//msec csigaszünet Fűtéskor
        {/*30000,*/  7,   1,  13,  1000, 1, "Cs.szunet tart:","ms"},//msec csigaszünet tűztartáskor
        {/*  450,*/ 11,   0,  13,  10,   1, "Csigamenetido:" ,"ms"},//msec Csiga menetidő
        {/*   65,*/ 11,   1,  12,  1,    1, "Sziv bekapcs :" ,"C" },//C°   Szivattyú bekapcsolási hő.
        {/*   55,*/ 12,   2,  12,  1,    1, "Sziv kikapcs :" ,"C" },//C°   Sziv kikapcsolási hőmérséklet
        {/*   65,*/  2,   3,  12,  1,    1, "Tisztitaskoz"   ,"min"},//perc Időköz nagyadag tisztításkor
        {/*   65,*/ 15,   3,  12,  1,    1, "Tisztitas ido"  ,"sec"},//ms  Menetidő nagyadag tisztításkor
        {/*   90,*/  0,   0,  A3,  1,    1, "Vesz homers."   ,"C" },//C°   Túlmelegedési küszöb
        {/*   76,*/  1,   0,  A3,  1,    0, ""               ,"C" },//c°   Előremenő víz
        {/*   53,*/  1,   1,  A4,  1,    0, ""               ,"C" },//C°   Viszzajövő
        {/*  198,*/ 15,   0,  A2,  1,    0, ""               ,"C" },//C°   Kémény hőmérséklet
        {/*  125,*/ 15,   1,  A5,  1,    0, "Lambda"         ,"Lam"},//    Lambda érték
        {/*    2,*/ 15,   2,  A1,  1,    0, ""               ,"C" },//C°   Külső hőmérséklet
        {/*    1,*/  3,   0,   2,  1,    0, "*"              ,""  },//B/K  Termosztat
};
int16_t Y[]={78,35,11000,30000,450,65,55,65,65,90,76,53,198,125,-2};

enum param_t {venti_Fut, venti_Tart,  csigaSz_Fut, csigaSz_Tart,  csiga_Megy, t_SzivBe, \
              t_SzivKi,  tiszt_Koz, tiszt_Tartam, t_Vesz, t_Elore , t_Vissza, t_Kemeny, Lambda,\
              t_Kinti,  termosztat };
/*void xprintx(char* cel, const int32_t valtozo, uint8_t m )
 { uint8_t x=0;
  if   ( valtozo < 0)  x++;
  if   (abs(valtozo)<10) ;
  else (abs(valtozo)<100) ? x++ :  x +=2;
  memccopy(&cel,&puff,x);
  lcd.setCursor(oszl,sor);
  lcd.print(valtozo);
 }

 void printx(int16_t valtozo, uint8_t oszl, uint8_t sor )
 { if   (valtozo<0)  oszl--;
  if   (abs(valtozo)<10) ;
  else (abs(valtozo)<100) ? oszl-- : oszl -=2;
  lcd.setCursor(oszl,sor);
  lcd.print(valtozo);
 }
*/

 
void beilleszt(const uint8_t i)
{ char tar[]="     ";
  itoa(Y[i]/X[i].oszto, tar, DEC);
    uint8_t hossz=strlen(tar);
  memcpy(&kepsor[X[i].sor][X[i].oszl-hossz+1], tar, hossz);
}

void fkep()
{ if (menu_Szint!=FOKEP) return;
  for( uint8_t i=venti_Fut ; i<t_Kinti ;  i++ ) beilleszt(i);
  lcd.setCursor(0, 0);  lcd.print(kepsor[0]);
  lcd.setCursor(0, 1);  lcd.print(kepsor[1]);
}
void nyomas(void) 
{ nyomva=millis()+50;
}

void akcio_Menu(gombok gomb)
{ static uint8_t aktiv_Sor;
  switch (menu_Szint)
  { case FOKEP:     ////////////////////  Főkép
      aktiv_Sor=0;
      if (gomb==ENTER || gomb==RIGHT)
      {  menu_Szint=MENU;
        lcd.clear();
        lcd.noCursor();
        lcd.print(X[venti_Fut].txt);
        lcd.setCursor(0,1);
        lcd << Y[venti_Fut] << "  " << X[venti_Fut].egyseg<<"  ";
      } 
    break;

    case MENU:      //////////////////  Menü
      switch (gomb)
      { case RIGHT:
        case ENTER:
          menu_Szint=ALLITO;
          lcd.setCursor(1,1);lcd.cursor(); lcd.blink();
        break;
        case LEFT:
          menu_Szint=FOKEP;
          fkep();
         break;
        case UP:
          if (aktiv_Sor>0) 
          { aktiv_Sor--;
            lcd.clear(); 
            lcd.print(X[aktiv_Sor].txt);
            lcd.setCursor(0,1);lcd.noBlink();
            lcd<<Y[aktiv_Sor]<<"  "<<X[aktiv_Sor].egyseg<<"  ";
          }
        break;
        case DOWN:
          if (aktiv_Sor<t_Vesz) 
          { aktiv_Sor++;
            lcd.clear(); 
            lcd.print(X[aktiv_Sor].txt);
            lcd.setCursor(0,1);lcd.noBlink();
            lcd<<(Y[aktiv_Sor])<<"  "<<X[aktiv_Sor].egyseg<<"  ";
          }
        break;
      }
    break;
    
    
    case ALLITO:
      int8_t elojel=1;
      switch (gomb)
      { case RIGHT:
        case LEFT:
        case ENTER:
          menu_Szint=MENU;
          lcd.noBlink();lcd.noCursor();
        break;
        case DOWN:
          elojel=-1;
        case UP:
          (aktiv_Sor!=csiga_Megy) ? Y[aktiv_Sor] += X[aktiv_Sor].oszto*elojel  : Y[aktiv_Sor] += 25*elojel  ;
          lcd.setCursor(0,1);
          lcd<<(Y[aktiv_Sor]/X[aktiv_Sor].oszto)<<"  "<<X[aktiv_Sor].egyseg<<"  ";
          lcd.setCursor(1,1);
        break;
      }
    break;  
  }
}

gombok gomb_Olvas()
{ uint16_t x = analogRead (A0);
  if      (x < 160)  return ENTER; 
  else if (x < 400)  return LEFT;  
  else if (x < 650)  return DOWN;  
  else if (x < 850)  return UP;    
  return RIGHT; 
}


int16_t ntc_Olvas(uint8_t lab){ float x=(float)(1/(log(1 / (1023. / analogRead(lab) - 1)) / 3950 + 1.0 / 298.15) - 273.15); return (int16_t)round(x);}

param_t jelolvas(uint32_t most)
{ const  uint32_t   olvasas_Koz=1000;    //[s] olvasas közti idő
  if (kov_Olvas< most )
  { Y[t_Elore]  =ntc_Olvas(X[t_Elore].lab)  ;
    Y[t_Vissza] =ntc_Olvas(X[t_Vissza].lab) ;
    Y[t_Kemeny] =ntc_Olvas(X[t_Kemeny].lab) ;
    Y[t_Kinti]  =ntc_Olvas(X[t_Kinti].lab)  ;
    kov_Olvas=most+olvasas_Koz;    
    if  (Y[t_Elore]<105 && Y[t_Elore]>5)    {beilleszt(t_Elore) ;}
    else  return t_Elore;
    if  (Y[t_Vissza]<95 && Y[t_Vissza]>5)   beilleszt(t_Vissza) ;   
    else return t_Vissza;
    if  (Y[t_Kemeny]<250 && Y[t_Kemeny]>5)  {beilleszt(t_Kemeny);}
    else return t_Kemeny;
    if  (Y[t_Kinti]<45  && Y[t_Kinti]>-25)  {beilleszt(t_Kinti) ;}
    else return t_Kinti;
    if  (Y[t_Elore]+3< Y[t_Vissza])         return 253;
    fkep();
    //Serial<<kepsor[0]<<"      "<<kepsor[1]<<"\n";
  }
  
  return 0;
}
// 12334567890123456 KezdőképAlapállapot
//╔════════════════╗  Jelmagyarázat:
//║79°45%12s 40 198║   |előre:79°|ventifűt:45%pwm||adagszünet_Füt:30|adagidő:0,4 mp|Kémény:198°
//║61 28%30  65 -10║   |visszaág:61°|VEntitart28%pwm||adagszünet_tart:30 Szivattyú be:65°|Külső:-10° |
//╚════════════════╝

//================================================================================
/*void frekivalt(int32_t  freq, uint8_t PWM )
                        //[Hz],        [%]
{  //Timer 2,  16 bit   16mhz  3 és 11-es lábak. 3-as=OCR2B  11-es = OCR2A/
   pinMode(X[venti_Fut].lab, OUTPUT);  //PIN11
   TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); //GYORS_PWM mód 
   TCCR2B = _BV(WGM22) | _BV(CS22); 
   TCCR2B = TCCR2B & (B11111000 | B00000100);  int32_t divisor=64;    //timer 2 divisor to    64  (The DEFAULT)
    //TCCR2B = TCCR2B & B11111000 | B00000001; int32_t divisor=1;   //timer 2 divisor to     1 
    //TCCR2B = TCCR2B & B11111000 | B00000010; int32_t divisor=8;   //timer 2 divisor to     8 
    //TCCR2B = TCCR2B & B11111000 | B00000011; int32_t divisor=32;    //timer 2 divisor to    32 
    //TCCR2B = TCCR2B & B11111000 | B00000101; int32_t divisor=128;   //timer 2 divisor to   128 
    //TCCR2B = TCCR2B & B11111000 | B00000110; int32_t divisor=256;   //timer 2 divisor to   256 
    //TCCR2B = TCCR2B & B11111000 | B00000111; int32_t divisor=1024;   //timer 2 divisor to  1024  
   OCR2A = F_CPU/divisor/freq-1;       //frekvencia a 3 lábon =16000000/divisor/(OCR2A+1)   
   OCR2B = (uint8_t)OCR2A*100/PWM+PWM/2;        //láb 3  PWM%
}
*/
void setup() 
{  Serial.begin(9600); //Serial<<"Vezérlés indul...\n";
   pinMode(TERMOSZT, INPUT);
   pinMode(X[csiga_Megy].lab, OUTPUT);
   pinMode(X[venti_Fut].lab, OUTPUT);   
   TCCR1B = TCCR1B & (B11111000 | B00000101);   // 9-10 Láb  PWM frequency : 30.64 Hz;
    //TCCR2B = TCCR2B & B11111000 | B00000111; // 3és  11 Láb  PWM frequency : 30.64 Hz
    //https://www.etechnophiles.com/change-frequency-pwm-pins-arduino-uno/
   attachInterrupt(digitalPinToInterrupt(3), nyomas, RISING);
   lcd.begin(16, 2);
   fkep(); 
}

 
void loop() 
{ String jelentes;
  most = millis();
  param_t ellenor;
  if (nyomva < most) 
  { gombok nyomott_Gomb=gomb_Olvas();
    akcio_Menu(nyomott_Gomb); 
    most=millis();
    //Serial<< nyomott_Gomb<<endl;
    nyomva=SOHA;
    }
  ellenor=jelolvas(most);
  termoszJel = (!digitalRead(TERMOSZT));
  Serial<< termoszJel<<endl;
  if(termoszJel!=termoszMult) //Váltás volt. Átállítjuk a paramétereket: 
  { if(termoszJel==TERMOSZBE) //--------- Fűtésre váltott --------------------
    { csigamegy=Y[csiga_Megy];         //  CSIGAMEGY_FUT;
      csigaszunet=Y[csigaSz_Fut];      //   CSIGASZ_FUT;
      csigaBeLesz=most;
      csigaKiLesz=SOHA;
      analogWrite(X[venti_Fut].lab, Y[venti_Fut]*100/255);
      delay(VENTI_KESES);
      melegit_e="  ------   Fűt  -------  Venti                GYORS >";
    }else                    //--------- Tűztartás --------
    { csigamegy=Y[csiga_Megy];         //   CSIGAMEGY_TART;
      csigaszunet=Y[csigaSz_Tart];     // CSIGASZ_TART;
      csigaKiLesz=most;
      csigaBeLesz=SOHA;
      analogWrite(X[venti_Tart].lab, Y[venti_Tart]*255/100);
      melegit_e="  -----Tűztartás-------  Venti LASSÚ >";
    }
  termoszMult = termoszJel;
  }
//--------A paramétereknek megfelelően frissíti az állapotokat
  if(csigaBeLesz < most)                          //Eljött a bekapcsolás ideje
  { digitalWrite(X[csiga_Megy].lab,CSIGABE);     //csiga indul
    csigaKiLesz = most+csigamegy;                //Majd ekkor áll le.
    jelentes="CSiga [BE]    van   Tjel:   "+String(termoszJel);
    Serial.println(jelentes+melegit_e);
  }
  if(csigaKiLesz < most)                          //Eljött a kikapcsolás ideje
  { digitalWrite(X[csigaSz_Tart].lab ,CSIGAKI);  //Csiga leáll.
    csigaBeLesz=most+csigaszunet;                //Ekkor indul újra.
    csigaKiLesz=SOHA;                            //Még egyszer ne állítsa le.
    jelentes="CSiga     [KI]van   Tjel:   "+String(termoszJel);
    Serial.println(jelentes+melegit_e);
  }
}