/*
 * Date:    04/10/2022
 * Title:   LCD  RTC WIFI AND LOCAL USE ON LCD16x2  & ESP32
 * Author:  Rubén Lozano
 * 
 * References:
 * Information: Está aplicación conecta el modulo esp32 a internet para obtener mediante la 
 *              busqueda en un servidor NTP la fecha y hora exacta para mi región, luego 
 *              este valor sera guardado de manera local mientras el equipo se desconéctara
 *              pudiendo colocar a nuestro modulo en modo ahorro de nergia o SLEEP
 *              desconectando el wifi y manteniendo la hora sincronizada hasta
 *              la siguiente petición de conexión.               
*/

/*
 *****************************************************
 *                 LIBRERIAS
 *****************************************************
*/ 
#include <WiFi.h>           //Librería para conexión wifi 
#include <Wire.h>           //Librería 
#include <LiquidCrystal.h>  //Librería para uso de pantallas de cristal liquido.
#include <ESP32Time.h>      //Librería para uso del RTC interno ESP32

/*
 *****************************************************
 *                VARIABLES DEFINIDAS
 *****************************************************
*/ 
#define RS 19 //PIN D19 o D5
#define EN 18 //PIN D18 o TX2 GPIO17
#define DB4 5 //PIN D5 o RX2 GPIO16
#define DB5 4 //PIN D4
#define DB6 2 //PIN D2
#define DB7 15 //PIN D15
LiquidCrystal LCD(RS, EN, DB4, DB5, DB6, DB7); //INICIALIZACION LCD 16x2
ESP32Time rtc;

//Variables para conexión del servidor.
#define NTP_SERVER     "pool.ntp.org"   //Servidor ntp para obtención de datos 
#define UTC_OFFSET     -18000           //UTC PAIS  x  3600seconds = hora del paìs buscado
#define UTC_OFFSET_DST 0                //
/*
 *****************************************************
 *                     SETUP
 *****************************************************
*/ 
void setup() {
  Serial.begin(115200);
  //Formato setTime(seg, min, hora, dia, mes, año) sin usar ceros
  rtc.setTime(30, 33, 12, 9, 4, 2021);  // 17th Jan 2021 15:24:30
  //rtc.setTime(1609459200);  // 1st Jan 2021 00:00:00 
  
  LCD.begin(16, 2);             // set up the LCD's number of columns and rows.
  
  mensajesLCD(0);      //Mensaje en pantalla LCD: 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);             //Mensaje en pantalla LCD: Conexión wifi exitosa                  
  configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER); //Configuracion del time
}

/*
 *****************************************************
 *                      LOOP
 *****************************************************
*/ 
void loop() {
    printtoSerial();
    printLocalTime();
}

/*
 *****************************************************
 *                   FUNCIONES
 *****************************************************
*/ 
void spinner() {                //FUNCION QUE CREA UN EMOTICON DE CONEXION
  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;
  }
}

void printLocalTime() {       //OBTIENE E IMPRIME LA HORA Y LA FECHA  POR MEDIO DE NTP 
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    LCD.setCursor(0, 1);
    LCD.println("Connection Err");
    return;
  }
//mensajesLCD(2); //Mensaje en pantalla LCD: Hora y fecha
                LCD.setCursor(8, 0);
                LCD.println(&timeinfo, "%H:%M:%S");
                LCD.setCursor(0, 1);
                LCD.println(&timeinfo, "%d/%m/%Y   %Z");
}

void mensajesLCD(int opc) {     //IMPRIME CIERTOS MENSAJES EN LA PNATALLA LCD
  switch(opc){
        case 0:              //Mensaje 1 (estableciendo conexión wifi)
                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

        break;
  }
}

void printtoSerial(){       //IMPRIME EN EL MONITOR SERIAL
    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 segundos=rtc.getSecond();                   //Devuelve los segundos entre (0-59)
    int minutos=rtc.getMinute();                    //Devuelve los segundos entre (0-59)
    int hora=rtc.getHour();                         //Devuelve los horas entre (0-12)
    int horas_24=rtc.getHour(true);                 //Devuelve las hora en formato de 24 horas (0-23)
    int dia=rtc.getDay();                           //Devuelve el dia en formato entero (1-31)
    int mes=rtc.getMonth();                         //Devuelve el mes en representación de un formato entero (0-11)
    int anio=rtc.getYear();                         //Devuelve el año en formato entero. 
    
    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(minutos);
    Serial.print(":");
    Serial.print(segundos);
    Serial.print("");
    Serial.print(horario);
    Serial.print("\n");
    delay(1000);
}