J008 ESP32 Sincronizando la hora con internet

Despcripción
El protocolo NTP
La sincronización entre los relojes de diferentes sistemas informáticos, en principio parece sencilla, pero se puede complicar de formas insospechadas, porque al final todo es una cuestión de la precisión con la que necesitemos esa sincronización.

Hay una norma de sincronización en red llamada NTP por sus siglas de Network Time Protocolo, o Protocolo de Tiempo en Red.

La idea básica es un conjunto de relojes en Internet sincronizados con un reloj de máxima precisión, como GPS o reloj atómico, que llamaremos de estrato 1.

A su vez este grupo sincroniza a un segundo grupo de relojes de menor nivel que llamaremos de estrato 2 y así sucesivamente hasta llegar a los estratos de gran público.

La ventaja de este sistema, es que todos los relojes se sincronizan contra una hora estándar central y los errores que se generan no serán acumulativos.

Como la idea de fondo es enviar un mensaje solicitando la hora a un servidor central, que nos responde con la hora exacta… de cuando envió el mensaje, se pueden hacer ajustes calculando este retraso para mayor exactitud del valor, pero en la mayor parte de las aplicaciones civiles, basta con una precisión de algunos milisegundos.Si se repite la sincronización periódicamente, no habrá deriva de la hora, evitando la acumulación de errores.

Por eso, para la mayor parte de las aplicaciones normales, en las que podemos ignorar estas pequeñas diferencias, se desarrolló un protocolo simple de NTP que se llamó SNTP, con la S de simple, y que es el que más uso general tiene, pues evita la complicación de calcular los retrasos estadísticos y su corrección, y se conforma con el tiempo que recibe.

Destacar que el protocolo NTP y SNTP se implementa en UDP que un protocolo de transporte diferente a TCP/IP, que también corre sobre Ethernet y Arduino soporta con una librería.

Las firmas de tiempo que se usan en NTP, son de 32 bits indicando la parte entera en segundos, que cuentan desde  el 1 de Enero de 1900, y una parte fraccionaria también de 32 bits. 

Por ello la resolución teórica de NTP sería de 232 segundos =136 años y una resolución teórica de 2-32  segundos, o sea 0,233 nanosegundos.

La norma define una colección de mensajes para interrogar a un servidor NTP y especifica las respuestas de vuelta. Utilizaremos esta norma para poner en hora el  Arduino a través de una petición UDP a un servidor NTP.

Materiales
Placa ESP32
Placa ES
Cable USB para conectar la placa ESP32 al PC y que además siver de alimentación a la propia placa.

Esquema 
No hay esquema

Montaje
No hay montaje

Código
El siguiente código es para un ESP32. Sirve para poner el ESP en hora desde internet.

Incluye la biblioteca WiFi del ESP32.
Permite usar funciones como:
WiFi.begin(), WiFi.status(), WiFi.disconnect(), WiFi.localIP(), WiFi.mode(),WiFi.scanNetworks()
#include <WiFi.h>

Incluye las funciones de fecha y hora del sistema ESP32.
Permite usar:
configTime(), getLocalTime(), time(), localtime(), gmtime()
#include "time.h"

Declara un puntero constante a una cadena de caracteres.
Contiene el nombre (SSID) de la red WiFi a la que se conectará el ESP32.
Puede ser cualquier nombre de red válido.
const char* ssid = "Nombre de la red wifi";

Declara un puntero constante a una cadena de caracteres.
Contiene la contraseña de la red WiFi.
Puede ser cualquier contraseña válida para la red indicada.
const char* password = "Contraseña de la red wifi";

Declara un puntero constante a una cadena de caracteres.
Contiene el nombre del servidor NTP.
Algunos ejemplos posibles:
"pool.ntp.org", "es.pool.ntp.org", "time.google.com", "time.windows.com", "time.nist.gov"
const char* ntpServer = "pool.ntp.org";

Define el desplazamiento horario respecto a UTC en segundos.
UTC = 0
España invierno = 3600
España verano (si no se usa daylightOffset_sec) = 7200
Canarias invierno = 0
Canarias verano = 3600
const long gmtOffset_sec = 3600;

Define el ajuste adicional por horario de verano.
Normalmente:
0 -> sin horario de verano
3600 -> añadir una hora
const int daylightOffset_sec = 3600;

Función setup.

Arduino la ejecuta una sola vez al arrancar o reiniciar.
No admite parámetros.
No devuelve ningún valor porque es void.
void setup(){

Inicializa la comunicación serie.

Velocidades habituales: 9600 o más comunmente 115200
Serial.begin(115200);

Inicia la conexión WiFi.
Parámetro 1:
ssid -> nombre de la red
Parámetro 2:
password -> contraseña
Sobrecargas:
WiFi.begin();, WiFi.begin(ssid);, WiFi.begin(ssid,password);
WiFi.begin(ssid, password);

Bucle que se ejecuta mientras NO exista conexión WiFi.
WiFi.status() devuelve un valor wl_status_t.
Valores posibles:
WL_IDLE_STATUS
WL_NO_SSID_AVAIL
WL_SCAN_COMPLETED
WL_CONNECTED
WL_CONNECT_FAILED
WL_CONNECTION_LOST
WL_DISCONNECTED
El operador != significa "distinto de".
while (WiFi.status() != WL_CONNECTED){

Detiene la ejecución durante 500 milisegundos.

delay(500);

Imprime un punto en el monitor serie.
print() no añade salto de línea.
Puede imprimir:
texto, enteros, flotantes, caracteres, cadenas
Serial.print(".");
  }

Imprime un salto de línea.
println() siempre termina con CR+LF.
Equivale a pasar a la línea siguiente.
Serial.println();

Imprime el texto indicado y después añade salto de línea.
Serial.println("WiFi conectada");

Configura el sistema horario del ESP32.
Parámetro 1:
desplazamiento respecto UTC.
Parámetro 2:
corrección horario verano.
Parámetro 3:
servidor NTP.
configTime(gmtOffset_sec,
             daylightOffset_sec,
             ntpServer);
}

Función loop.
Arduino la ejecuta continuamente.
Cuando termina vuelve a empezar.
No admite parámetros.
No devuelve valor.
void loop(){

Declara una estructura tm.

Contendrá:
año, mes, día, hora, minuto, segundo, día de la semana, día del año
Campos principales:
tm_sec
tm_min
tm_hour
tm_mday
tm_mon
tm_year
tm_wday
tm_yday
tm_isdst
struct tm timeinfo;

Obtiene la hora local.
Parámetro:
&timeinfo
El operador & significa "dirección de memoria de".
La función devuelve:
true -> hora obtenida correctamente
false -> error
if (getLocalTime(&timeinfo)){
   
Imprime la fecha y hora usando una máscara de formato.
Parámetro 1:
&timeinfo
Dirección de la estructura tm.
Parámetro 2:
Cadena de formato.
Códigos más habituales:
%d -> día del mes (01-31)
%m -> mes (01-12)
%Y -> año completo (2026)
 %y -> año corto (26)
%H -> hora 00-23
%I -> hora 01-12
%M -> minutos
%S -> segundos
%A -> nombre completo del día
%a -> nombre abreviado del día
%B -> nombre completo del mes
%b -> nombre abreviado del mes
%j -> día del año
%w -> día de la semana
%% -> carácter %
Serial.println(&timeinfo,
   
Formato de salida:
%d -> día
/
%m -> mes
/
%Y -> año
espacio
%H -> hora
:
%M -> minutos
:
%S -> segundos
"%d/%m/%Y %H:%M:%S");
  }

Espera 1000 milisegundos.
Equivale a 1 segundo.
delay(1000);
}

Aqui tienes el código completo

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

const char* ssid = "MOVISTAR_D182";
const char* password = "Cme8WCaJZAexdvHDtlod";

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

void setup(){
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi conectada");
  configTime(gmtOffset_sec,
             daylightOffset_sec,
             ntpServer);
}

void loop(){
  struct tm timeinfo;
  if (getLocalTime(&timeinfo)){
    Serial.println(&timeinfo,
    "%d/%m/%Y %H:%M:%S");
  }
  delay(1000);
}
El programa de interrogación NTP
 


No hay comentarios:

Publicar un comentario