/*
 * Modder:  @red9030
 * Title:   BIGNUMBER NTP Clock  + LCD1602 I²C ESP32 version
 * Reference: https://arduinogetstarted.com/tutorials/arduino-lcd-clock
 *            https://steemit.com/utopian-io/@lapilipinas/arduino-big-digits-0-99-with-i2c-16x2-lcd
 *  _   _     _   _ 
 * |_| |_| . |_| |_|
 * |_| |_| . |_| |_|
 * 
 * This example code is in the public domain
 */

/*
 * FILAS    ----
 * COLUMNAS ||||
*/

/*
 *****************************************************
 *    LIBRERIAS
 *****************************************************
*/
#include <Wire.h>               //Librery for I2C connection
#include <WiFi.h>               //Librery for wifi connection                
#include <LiquidCrystal_I2C.h>  //Librery for Crystal Liquid Display "LCD".
#include <ESP32Time.h>          //Library for internal RTC ESP32.
/*
 *****************************************************
 *    VARIABLES
 *****************************************************
*/
#define boton1 19
#define boton2 18  
#define I2C_address 0x27    // 0x27 , 0x3F , 0x20 , 0x38
const int lcdFilas = 2;     //Rows LCD
const int lcdColumnas = 16; //Colums LCD

LiquidCrystal_I2C LCD(I2C_address, lcdColumnas, lcdFilas);  // I2C address 0x27 (from DIYables LCD), 16 column and 2 rows

ESP32Time rtc; //RTC ESP32
struct tm timeinfo;     //Create a tm type structure
byte dia, mes, anio, hora, minuto, segundo; //Declare the variables where the data time, day, month and year willbe stored.

//Server connection variables.
#define NTP_SERVER     "pool.ntp.org"   //Server ntp for obtain data.
#define UTC_OFFSET     -18000           //UTC Country  x  3600seconds = Country hour searching.
#define UTC_OFFSET_DST 0                //

//Varibles for BIG NUMBERS
byte LT[8] = { B00111, B01111, B11111, B11111, B11111, B11111, B11111, B11111 };
byte UB[8] ={ B11111, B11111, B11111, B00000, B00000, B00000, B00000, B00000 };
byte RT[8] ={ B11100, B11110, B11111, B11111, B11111, B11111, B11111, B11111 };
byte LL[8] ={ B11111, B11111, B11111, B11111, B11111, B11111, B01111, B00111 };
byte LB[8] ={ B00000, B00000, B00000, B00000, B00000, B11111, B11111, B11111 };
byte LR[8] ={ B11111, B11111, B11111, B11111, B11111, B11111, B11110, B11100 };
byte MB[8] ={ B11111, B11111, B11111, B00000, B00000, B00000, B11111, B11111 };
byte block[8] ={ B11111, B11111, B11111, B11111, B11111, B11111, B11111, B11111 };

/*
 *****************************************************
 *    INICIO
 *****************************************************
*/
void setup() {
  Serial.begin(115200);

  //LCD
  LCD.init();                        // initialize the lcd I2C
  //LCD.begin(lcdColumnas,lcdFilas); // initialize the lcd 
  LCD.backlight();

  //BIG CHARACTERES ON LCD
  LCD.createChar(0,LT);
  LCD.createChar(1,UB);
  LCD.createChar(2,RT);
  LCD.createChar(3,LL);
  LCD.createChar(4,LB);
  LCD.createChar(5,LR);
  LCD.createChar(6,MB);
  LCD.createChar(7,block);
  
  // Print a message to the LCD.
  int temp = 10;
  LCD.clear();
  printDigits(0,0);
  printDigits(1,4);
  printDigits(2,8);
  printDigits(3,12);
  LCD.clear();

  //Set RTC Buttons
  pinMode(boton1, INPUT_PULLUP);
  pinMode(boton2, INPUT_PULLUP);

  mensajesLCD(0);      //LCD message: estableciendo conexión wifi

   //Conexión wifi
  WiFi.begin("Wokwi-GUEST", "", 6);
  while (WiFi.status() != WL_CONNECTED) {
    delay(250);
  spinner();
  }
  
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  mensajesLCD(1);             //LCD message: Conexión wifi exitosa                    
  configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER); //Time Configuration.


}

/*
 *****************************************************
 *    REPETICIÓN
 *****************************************************
*/
void loop() {
  //if(digitalRead(boton1) == LOW){
    //setearDatosAlRtc();
  //}else{
    printtoSerial();
    printLocalTime();
    
    segundo=rtc.getSecond();                   //Devuelve los segundos entre (0-59)
    minuto=rtc.getMinute();                    //Devuelve los segundos entre (0-59)
    hora=rtc.getHour(true);                    //Devuelve los horas entre (0-12).
    dia=rtc.getDay();                          //Devuelve el dia en formato entero (1-31)
    mes=rtc.getMonth();                        //Devuelve el mes en representación de un formato entero (0-11)
    anio=rtc.getYear();                        //Devuelve el año en formato entero. 
    mensajesLCD(2);
 // }
}

/*
 *****************************************************
 *    FUNCIONES
 *****************************************************
*/

//FUNCION QUE CREA UN EMOTICON DE CONEXION
void spinner() {                
  static int8_t counter = 0;
  const char* glyphs = "\xa1\xa5\xdb";
  LCD.setCursor(15, 1);
  LCD.print(glyphs[counter++]);
  if (counter == strlen(glyphs)) {
    counter = 0;
  }
}

//OBTIENE E IMPRIME LA HORA Y LA FECHA  POR MEDIO DE NTP 
void printLocalTime() {       
  if (!getLocalTime(&timeinfo)) {
    LCD.setCursor(0, 1);
    LCD.println("Connection Err");
    return;
  }

}

 //IMPRIME CIERTOS MENSAJES EN LA PNATALLA LCD
void mensajesLCD(int opc) {    
  switch(opc){
        case 0:              //Mensaje 1 (estableciendo conexión wifi)
                LCD.clear();
                LCD.setCursor(0, 0);
                LCD.print("Connecting to ");
                LCD.setCursor(0, 1);
                LCD.print("WiFi ");
        break;
        case 1:             //Mensaje 2
                LCD.clear();
                LCD.setCursor(0, 0);
                LCD.println("Online");
                LCD.setCursor(0, 1);
                LCD.println("Updating time...");
        break;
        case 2:              //Mensaje 3
//mensajesLCD(2); //Mensaje en pantalla LCD: Hora y fecha
                if(hora < 10){
                        printNumber(0,0); //printNumer(Valor, Columna)
                        printNumber(hora,0);
                      }else 
                        printNumber(hora,0);
                        LCD.setCursor(6, 0);
                        LCD.print(".");
                        LCD.setCursor(6, 1);
                        LCD.print(".");
                  if(minuto < 10){
                        printNumber(0,7);
                        printNumber(minuto,7);
                      }else
                        printNumber(minuto,7);
                        LCD.setCursor(13, 0);
                        LCD.print(".");
                        LCD.setCursor(13, 1);
                        LCD.print(".");
                  if(segundo < 10){
                        LCD.print("0");
                        LCD.print(segundo);
                      }else
                        LCD.print(segundo);
          break;
  }
}

//IMPRIME EN EL MONITOR SERIAL
void printtoSerial(){       
    String now=rtc.getTime("%A,%B %d %Y %H:%M:%S"); //Devuelve la hora con el formato especificado
    String horario=rtc.getAmPm(true);               // Devuelve el horario si es AM o PM
    int horas_24=rtc.getHour(true);                 //Devuelve las hora en formato de 24 horas (0-23)

    
    Serial.println("Hora actual");
    Serial.print("Forma 1: ");
    Serial.println(now);  
  
    Serial.print("Forma 2: ");
    Serial.print(dia);
    Serial.print("/");
    Serial.print(mes+1);
    Serial.print("/");
    Serial.print(anio);
    Serial.print(" ");
    Serial.print(horas_24);
    Serial.print(":");
    Serial.print(minuto);
    Serial.print(":");
    Serial.print(segundo);
    Serial.print("");
    Serial.print(horario);
    Serial.print("\n");
    delay(250);
}

//Print the update number
void printNumber(int val,int col){  
     printDigits(val/10,col);
     printDigits(val%10,col+3);
}

void custom0(int x){
  LCD.setCursor(x,0);
  LCD.write((byte)0); 
  LCD.write(1); 
  LCD.write(2);
  LCD.setCursor(x, 1);
  LCD.write(3); 
  LCD.write(4); 
  LCD.write(5);
}
void custom1(int x){
  LCD.setCursor(x,0);
  LCD.write(1);
  LCD.write(2);
  LCD.print(" ");
  LCD.setCursor(x,1);
  LCD.write(4);
  LCD.write(7);
  LCD.write(4);
}
void custom2(int x){
  LCD.setCursor(x,0);
  LCD.write(6);
  LCD.write(6);
  LCD.write(2);
  LCD.setCursor(x, 1);
  LCD.write(3);
  LCD.write(4);
  LCD.write(4);
}
void custom3(int x){
  LCD.setCursor(x,0);
  LCD.write(6);
  LCD.write(6);
  LCD.write(2);
  LCD.setCursor(x, 1);
  LCD.write(4);
  LCD.write(4);
  LCD.write(5);
}
void custom4(int x){
  LCD.setCursor(x,0);
  LCD.write(3);
  LCD.write(4);
  LCD.write(7);
  LCD.setCursor(x, 1);
  LCD.print(" ");
  LCD.print(" ");
  LCD.write(7);
}
void custom5(int x){
  LCD.setCursor(x,0);
  LCD.write(3);
  LCD.write(6);
  LCD.write(6);
  LCD.setCursor(x, 1);
  LCD.write(4);
  LCD.write(4);
  LCD.write(5);
}
void custom6(int x){
  LCD.setCursor(x,0);
  LCD.write((byte)0);
  LCD.write(6);
  LCD.write(6);
  LCD.setCursor(x, 1);
  LCD.write(3);
  LCD.write(4);
  LCD.write(5);
}
void custom7(int x){
  LCD.setCursor(x,0);
  LCD.write(1);
  LCD.write(1);
  LCD.write(2);
  LCD.setCursor(x, 1);
  LCD.print(" ");
  LCD.print(" ");
  LCD.write(7);
}
void custom8(int x){
  LCD.setCursor(x,0);
  LCD.write((byte)0);
  LCD.write(6);
  LCD.write(2);
  LCD.setCursor(x, 1);
  LCD.write(3);
  LCD.write(4);
  LCD.write(5);
}
void custom9(int x){
  LCD.setCursor(x,0);
  LCD.write((byte)0);
  LCD.write(6);
  LCD.write(2);
  LCD.setCursor(x, 1);
  LCD.print(" ");
  LCD.print(" ");
  LCD.write(7);
}

//Print digits on LCD
void printDigits(int digits, int x){
  // utility function for digital clock display: prints preceding colon and leading 0
  switch (digits) {
  case 0: 
    custom0(x);
    break;
  case 1: 
    custom1(x);
    break;
  case 2: 
    custom2(x);
    break;
  case 3: 
    custom3(x);
    break;
  case 4: 
    custom4(x);
    break;
  case 5: 
    custom5(x);
    break;
  case 6: 
    custom6(x);
    break;
  case 7: 
    custom7(x);
    break;
  case 8: 
    custom8(x);
    break;
  case 9: 
    custom9(x);
    break;
  }
}