Obtener la fecha y hora del servidor NTP con ESP32


De vez en cuando se encontrará con una idea en la que mantener el tiempo es una preocupación principal. Por ejemplo, imagine un relé que debe activarse en un momento determinado o un registrador de datos que debe almacenar valores en intervalos precisos.

Lo primero que se te viene a la mente es usar un chip RTC (Real Time Clock). Pero estos chips no son perfectamente precisos, por lo que debe realizar ajustes manuales una y otra vez para mantenerlos sincronizados.

La solución aquí es usar Network Time Protocol (NTP). Si su proyecto ESP32 tiene acceso a Internet, puede obtener la fecha y la hora (con una precisión de unos pocos milisegundos de UTC) GRATIS . No necesita ningún hardware adicional.

¿Qué es NTP?

Un NTP significa Network Time Protocol . Es un Protocolo de Internet (IP) estándar para sincronizar los relojes de la computadora con alguna referencia a través de una red.

El protocolo se puede usar para sincronizar todos los dispositivos en red con el tiempo universal coordinado (UTC) en unos pocos milisegundos (50 milisegundos en la Internet pública y menos de 5 milisegundos en un entorno LAN).

El tiempo universal coordinado (UTC) es un estándar de tiempo mundial, estrechamente relacionado con GMT (hora del meridiano de Greenwich). UTC no varía, es el mismo en todo el mundo.

NTP establece los relojes de las computadoras en UTC, el cliente aplica cualquier compensación de zona horaria local o compensación de horario de verano. De esta manera, los clientes pueden sincronizarse con los servidores independientemente de las diferencias de ubicación y zona horaria.

Arquitectura NTP

NTP utiliza una arquitectura jerárquica. Cada nivel de la jerarquía se conoce como estrato .

En la parte superior se encuentran los dispositivos de cronometraje de alta precisión, como relojes atómicos, GPS o relojes de radio, conocidos como relojes de hardware de estrato

Los servidores Stratum 1 tienen una conexión directa a un reloj de hardware stratum 0 y, por lo tanto, tienen la hora más precisa.

Arquitectura jerárquica NTP con estratos

Cada estrato en la jerarquía se sincroniza con el estrato superior y actúa como servidor para las computadoras del estrato inferior.

¿Cómo funciona NTP?

NTP puede funcionar de varias maneras. La configuración más habitual es la de operar en modo cliente-servidor . El principio básico de funcionamiento es el siguiente:

  1. El dispositivo cliente, como ESP32, se conecta al servidor mediante el Protocolo de datagramas de usuario (UDP) en el puerto 123.
  2. Luego, un cliente transmite un paquete de solicitud a un servidor NTP.
  3. En respuesta a esta solicitud, el servidor NTP envía un paquete de marca de tiempo.
  4. Un paquete de marca de tiempo contiene información múltiple, como la marca de tiempo UNIX, la precisión, el retraso o la zona horaria.
  5. Luego, un cliente puede analizar los valores de fecha y hora actuales.
Funcionamiento del servidor NTP: transferencia de paquetes de solicitud y marca de tiempo

Obtener fecha y hora del servidor NTP

El siguiente esquema le brindará una comprensión completa de cómo obtener la fecha y la hora del servidor NTP.

Antes de subir el boceto, debe realizar algunos cambios para que funcione para usted.

  • Debe modificar las siguientes dos variables con sus credenciales de red, para que ESP32 pueda establecer una conexión con la red existente.const char* ssid = "YOUR_SSID"; const char* password = "YOUR_PASS";
  • Debe ajustar el desplazamiento UTC para su zona horaria en milisegundos. Consulte la lista de compensaciones de tiempo UTC . Aquí hay algunos ejemplos para diferentes zonas horarias:
    • Para UTC -5.00 : -5 * 60 * 60 : -18000
    • Para UTC +1.00 : 1 * 60 * 60 : 3600
    • Para UTC +0.00 : 0 * 60 * 60 : 0
    const long gmtOffset_sec = 3600;
  • Cambie la compensación de la luz del día en milisegundos. Si su país observa el horario de verano , configúrelo en 3600. De lo contrario, configúrelo en 0.const int daylightOffset_sec = 3600;

Una vez que haya terminado, continúe y pruebe el boceto.

#include <WiFi.h>
#include "time.h"

const char* ssid       = "YOUR_SSID";
const char* password   = "YOUR_PASS";

const char* ntpServer = "pool.ntp.org";
const long  gmtOffset_sec = 3600;
const int   daylightOffset_sec = 3600;

void printLocalTime()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}

void setup()
{
  Serial.begin(115200);
  
  //connect to WiFi
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  Serial.println(" CONNECTED");
  
  //init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();

  //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
}

void loop()
{
  delay(1000);
  printLocalTime();
}

Después de cargar el boceto, presione el botón EN en su ESP32 y debería obtener la fecha y la hora cada segundo, como se muestra a continuación.

ESP32 lee la fecha y la hora de la salida del servidor NTP en el monitor serie

Código Explicación

Echemos un vistazo rápido al código para ver cómo funciona. Primero, incluimos las bibliotecas necesarias para este proyecto.

  • La biblioteca WiFi.h proporciona métodos WiFi específicos de ESP32 que llamamos para conectarse a la red.
  • time.h es la biblioteca de tiempo nativo de ESP32 que realiza una sincronización elegante del servidor NTP.
#include <WiFi.h>
#include "time.h"

A continuación, configuramos algunas constantes como SSID, contraseña WiFi, UTC Offset y Daylight offset que ya conoce.

Junto con eso, debemos especificar la dirección del servidor NTP que deseamos usar. pool.ntp.org es un proyecto NTP abierto ideal para cosas como esta.

const char* ntpServer = "pool.ntp.org";

El pool.ntp.org selecciona automáticamente los servidores de tiempo que están geográficamente cerca de usted. Pero si desea elegir explícitamente, use una de las subzonas de pool.ntp.org.

ÁreaNombre de host
En todo el mundopiscina.ntp.org
Asiaasia.pool.ntp.org
Europaeuropa.pool.ntp.org
América del nortenorteamerica.pool.ntp.org
Oceaníaoceania.pool.ntp.org
Sudamericasudamerica.pool.ntp.org

En la sección de configuración, primero inicializamos la comunicación en serie con la PC y nos unimos a la red WiFi usando la WiFi.begin()función.

Serial.begin(115200);

//connect to WiFi
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println(" CONNECTED");

Una vez que ESP32 está conectado a la red, inicializamos el cliente NTP usando la configTime()función para obtener la fecha y la hora de un servidor NTP.

//init and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);

Ahora podemos simplemente llamar a la printLocalTime()función personalizada cada vez que queramos imprimir la fecha y hora actuales.

getLocalTime()La función se utiliza para transmitir un paquete de solicitud a un servidor NTP y analizar el paquete de marca de tiempo recibido en un formato legible. Toma la estructura del tiempo como parámetro.

Puede acceder a la información de fecha y hora accediendo a los miembros de esta estructura de tiempo.

%Adevuelve el día de la semana
%Bdevuelve el mes del año
%ddevuelve el día del mes
% Yaño de retorno
%Hhora de regreso
%Mdevuelve minutos
%Sdevuelve segundos
void printLocalTime()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
}

Cómo usar un módulo de reloj en tiempo real (DS3231)


Antes de nada, debería saber qué es un RTC (Real Time Clock), o reloj de tiempo real. Estos chips son muy frecuentes en multitud de aplicaciones, de hecho, cualquier PC tiene uno de ellos en la placa base, y está alimentado también por una pila CR2032 también, que por cierto es la que mantiene la hora y la configuración en el BIOS/UEFI y del que la coge el sistema operativo al arrancar para estar en hora (aunque ahora, con Internet, se puede usar la sincronización con servidores para mayor precisión, pero esto es otra historia…).

El RTC pues ,lo que hace es obtener mediciones de tiempo, así de simple. La diferencia con otros tipos de relojes electrónicos es que simplemente mide el tiempo, y lo hace contabilizando pulsos de señal de reloj, sabiendo la frecuencia y periodos de la misma. Además de la hora, un RTC también permite llevar una contabilidad de los días, semanas, meses y años. Es decir, la fecha completa…

En el caso del Time Clock Module (o DS3231) es un módulo que mide el tiempo, dependiente o independientemente de su tarjeta Arduino ( o derivado ) a través de su propia electrónica especializada consistente en el DS3231 acompañado de un Xtal o cristal de cuarzo que actuará como resonador, el que aporta la frecuencia. Adicionalmente, tambien se necesita una circuitería electrónica capaz de llevar el recuento y almacenar la fecha en una memoria. La circuitería debe ser capaz de contabilizar segundos, minutos, horas, días, semanas, meses y años.

Esa memoria es volátil, por eso necesita de la pila, para tener alimentación constante. Si no tiene pila o se agota, se borrará… Eso es lo que le ocurre a los PCs cuando se le agota la pila, dan una hora incorrecta. Si la configuras mientras el PC está encendido, la hora se mantendrá, ya que el RTC se está alimentando, pero es durante los procesos durante los que está apagado cuando se necesita de esa batería.

En cuanto a la forma de comunicarse con el RTC DS3131 para obtener los valores de fecha que consigue, se hace mediante bus I2C. Y para la alimentación, puedes usar 2.3 a 5.5v para el DS3231, lo que es algo más bajo que los 4.5 a 5.5v del DS1307, por lo que puede ser más eficiente energéticamente y hacer que la pila dure más.

Además, debe saber que estos módulos suelen tener una EEPROM adicional AT24C32 para almacenar algunos registros y mediciones previas, lo que es bastante práctico.

En el caso de usarlo con Arduino, la tarjeta Arduino mide el tiempo transcurrido desde que se encendió el módulo (en ms) y el módulo viene ensamblado listo para usar, con batería (suministrada).

Código

El código ha sido realizado por Gilles Thebault: http://gilles.thebault.free.fr/spip.php?article53

Biblioteca

El código necesita la biblioteca «Wire», que ya está en la tarjeta. Así que no tiene que descargarlo.

También necesitará la biblioteca «ds3231»: https://github.com/rodan/ds3231&nbsp;.

Conexiones

CÓDIGO

Arduino DS3231

Este código mostrará valores en el monitor serie.

#include <Wire.h>
#include <ds3231.h>
 
struct ts t; 
 
void setup ()  {
  Serial.begin ( 9600 ) ;
  Wire.begin () ;
  DS3231_init ( DS3231_CONTROL_INTCN ) ;
  /*------------------------------------------------ ----------------------------
  ¡Para sincronizar su módulo de reloj, inserte los valores de horario a continuación!
  -------------------------------------------------- --------------------------*/
  t.hour=12; 
  t.min=30;
  t.sec=0;
  t.mday=25;
  t.mon=12;
  t.year=2019;
 
  DS3231_set ( t ) ; 
}
 
void loop vacío ()  {
  DS3231_get ( & t ) ;
  Serial.print ( "Fecha:" ) ;
  Serial.print ( t.mday ) ;
  Serial.print ( "/" ) ;
  Serial.print ( t.mon ) ;
  Serial.print ( "/" ) ;
  Serial.print ( t.year ) ;
  Serial.print ( "\t Hora:" ) ;
  Serial.print ( t.hour ) ;
  Serial.print ( ":" ) ;
  Serial.print ( t.min ) ;
  Serial.print ( "." ) ;
  Serial.println ( t.seg ) ;
 
  delay ( 1000 ) ;
}