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 un 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");
}

Archivos de alojamiento en el servidor web ESP32 desde la tarjeta MicroSD


En este post vamos a construir un servidor web ESP32 para servir archivos desde una tarjeta microSD usando un módulo de tarjeta microSD, el cual se comunicara usando el protocolo SPI sirviendo sus archivos HTML, CSS, JavaScript, imágenes y otros activos guardados en la tarjeta microSD. Esto puede ser especialmente útil si sus archivos son demasiado grandes para caber en el sistema de archivos (SPIFFS), o también puede ser más conveniente según su proyecto. Para construir el servidor web, usaremos la biblioteca ESPAsyncWebServer.

Archivos de alojamiento del servidor web ESP32 desde la tarjeta MicroSD

Descripción del proyecto

Para mostrarle cómo crear un servidor web con archivos de una tarjeta microSD, crearemos una página HTML simple que muestra texto formateado con CSS. También serviremos un favicon. La siguiente imagen muestra la página web que serviremos:

Servidor web ESP32 con archivos desde tarjeta microSD
  • El servidor web se construye utilizando la biblioteca ESPAsyncWebServer ;
  • Los archivos HTML, CSS y favicon se guardan en la tarjeta microSD;
  • La tarjeta microSD se comunica con el ESP32 a través del protocolo de comunicación SPI;
  • Cuando el cliente realiza una solicitud al ESP32, este sirve los archivos guardados en la tarjeta microSD;
Servidor web ESP32 con archivos de tarjeta microSD Cómo funciona

Módulo de tarjeta MicroSD

Existen diferentes módulos de tarjetas microSD compatibles con el ESP32. Estamos utilizando el módulo de tarjeta microSD que se muestra en la siguiente figura el cual se comunica mediante el protocolo de comunicación SPI. Puede usar cualquier otro módulo de tarjeta microSD con una interfaz SPI.

Módulo de tarjeta microSD para ESP32 ESP8266 Arduino SPI

Asignación de pines del módulo de la tarjeta MicroSD

El módulo de la tarjeta microSD se comunica mediante el protocolo de comunicación SPI. Usaremos los pines SPI ESP32 predeterminados como se muestra en la siguiente tabla:

módulo de tarjeta microSDESP32
3V33,3 V
CSGPIO5
MOSIGPIO23
CLKGPIO18
MISOGPIO19
TIERRATIERRA

Preparación de la tarjeta MicroSD

Antes de continuar , asegúrese de formatear su tarjeta microSD como FAT32 . Siga las siguientes instrucciones para formatear su tarjeta microSD o use una herramienta de software como SD Card Formater (compatible con Windows y Mac OS).

1.  Inserte la tarjeta microSD en su computadora. Vaya a  Mi PC  y haga clic derecho en la tarjeta SD. Seleccione  Formato  como se muestra en la figura a continuación.

Preparación de la tarjeta MicroSD Formato de tarjeta microSD

2.  Aparece una nueva ventana. Seleccione  FAT32 , presione  Iniciar  para iniciar el proceso de formateo y siga las instrucciones en pantalla.

Preparación de la tarjeta MicroSD Formato de tarjeta microSD

Después de formatear la tarjeta microSD, puede pegar allí los archivos utilizados para construir el servidor web, moveremos los ficheros index.html,estilo.css, y favicon.png a allí. Siga la siguiente sección para obtener sus archivos.

Archivo HTML

Crea un archivo llamado index.html con el siguiente contenido:

<!DOCTYPE HTML><html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" type="text/css" href="style.css">
  <link rel="icon"  type="image/png" href="favicon.png">
  <title>ESP Web Server</title>
</head>
<body>
  <h1>Hello World!</h1>
  <p>This page was built with files from a microSD card.</p>
</body>
</html>

Archivo CSS

Crea un archivo llamado style.css con el siguiente contenido:

html {
    font-family: Arial; 
    text-align: center;
}
body {
    max-width: 400px; 
    margin:0px auto;
}

icono de favoritos

También serviremos un favicon. Es una imagen png de 15×15 píxeles. Puede usar el mismo favicon que el nuestro, o su propio ícono, o ningún favicon.

Puede hacer clic en el siguiente enlace para descargar el favicon:

Copiar archivos a la tarjeta MicroSD

Después de tener todos los archivos preparados, abra el directorio de la tarjeta microSD y pegue los archivos.

Carpeta de tarjeta microSD con archivos para construir servidor web

Piezas necesarias

Placa de pruebas de cableado del módulo de tarjeta microSD ESP32

Para este cometido necesitamos las siguientes partes:

  • ESP32  
  • Módulo de tarjeta microSD
  • Tarjeta micro SD
  • Tablero de circuitos
  • Cables puente

Diagrama esquemático

Conecte el módulo de la tarjeta microSD al ESP32 como se muestra en el siguiente diagrama esquemático, donde como vemos alimentamos desde el ESP32 al lector de tarjetas y usaremos los pines SPI del ESP32 predeterminados ( GPIOS 5,23,18 Y 19) tal y como se ha expuesto en la sección anterior.

Diagrama de cableado del módulo de tarjeta microSD ESP32

Código

Copie el siguiente código en su IDE de Arduino.

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-web-server-microsd-card/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "FS.h"
#include "SD.h"
#include "SPI.h"

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

void initSDCard(){
  if(!SD.begin()){
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD.cardType();

  if(cardType == CARD_NONE){
    Serial.println("No SD card attached");
    return;
  }

  Serial.print("SD Card Type: ");
  if(cardType == CARD_MMC){
    Serial.println("MMC");
  } else if(cardType == CARD_SD){
    Serial.println("SDSC");
  } else if(cardType == CARD_SDHC){
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);
}

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void setup() {
  Serial.begin(115200);
  initWiFi();
  initSDCard();

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SD, "/index.html", "text/html");
  });

  server.serveStatic("/", SD, "/");

  server.begin();
}

void loop() {
  
}

Obviamente debe insertar sus credenciales de red en las siguientes variables y el código debería funcionar de inmediato:

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Cómo funciona el código

Primero, asegúrese de incluir las bibliotecas FS.h,SD.h y SPI. h para poder comunicarse con la tarjeta microSD y manejar archivos.

#include "FS.h"
#include "SD.h"
#include "SPI.h"

Inicializar tarjeta MicroSD

losinitSDCard() es la función que inicializa la tarjeta microSD en los pines SPI predeterminados.

void initSDCard(){
  if(!SD.begin()){
    Serial.println("Card Mount Failed");
    return;
  }
  uint8_t cardType = SD.cardType();

  if(cardType == CARD_NONE){
    Serial.println("No SD card attached");
    return;
  }
  Serial.print("SD Card Type: ");
  if(cardType == CARD_MMC){
    Serial.println("MMC");
  } else if(cardType == CARD_SD){
    Serial.println("SDSC");
  } else if(cardType == CARD_SDHC){
    Serial.println("SDHC");
  } else {
    Serial.println("UNKNOWN");
  }
  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);
}

Luego, debe llamar a esta función en la configuración():

initSDCard();

Servir archivos desde la tarjeta microSD

Cuando accede a la dirección IP ESP32 en la raíz (/) URL, envíe el archivo HTML guardado en la tarjeta microSD.

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(SD, "/index.html", "text/html");
});

El primer argumento de la función de enviar() es el sistema de archivos donde se guardan los archivos. En este caso, se guarda en la tarjeta SD. El segundo argumento es la ruta donde se encuentra el archivo.(/index.html). El tercer argumento se refiere al tipo de contenido (texto/html).

Cuando el archivo HTML se cargue en su navegador, solicitará los archivos CSS y favicon. Estos son archivos estáticos guardados en el mismo directorio . Podemos agregar la siguiente línea para servir archivos estáticos en un directorio cuando lo solicite la URL raíz. Sirve los archivos CSS y favicon automáticamente.

server.serveStatic("/", SD, "/");

Si su servidor web necesita manejar más rutas, puede agregarlas a la configuración(). No olvide configurar SD como primer argumento de la función enviar(). De esta forma, buscará los archivos en la tarjeta microSD.

Es tan simple como esto. Esto se puede aplicar a cualquier otro proyecto de servidor web.

Demostración

Después de cargar el código, abra el monitor en serie a una velocidad de transmisión de 115200. Presione el botón RST integrado.

Debería obtener algo similar en el Serial Monitor: la dirección IP ESP32 e información sobre la tarjeta microSD.

Servidor web con archivos de la tarjeta MicroSD Dirección IP del monitor serie

Abra un navegador en su red local y pegue la dirección IP ESP32. Cargará la siguiente página web con los archivos guardados en la tarjeta microSD. Observe el icono de favoritos en la barra de título del navegador web.

Servidor web ESP32 con archivos desde tarjeta microSD