Reloj con Matriz led 8*64 sin RTC cambio anticipado de fecha

Saludos a todos, es mi primera consulta y agradezco cualquier ayuda que me puedan brindar.
Encontré un código para hacer un reloj digital con matrices de led de 8x8, con 8 unidades, es decir queda un bloque de 8x64 leds y funciona muy bien con un detalle relevante. Parece ser que está hecho con horario de verano con GTM 5.5 , Lo cambié a mi zona horaria de Colombia GTM -5 y el reloj cambia la fecha al dia siguiente a las 19:01:00 HRS. parece ser que para cambiar la fecha se rige por la hora real UTC (Coordinated Universal Time). He consultado, acudí al Chat GPT y me dió varias opciones pero nada funciona y ya no sé que hacer. Es un reloj que consulta la hora a un servidor(google) y de aqui extrae la hora y fecha, pero no usa RTC. Si necesitan el codigo original no sé donde postearlo. El chat GPT dice que el inconveniente es la parte negativa de la zona (-5) y que al recalcular la hora se hace dificil. pero con todas las opciones que me da la fecha sigue cambiando a las 19 HRS.
Codigo aqui: NTP_clock_dot matrix - Google Drive
https://www.youtube.com/watch?v=W-h2dHcIwKc

Hola @rogersh7 deberías leer las normas del foro y postear el código y no obligarnos a tener que descargarlo para evaluar lo que ocurre.
Parece una trivialidad pero no lo es.
Ahora te invito a que usando etiquetas (si no sabes lee las normas) postees en un nuevo post el código y te daremos posibles soluciones.

He corrido tu código, hice ajustes para ver los datos y solo modificando aquí funciona perfectamente

float utcOffset           = -3.0;  //GMT 5.30
long localEpoc            = 0;
long localMillisAtUpdate ;   // no hace falta ponerlo en 0. Es una variable que se usa justamente para actualizar millis().

GMT-3 es para Argentina que es mi caso.

El programa no me gusta como funciona, actualiza demasiado seguido.
Tal vez se deba a que no estoy viendo los array y ahi ocurra mejor.

Hola @Surbyte muchisimas gracias de antemano, probaré, ahora me toca esperar a las 19:01 HRs para verificar que no cambie la fecha antes de tiempo, si no a las 12:00 PM. La hora funciona perfecto. Te estaré contando como me va. Gracias nuevamente.

Te cambia la fecha a las 19:00 y por que?
Eso fue a tus 19:00 y el reloj con GMT-5 o sea corrido 5 hs, pero si estas en hora no va a cambiar hasta las 24 como corresponde.
En realidad no cambio a las 19:00, estas mezclando cosas.
Tu leias 18:59 y el mostraba 23:59 y a las 19:00 fueron las 24 o sea 5 hs cambiado.

Lo cambié a mi zona horaria de Colombia GTM -5 y el reloj cambia la fecha al dia siguiente a las 19:01:00 (7:01 minuto de la noche mostrado en el panel de matriz 8x64) HRS. parece ser que para cambiar la fecha se rige por la hora real UTC (Coordinated Universal Time).
Cuando en Colombia son las 7:01 pm la UTC tiene las 12 PM y es ahi cuando en mi matriz de led muestra la fecha del siguiente dia.
La hora me la muestra correctamente todo el tiempo.

Adjunta el código de acuerdo a las Normas como ya te lo ha pedido el moderador (@Surbyte) así lo podemos ver directamente aquí.

Agrego:
Tu código no hace corrección de la fecha, imprime la subcadena con la fecha tal y como llega del servidor (variable date), entonces la muestra en cuanto cambia la fecha UTC (en tu caso a las 19:00).
Te sugiero usar la librería Time que te facilita el ajuste a tu uso horario (corrige hora y fecha) y además mantiene la hora mediante un rtc virtual (evitas tu rutina updateTime())

Y obviamente no imprimir directamente la fecha desde la variable date. :wink:

Saludos @MaximoEsfuerzo , claro que si:

/*
  ESP-01 pinout from top:
  
  GND    GP2 GP0 RX/GP3
  TX/GP1 CH  RST VCC

  MAX7219
  ESP-1 from rear
  Re Br Or Ye
  Gr -- -- --

  USB to Serial programming
  ESP-1 from rear, FF to GND, RR to GND before upload
  Gr FF -- Bl
  Wh -- RR Vi

  GPIO 2 - DataIn
  GPIO 1 - LOAD/CS
  GPIO 0 - CLK

  ------------------------
  NodeMCU 1.0 pinout:

  D8 - DataIn
  D7 - LOAD/CS
  D6 - CLK
  
*/


#include "Arduino.h"
#include <ESP8266WiFi.h>


WiFiClient client;

String date;

#define NUM_MAX 8

// for ESP-01 module
//#define DIN_PIN 2 // D4
//#define CS_PIN  3 // D9/RX
//#define CLK_PIN 0 // D3

// for NodeMCU 1.0
#define DIN_PIN 14  // D8
#define CS_PIN  13  // D7
#define CLK_PIN 12  // D6



#include "max7219.h"
#include "fonts.h"

// =======================================================================
// CHANGE YOUR CONFIG HERE:
// =======================================================================
const char* ssid     = "XXXXXXXX";     // SSID of local network
const char* password = "XXXXXXX";   // Password on network

// =======================================================================

void setup() 
{
  Serial.begin(115200);
  initMAX7219();
  sendCmdAll(CMD_SHUTDOWN,1);
  sendCmdAll(CMD_INTENSITY,0);
  Serial.print("Connecting WiFi ");
  WiFi.begin(ssid, password);
  printStringWithShift("Connecting...... ",25);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected: "); Serial.println(WiFi.localIP());
}
// =======================================================================
#define MAX_DIGITS 16
byte dig[MAX_DIGITS]={0};
byte digold[MAX_DIGITS]={0};
byte digtrans[MAX_DIGITS]={0};
int updCnt = 0;
int dots = 0;
long dotTime = 0;
long clkTime = 0;
int dx=0;
int dy=0;
byte del=0;
int h,m,s;
// =======================================================================
void loop()
{
  if(updCnt<=0) 
  { 
    updCnt = 10;  // every 10 scrolls, ~450s=7.5m
    Serial.println("Getting data...");
    printStringWithShift("Getting data....",25);  // 25    SPEED
    getTime();
    Serial.println("Data loaded");
    clkTime = millis();
  }
 
  if(millis()-clkTime > 120000 && !del && dots) // clock for 40s, then scrolls for about 30s
  { 
    printStringWithShift(date.c_str(),75);
   delay(10000);
   printStringWithShift("           .Reloj Digital.",75);
   delay(3000);
    updCnt--;
    clkTime = millis();
  }
    if(millis()-dotTime > 500) 
  {
    dotTime = millis();
    dots = !dots;
  }
  updateTime();
  showAnimClock();
  
 }

// =======================================================================

void showSimpleClock()
{
  dx=dy=0;
  clr();
  showDigit(h/10,  1, dig6x8);
  showDigit(h%10,  9, dig6x8);
  showDigit(m/10, 18, dig6x8);
  showDigit(m%10, 26, dig6x8);
  showDigit(s/10, 49, dig6x8);
  showDigit(s%10, 49, dig6x8);
  setCol(16,dots ? B00100100 : 0);
  setCol(33,dots ? B00100100 : 0);
  refreshAll();
}

// =======================================================================

void showAnimClock()
{
  byte digPos[6]={1,8,18,25,41,49};
  int digHt = 12;
  int num = 6; 
  int i;
  if(del==0) {
    del = digHt;
    for(i=0; i<num; i++) digold[i] = dig[i];
    if(h>12)
   {
    h=h-12;
    }
    dig[0] = h/10 ? h/10 : 10;
    dig[1] = h%10;
    dig[2] = m/10;
    dig[3] = m%10;
    dig[4] = s/10;
    dig[5] = s%10;
    for(i=0; i<num; i++)  digtrans[i] = (dig[i]==digold[i]) ? 0 : digHt;
  } else
    del--;
  
  clr();
  
  for(i=0; i<num; i++) {
    if(digtrans[i]==0) {
      dy=0;
      showDigit(dig[i], digPos[i], dig6x8);
    } else {
      dy = digHt-digtrans[i];
      showDigit(digold[i], digPos[i], dig6x8);
      dy = -digtrans[i];
      showDigit(dig[i], digPos[i], dig6x8);
      digtrans[i]--;
    }
  }
  dy=0;
  setCol(15,dots ? B00100100 : 0);
  setCol(16,dots ? B00100100 : 0);
  setCol(34,dots ? B00100100 : 0);
  setCol(35,dots ? B00100100 : 0);
  refreshAll();
  delay(30);
}

// =======================================================================

void showDigit(char ch, int col, const uint8_t *data)
{
  if(dy<-8 | dy>8) return;
  int len = pgm_read_byte(data);
  int w = pgm_read_byte(data + 1 + ch * len);
  col += dx;
  for (int i = 0; i < w; i++)
    if(col+i>=0 && col+i<8*NUM_MAX) {
      byte v = pgm_read_byte(data + 1 + ch * len + 1 + i);
      if(!dy) scr[col + i] = v; else scr[col + i] |= dy>0 ? v>>dy : v<<-dy;
    }
}

// =======================================================================

void setCol(int col, byte v)
{
  if(dy<-8 | dy>8) return;
  col += dx;
  if(col>=0 && col<8*NUM_MAX)
    if(!dy) scr[col] = v; else scr[col] |= dy>0 ? v>>dy : v<<-dy;
}

// =======================================================================

int showChar(char ch, const uint8_t *data)
{
  int len = pgm_read_byte(data);
  int i,w = pgm_read_byte(data + 1 + ch * len);
  for (i = 0; i < w; i++)
    scr[NUM_MAX*8 + i] = pgm_read_byte(data + 1 + ch * len + 1 + i);
  scr[NUM_MAX*8 + i] = 0;
  return w;
}

// =======================================================================

void printCharWithShift(unsigned char c, int shiftDelay) {
  
  if (c < ' ' || c > '~'+25) return;
  c -= 32;
  int w = showChar(c, font);
  for (int i=0; i<w+1; i++) {
    delay(shiftDelay);
    scrollLeft();
    refreshAll();
  }
}

// =======================================================================

void printStringWithShift(const char* s, int shiftDelay){
  while (*s) {
    printCharWithShift(*s, shiftDelay);
    s++;
  }
}

// =======================================================================

float utcOffset = -5;//GMT 5.30 
long localEpoc = 0;
long localMillisAtUpdate;

void getTime()
{
  WiFiClient client;
  if (!client.connect("www.google.com", 80)) {
    Serial.println("connection to google failed");
    return;
  }

  client.print(String("GET / HTTP/1.1\r\n") +
               String("Host: www.google.com\r\n") +
               String("Connection: close\r\n\r\n"));
  int repeatCounter = 0;
  while (!client.available() && repeatCounter < 10) 
  {
    delay(500);
    //Serial.println(".");
    repeatCounter++;
    
  }

  String line;
  client.setNoDelay(false);
  while(client.connected() && client.available()) {
    line = client.readStringUntil('\n');
    line.toUpperCase();
    if (line.startsWith("DATE: ")) {
      date = "     "+line.substring(0, 22);
      h = line.substring(23, 25).toInt();
      m = line.substring(26, 28).toInt();
      s = line.substring(29, 31).toInt();
      localMillisAtUpdate = millis();
      localEpoc = (h * 60 * 60 + m * 60 + s);
      
    }
  }
  client.stop();
}

// =======================================================================

void updateTime()
{
  long curEpoch = localEpoc + ((millis() - localMillisAtUpdate) / 1000);
  long epoch = round(curEpoch + 3600 * utcOffset + 86400L);
  h = ((epoch  % 86400L) / 3600) % 24;
  m = (epoch % 3600) / 60;
  s = epoch % 60;
}

Editado por moderador para no publicar SSID ni Password

Aquí hice un video de que es lo que me pasa para ilustrarlos mejor, esta vez la fecha la cambió alrrededor de las 19:11 Hrs al final del video.

He modificado la forma en que se obtiene la información de la hora y ahora usa un servidor NTP que es mucho mas facil de adaptar que lo que estabas usando.
En el proceso perdí alguna cosa pero lo importante esta ahi.
Revisa si funciona bien.
Yo lo probé con GMT-3 y ahora lo comenté. Quedó con -5

#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>

WiFiClient client;

String date;

#define NUM_MAX 8

// for NodeMCU 1.0
#define DIN_PIN 15  // D8
#define CS_PIN 13   // D7
#define CLK_PIN 12  // D6

#include "max7219.h"
#include "fonts.h"

// =======================================================================
// CONFIGURACIÓN:
// =======================================================================
const char* ssid = "XXXXXXXX";               // SSID de la red WiFi
const char* password = "XXXXXXXXXXX";  // Contraseña de la red WiFi

// Configuración de NTP
WiFiUDP ntpUDP;
// NTPClient timeClient(ntpUDP, "pool.ntp.org", -3 * 3600, 60000);  // UTC-3, actualización cada 60s
NTPClient timeClient(ntpUDP, "pool.ntp.org", -5 * 3600, 60000);  // UTC-3, actualización cada 60s

void setup() {
  Serial.begin(115200);
  initMAX7219();
  sendCmdAll(CMD_SHUTDOWN, 1);
  sendCmdAll(CMD_INTENSITY, 0);
  Serial.print("Conectando a WiFi ");
  delay(10);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  printStringWithShift("Connecting...... ", 25);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Conectado: ");
  Serial.println(WiFi.localIP());

  // Inicia el cliente NTP
  timeClient.begin();
}

// =======================================================================
#define MAX_DIGITS 16
byte dig[MAX_DIGITS] = { 0 };
byte digold[MAX_DIGITS] = { 0 };
byte digtrans[MAX_DIGITS] = { 0 };
int updCnt = 0;
int dots = 0;
long dotTime = 0;
long clkTime = 0;
int dx = 0;
int dy = 0;
byte del = 0;
int h, m, s;
long updateShowTime = 0;
// =======================================================================

void loop() {
  if (updCnt <= 0) {
    updCnt = 10;  // cada 10 scrolls, ~450s=7.5m
    Serial.println("Obteniendo datos...");
    printStringWithShift("Getting data....", 25);  // 25    SPEED
    getTime();
    Serial.println("Datos cargados");
    clkTime = millis();
  }

  if (millis() - clkTime > 120000 && !del && dots) {  // reloj por 40s, luego scrolls por unos 30s
    Serial.println(date.c_str());
    printStringWithShift(date.c_str(), 75);
    delay(10000);
    printStringWithShift("                    .HRB Embedded.", 75);
    delay(3000);
    updCnt--;
    clkTime = millis();
  }

  if (millis() - dotTime > 500) {
    dotTime = millis();
    dots = !dots;
  }

  // Si no muestra los datos como se espera quita las lineas que te indique con comentario QUITAR SI ES NECSARIO
  if (millis() - updateShowTime > 1000UL) {     // Quitar o solo comentar si es necesario
    updateTime();
    showSimpleClock();
    updateShowTime = millis();                  // Quitar o solo comentar si es necesario
  }                                             // Quitar o solo comentar si es necesario
}

void printStringWithShift(const char* s, int shiftDelay) {
  while (*s) {
    printCharWithShift(*s, shiftDelay);
    s++;
  }
}

// =======================================================================

void showDigit(char ch, int col, const uint8_t* data) {
  if (dy<-8 | dy> 8) return;
  int len = pgm_read_byte(data);
  int w = pgm_read_byte(data + 1 + ch * len);
  col += dx;
  for (int i = 0; i < w; i++)
    if (col + i >= 0 && col + i < 8 * NUM_MAX) {
      byte v = pgm_read_byte(data + 1 + ch * len + 1 + i);
      if (!dy) scr[col + i] = v;
      else scr[col + i] |= dy > 0 ? v >> dy : v << -dy;
    }
}

// =======================================================================

void setCol(int col, byte v) {
  if (dy<-8 | dy> 8) return;
  col += dx;
  if (col >= 0 && col < 8 * NUM_MAX)
    if (!dy) scr[col] = v;
    else scr[col] |= dy > 0 ? v >> dy : v << -dy;
}

// =======================================================================

int showChar(char ch, const uint8_t* data) {
  int len = pgm_read_byte(data);
  int i, w = pgm_read_byte(data + 1 + ch * len);
  for (i = 0; i < w; i++)
    scr[NUM_MAX * 8 + i] = pgm_read_byte(data + 1 + ch * len + 1 + i);
  scr[NUM_MAX * 8 + i] = 0;
  return w;
}

// =======================================================================

void printCharWithShift(unsigned char c, int shiftDelay) {

  if (c < ' ' || c > '~' + 25) return;
  c -= 32;
  int w = showChar(c, font);
  for (int i = 0; i < w + 1; i++) {
    delay(shiftDelay);
    scrollLeft();
    refreshAll();
  }
}

// =======================================================================

void showSimpleClock() {
  dx = dy = 0;
  clr();
  showDigit(h / 10, 1, dig6x8);
  showDigit(h % 10, 9, dig6x8);
  showDigit(m / 10, 18, dig6x8);
  showDigit(m % 10, 26, dig6x8);
  showDigit(s / 10, 49, dig6x8);
  showDigit(s % 10, 49, dig6x8);
  Serial.printf("%02d:%02d:%02d\n", h, m, s);
  setCol(16, dots ? B00100100 : 0);
  setCol(33, dots ? B00100100 : 0);
  refreshAll();
}

// =======================================================================

void getTime() {
  // Actualiza la hora desde el servidor NTP
  timeClient.update();
  
  // Extrae la hora actual en segundos desde 1970
  long epochTime = timeClient.getEpochTime();
  
  // Convierte la hora en formato h, m, s
  h = (epochTime % 86400L) / 3600;
  m = (epochTime % 3600) / 60;
  s = epochTime % 60;

  // Formatear la fecha como dd/mm/yyyy
  String formattedDate = timeClient.getFormattedTime();
  date = "     " + formattedDate;
  
  Serial.printf("Hora obtenida: %02d:%02d:%02d\n", h, m, s);
}

// =======================================================================

void updateTime() {
  // Calcula el tiempo local basado en los datos del NTPClient
  long curEpoch = timeClient.getEpochTime();
  
  // Convierte a horas, minutos y segundos
  h = (curEpoch % 86400L) / 3600;
  m = (curEpoch % 3600) / 60;
  s = curEpoch % 60;
}


Repito debería andar mas o menos bien la hora y fecha, aunque no es exactamente como antes.

Hi
Yo uso un GPS GY-NEO6MV2 modulo para leer la hora sin problemas. La library ya tiene el commando para leer la fecha. El modulo vale un peso en Aliexpress/

Te invito a que lo cambies @tauro0221 te aseguro que me dió un trabajito ponerle NTPClient que no es por nada, me parece de lo mejor. Lo que sugieres esta bien pero requiere el modulo NEO6

Agrego a lo que dice @Surbyte :

Y no estar en interiores... :wink:

Coincido totalmente en que lo mejor es usar un servidor NTP (que pa'eso son :grin:)

Hi,
El problema de usar ntp es que sino me equivoco nesecita un server y el gps no se nececita un server ya que el module de gps se comunica directamente al satelite.para leer la informacion. Yo leeo la hora y la fecha para un reloj digital de un solo dijito para dar la hora, la humedad y temperatura de la habitacion.. Tambien da la hora verbalmente en espanol usando un mp3
player.

Si el PO lee la hora de Google entonces tiene conectividad y lo único que tiene que hacer es consultar la hora a un servidor NTP en lugar de "capturarla" de Google.

Por otro lado, el módulo GPS también puede servir (de hecho muchos servidores NTP se sincronizan con la señal GPS) pero en este caso sería más sencillo usar un RTC y listo.

Hi,
Yo tambien uso un reloj ds1307 para mantener la hora en caso de que el gps falle. Comparo la hora y si eata feuera de la hora del gps le doy update al ds1307. El proposito es de que si el ds1307 pierde o se adelante uso la hora del gps para adjustarlo.

Muchas gracias a todos por sus aportes, creo que lo haré con NTP ya lo habia pensado pero queria rescatar este. Muchas gracias a todos nuevamente. demos por cerrado este caso.