//----------------inclusão de biblioteca---------------------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <RTClib.h>
#include <SPI.h>
#include <SD.h>
#include <EEPROM.h>

//----------------Definições dos pinos-----------------------------------
const int M_ROBO = 13;      // Motor de movimento do robô
const int M_ESCOV = 12;    // Motor das escovas
const int M_BOMBA = 26;    // Motor da bomba
const int FC_INI = 14;      // Fim de curso do robô do lado inicial
const int FC_END = 27;      // Fim de curso do robô do lado final
const int BT_A = 5;       // Botão 1 (Esquerda)
const int BT_B = 16;        // Botão 2 (Direita)
const int BT_C = 17;        // Botão 3 (sel)
const int BT_D = 4;         // Botão 4 (Voltar)
const int SD_MISO = 19;
const int SD_MOSI = 23;
const int SD_SCK = 18;
const int SD_CS = 25;

const int mem1 = 0;
const int mem2 = 1;
const int mem3 = 2;

//----------------Inicialização do LCD e RTC-----------------------------
LiquidCrystal_I2C lcd(0x27, 20, 4);  // Endereço 0x27 para LCD 16x2
RTC_DS3231 rtc;
File myFile;

//----------------variaveis globais--------------------------------------
int H_agenda = 0;  //usado para salvar a agenda definida pelo usuario
int M_agenda = 0;  //usado para salvar a agenda definida pelo usuario
int S_agenda = 0;  //usado para salvar a agenda definida pelo usuario
int intervalo = 1; //usado para salvar a agenda definida pelo usuario
bool menu = 0;     //define quando algum menu foi acessado
int sel_s = 1;     //esse valor e usado quando a variavel "sel" é alterado
int sel = 0;       //diz ao código qual menu está selecionado
int m_s = 1;       //sse valor e usado quando a variavel "menu" é alterado
int time_home = 0; //variavel usada para contar voltas loop para registrar tempo
int result;        //variavel usada para dar resultado atravez de uma função(void)
int result_t ;     //variavel usada para dar resultado atravez de uma função(void) e usado para registro de tempo
bool bt_s1 = 0;    //usado para travar botao no seu estado
bool bt_s2 = 0;    //usado para travar botao no seu estado
bool bt_s3 = 0;    //usado para travar botao no seu estado
bool bt_s4 = 0;    //usado para travar botao no seu estado
bool result_b;     //usado para dar resultado atravez de uma função(void)
//----------------caracteres especiais logo da empresa------------------------
  byte SIMB1[8] = {B00000,B00000,B00000,B00011,B00010,B00000,B00101,B01101};
  byte SIMB2[8] = {B00000,B00100,B01110,B00000,B01110,B11111,B11111,B11111};
  byte SIMB3[8] = {B00000,B00000,B00000,B11000,B01000,B00000,B10100,B10110};
  byte SIMB5[8] = {B00101,B00000,B00010,B00011,B00000,B00000,B00000,B00000};
  byte SIMB6[8] = {B11111,B11111,B01110,B00000,B01110,B00100,B00000,B00000};
  byte SIMB7[8] = {B10100,B00000,B01000,B11000,B00000,B00000,B00000,B00000};
//----------------------------------------------------------------------------------------------------------
void setup() {
  // Inicializar comunicação
  Serial.begin(115200);
  Wire.begin();
  lcd.begin(20, 4);
  rtc.begin();
  lcd.clear();

  // Configuração de pinos
  pinMode(M_ROBO, OUTPUT);
  pinMode(M_ESCOV, OUTPUT);
  pinMode(M_BOMBA, OUTPUT);
  pinMode(FC_INI, INPUT);
  pinMode(FC_END, INPUT);
  pinMode(BT_A, INPUT);
  pinMode(BT_B, INPUT);
  pinMode(BT_C, INPUT);
  pinMode(BT_D, INPUT);

  //declara caracters especiais
  lcd.createChar(6, SIMB3); 
  lcd.createChar(7, SIMB5); 
  lcd.createChar(8, SIMB6); 
  lcd.createChar(9, SIMB7); 
  lcd.createChar(4, SIMB1); 
  lcd.createChar(5, SIMB2);
  
  //escreve logo da empresa
  lcd.setCursor(8,0);
  lcd.write(4);
  lcd.write(5);
  lcd.write(6);
  lcd.setCursor(8,1);
  lcd.write(7);
  lcd.write(8);
  lcd.write(9);
  writeTexto("SUN CLEAR",5,2);

// verifica cartao SD
  SPI.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);
  if (!SD.begin(SD_CS)) {
    Serial.println("Falha ao inicializar o cartão SD");
    writeTexto("Falha no cartao SD",0,3);
    delay(3000); 
    menu = 1;
    sel = 3;
  }
  delay(3000);  // Espera para mostrar mensagem inicial
  recuperarVariaveis();
  lcd.clear();
}
//----------------------------------------------------------------------------------------------------------
void loop() {
  // Executa diferentes funções de acordo com o menu selecionado
  if(menu){
    switch(sel){
      case 0:
        menu_edit_h();   // menu de edição de hora
      break;
      case 1:
        agenda();  //menu de edição de agenda
      break;
      case 2:
        menu_limpeza(); //menu para ativar limpeza
      break;
      case 3:
        menu_reset(); //menu para reiniciar o esp
      break;
    }
  }
  if(!menu)MENU_HOME(); //menu principal
  if(menu && sel > 3)menu = 0;
  delay(10);
}
//----------------------------------------------------------------------------------------------------------
void agenda(){
  lcd.clear();
  //cria variaveis locais 
  int time = 0; //time para contagem de tempo
  int select = 0; //para seleção do que vai ser editado 

  //desenha a tela
  writeTexto("Hora",0,0);
  writeTexto(":",8,0);
  writeTexto("intervalo em dias:",0,2);

  //cria um loop interno enquanto estiver editandoo
  while(menu == 1){
      
      time++;// conta uma volta

      if(time > 49)time = 0; //se a contagem de tempo chegar a 50, ele volta para 0

      // tela ----------------------------------------------------------

      // funcao "writeNumberEdit" explicação:
      // (numero da coluna do lcd, numero da linha do lcd, variavel que vai aparecer na tela, ...
      // ... conntagem de tempo, selecao atual do que esta editando, valor da selecao pra ser editado)

      writeNumberEdit(6,0,H_agenda,time,select,0);
      writeNumberEdit(9,0,M_agenda,time,select,1);
      writeNumberEdit(9,3,intervalo,time,select,2);


      // botoes -------------------------------------------------------------

      // funcao "verificarBotao" explicação:
      // (botao há ser verificado, set do botao, variavel que vai ser editado , ...
      // ... numero minimo, numero maximo, escolhe se incrementa ou decrementa, contagem de tempo,...  
      // ... valor pra editar contagem de tempo)
      // para trazer a variavel modificada são:
      // result    traz a variavel incrementada ou decrementada
      // result_t  traz o tempo resetado
      // result_b  traz o set do botao atualizado

      switch(select){
        case 0:
          verificarBotao(BT_A, bt_s1, H_agenda, 0, 23, true, time, -1);
          H_agenda = result;
        break;
        case 1:
          verificarBotao(BT_A, bt_s1, M_agenda, 0, 59, true, time, -1);
          M_agenda = result;
        break;
        case 2:
          verificarBotao(BT_A, bt_s1, intervalo, 0, 59, true, time, -1);
          intervalo = result;
        break;
      }
      bt_s1 = result_b;
      time = result_t;
       switch(select){
        case 0:
          verificarBotao(BT_B,bt_s2,H_agenda,0,23,false,time,-1);
          H_agenda = result;
        break;
        case 1:
          verificarBotao(BT_B,bt_s2,M_agenda,0,59,false,time,-1);
          M_agenda = result;
        break;
        case 2:
          verificarBotao(BT_B,bt_s2,intervalo,0,59,false,time,-1);
          intervalo = result;
        break;
      }
      time = result_t;
      bt_s2 = result_b;
      verificarBotao(BT_C,bt_s3,select,0,2,true,time,-1);
      select = result;
      time = result_t;
      bt_s3 = result_b;
      verificarBotao(BT_D,bt_s4,menu,0,1,false,time,-1);
      menu = result;
      time = result_t;
      bt_s4 = result_b;

    delay(10);
  }
  lcd.clear();
  m_s = 4;
  gravarVariaveis(H_agenda, M_agenda, intervalo);
  //EEPROM.put(mem1, H_agenda);
  //EEPROM.put(mem2, M_agenda);
  //EEPROM.put(mem3, intervalo);

}
//----------------------------------------------------------------------------------------------------------
void MENU_HOME(){
  time_home++;
  if(menu == 0 && sel != m_s){
    m_s = sel;
    if(sel < 3){
      if(sel == 0)writeTexto(">Hora<(Editar)   1/2",0,0);   
      if(sel != 0)writeTexto(" Hora            1/2",0,0);    
      if(sel == 1)writeTexto(">Agenda<(Editar)    ",0,1);   
      if(sel != 1)writeTexto(" Agenda             ",0,1);   
      if(sel == 2)writeTexto(">Limpeza<(Ativar)   ",0,2);   
      if(sel != 2)writeTexto(" Limpeza            ",0,2);  
    }
    if(sel > 2){
      if(sel == 3)writeTexto(">Reiniciar<      2/2",0,0);   
      if(sel != 3)writeTexto(" Reiniciar       2/2",0,0);    
      if(sel == 4)writeTexto(">                   ",0,1);   
      if(sel != 4)writeTexto("                    ",0,1);   
      if(sel == 5)writeTexto(">                   ",0,2);   
      if(sel != 5)writeTexto("                    ",0,2);  
    }
    
  }
  
  if(time_home == 45){
    DateTime now = rtc.now();
    writeNumberEdit(0,3,rtc.now().hour(),0,0,0);
    writeNumberEdit(3,3,rtc.now().minute(),0,0,0);
    writeNumberEdit(6,3,rtc.now().second(),0,0,0);
    writeNumberEdit(10,3,rtc.now().day(),0,0,0);
    writeNumberEdit(13,3,rtc.now().month(),0,0,0);
    writeNumberEdit(16,3,rtc.now().year(),0,0,0);  
    writeTexto(":",2,3);
    writeTexto(":",5,3);
    writeTexto("/",12,3);
    writeTexto("/",15,3);
  }
  if(time_home == 90)time_home = 0;
  //CONFIG DO BOTÕES
  verificarBotao(BT_A,bt_s1,sel,0,5,true, 0,0);sel = result;bt_s1 = result_b;
  verificarBotao(BT_B,bt_s2,sel,0,5,false, 0,0);sel = result;bt_s2 = result_b;
  verificarBotao(BT_C,bt_s3,menu,0,1,true, 0,0);menu = result;bt_s3 = result_b;
  verificarBotao(BT_D,bt_s4,menu,0,1,false, 0,0);menu = result;bt_s4 = result_b;
}
//----------------------------------------------------------------------------------------------------------
void menu_edit_h(){ 
  int time = 0;
  int select = 0;
  int diasNoMes[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  lcd.clear();
  DateTime now = rtc.now();
  writeTexto("Hora: ",0,0);
  writeTexto(":",8,0);
  writeTexto(":",11,0);
  writeTexto("Data: ",0,1);
  writeTexto("/",8,1);
  writeTexto("/",11,1);

  int H = rtc.now().hour(), M = rtc.now().minute(), S = rtc.now().second();
  int DAY = rtc.now().day(), MONTH = rtc.now().month(), Y = rtc.now().year();
  while(menu == 1){
    time++;
    if(time > 49)time = 0;
    // tela ----------------------------------------------------------
    writeNumberEdit(6,0,H,time,select,0);
    writeNumberEdit(9,0,M,time,select,1);
    writeNumberEdit(12,0,S,time,select,2);
    writeNumberEdit(6,1,DAY,time,select,3);
    writeNumberEdit(9,1,MONTH,time,select,4);
    writeNumberEdit(12,1,Y,time,select,5);
    // botoes -------------------------------------------------------------
    if (select == 0){verificarBotao(BT_A,bt_s1,H,0,23,true,time,-1);H = result; time = result_t;bt_s1 = result_b;}
    if (select == 1){verificarBotao(BT_A,bt_s1,M,0,59,true,time,-1);M = result; time = result_t;bt_s1 = result_b;}
    if (select == 2){verificarBotao(BT_A,bt_s1,S,0,59,true,time,-1);S = result; time = result_t;bt_s1 = result_b;}
    if (select == 3){verificarBotao(BT_A,bt_s1,DAY,1,diasNoMes[MONTH - 1],true,time,-1);DAY = result; time = result_t;bt_s1 = result_b;}
    if (select == 4){verificarBotao(BT_A,bt_s1,MONTH,1,12,true,time,-1);MONTH = result; time = result_t;bt_s1 = result_b;}
    if (select == 5){verificarBotao(BT_A,bt_s1,Y,2020,2100,true,time,-1);Y = result; time = result_t;bt_s1 = result_b;}
    if (select == 0){verificarBotao(BT_B,bt_s2,H,0,23,false,time,-1);H = result; time = result_t;bt_s2 = result_b;}
    if (select == 1){verificarBotao(BT_B,bt_s2,M,0,59,false,time,-1);M = result; time = result_t;bt_s2 = result_b;}
    if (select == 2){verificarBotao(BT_B,bt_s2,S,0,59,false,time,-1);S = result; time = result_t;bt_s2 = result_b;}
    if (select == 3){verificarBotao(BT_B,bt_s2,DAY,1,diasNoMes[MONTH - 1],false,time,-1);DAY = result; time = result_t;bt_s2 = result_b;}
    if (select == 4){verificarBotao(BT_B,bt_s2,MONTH,1,12,false,time,-1);MONTH = result; time = result_t;bt_s2 = result_b;}
    if (select == 5){verificarBotao(BT_B,bt_s2,Y,2020,2100,false,time,-1);Y = result; time = result_t;bt_s2 = result_b;}
    verificarBotao(BT_C,bt_s3,select,0,5,true,time,-1);select = result; time = result_t;bt_s3 = result_b;
    verificarBotao(BT_D,bt_s4,menu,0,1,false,time,-1);menu = result; time = result_t;bt_s4 = result_b;   
    delay(10);
  }
  lcd.clear();
  m_s = 4;
  rtc.adjust(DateTime(Y, MONTH, DAY, H, M, S));   // Ajuste Manual (Ano, Mês, Dia, Hora, Min, Seg)    
}

void menu_limpeza(){
  lcd.clear();
  writeTexto("Em breve",0,0);
  writeTexto("presione D",0,2);
  writeTexto("para voltar",0,3);
  while(menu == 1){
    verificarBotao(BT_D,bt_s4,menu,0,1,false,0,0);menu = result;bt_s4 = result_b;
    delay(10);
  }
  lcd.clear();
  m_s = 4;
}

void menu_reset(){
  bool teste = 0;
  lcd.clear();
  writeTexto("Reiniciar?",0,0);
  writeTexto(" D     C  ",0,2);
  writeTexto("Nao   Sim ",0,3);
  while(menu == 1){
    verificarBotao(BT_D,bt_s4,menu,0,1,false,0,0);menu = result;bt_s4 = result_b;
    delay(10);
    verificarBotao(BT_C,bt_s3,teste,0,1,true,0,0);teste = result;bt_s3 = result_b;
    if(teste)menu = 0;
  }
  lcd.clear();
  m_s = 4;
  
  if (teste){
    writeTexto("Reiniciando...",0,0);
    delay(1000);
    lcd.clear();
    ESP.restart();
  }
}

//----------------------------------------------------------------------------------------------------------
void writeTexto(String texto,int NC,int NL){
  lcd.setCursor(NC, NL);
  lcd.print(texto);
}
//----------------------------------------------------------------------------------------------------------
void writeNumberEdit(int NC, int NL, int number,int t,int setsel, int testsel){ 
  // recebe as variaveis quando foi chamado 
  if(t <= 0){ //se a contagem de tempo for 0 ou menos ele escreve o numero na tela
      // nessa parte ve se o numero tem 1 ou dois digitos e formata ele
    if(number < 10 && number > -10){ //se tiver um digito
      lcd.setCursor(NC, NL); //numero da linha e coluna escolhida no chamado da funcao 
      lcd.print("0"); // coloca um 0 para mandar um digito pro lado
      lcd.print(number); // escreve o numero na tela
    }else{//se tiver 2 digitos
      lcd.setCursor(NC, NL);  //numero da linha e coluna escolhida no chamado da funcao 
      lcd.print(number);// escreve o numero na tela
    }
  }

  // essa parte é para fazer o numero picar na tela
  // se a contagem de tempo for maior que 25 e o numero for menor que 100
  if(t == 25 && number < 100 && setsel == testsel){
    lcd.setCursor(NC, NL); //numero da linha e coluna escolhida no chamado da funcao 
    lcd.print("  ");// apaga o numero na tela
  } 
  // se a contagem de tempo for maior que 25 e o numero for maior que 100
  if(t == 25 && number >= 100 && setsel == testsel){
    lcd.setCursor(NC, NL); //numero da linha e coluna escolhida no chamado da funcao 
    lcd.print("    ");// apaga o numero na tela
  }
}
//----------------------------------------------------------------------------------------------------------
void verificarBotao(int botao, bool setB,int V,int limite_M,int limite, bool sinal, int time,int time_set){ //
  result_t = time;
  if (digitalRead(botao) == HIGH && setB == 0){
    setB = 1;
    if(sinal){V++;if (V > limite)V = limite_M;}
    if(!sinal){V--;if (V < limite_M)V = limite;}
    result_t = time_set;
  }
  if (digitalRead(botao) == LOW && setB == 1)setB = 0;
  result = V;
  result_b = setB;
}
//------------------------------------------------------------------------------------------------------------
void gravarVariaveis(int a, int b,int c) {
  SD.remove("/variaveis.txt");
  File arquivo = SD.open("/variaveis.txt", FILE_WRITE);
  if (!arquivo) {
    Serial.println("Falha ao abrir o arquivo para escrita");
    return;
  }
  arquivo.printf("%d\n%d\n%d\n", a, b, c);

  arquivo.close();
  Serial.println("Variáveis gravadas com sucesso!");
}
void recuperarVariaveis() {
  File arquivo = SD.open("/variaveis.txt", FILE_READ);
  if (!arquivo) {
    Serial.println("Erro ao abrir o arquivo para leitura!");
    return;
  }

  int variavel1 = arquivo.parseInt();
  int variavel2 = arquivo.parseInt();
  int variavel3 = arquivo.parseInt();

  H_agenda = variavel1;
  M_agenda = variavel2;
  intervalo = variavel3;
  arquivo.close();
  //EEPROM.get(mem1, H_agenda);
  //EEPROM.get(mem2, M_agenda);
  //EEPROM.get(mem3, intervalo);


  Serial.println("Variáveis recuperadas com sucesso!");
}
GND5VSDASCLSQWRTCDS1307+
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
A
B
C
D