Domotiza tu casa – Día 5. El tiempo, protocolo NTP

Ahora que ya hemos hecho una estructura sencilla para nuestra web (podeis irla decorando con vuestros colores etc mientras os preparo algo más bonito), vamos pronto a ir trabajando con los datos de los sensores.

Pero antes de empezar a recibir datos de los sensores, necesitaremos dos cosas, el tiempo y almacenamiento (el próximo tutorial).

Dado que cada vez que se ejecuta el código que tenemos en arduino se reinician todas las variables, necesitamos conocer el tiempo a través de un medio externo.

Por suerte, tenemos el protocolo NTP (Network Time Protocol), uno de los protocolos más antiguos de internet (estaba incluso antes del 1985), que se creó para sincronizar la hora de los sistemas informáticos.

Este protocolo nos dará una precisión de milisegundos. Esto es mucho más de lo que necesitamos para controlar el riego o programar tareas 🙂 Si quereis más información acerca de este protocolo, lo podeis encontrar aquí :http://es.wikipedia.org/wiki/Network_Time_Protocol

A lo que íbamos. Si queremos programar un riego, saber a qué hora ha saltado una alarma, y mil cosas más en las que tenemos que comprobar la hora, necesitamos esta función.

Esta función nos devolverá un número, este número a simple vista no nos permite saber qué hora es, ya que ese número son los segundos que han pasado desde el 1 de enero de 1900.

Por lo tanto utilizaremos la librería de tiempo Time, la cual debereis importar en Sketch>Import Library>Time

Libreria Time
Libreria Time

Esta libreria consta de las funciones necesarias para manejar este número que a simple vista no sabríamos entender.

La idea entonces es la siguiente:

– Obtener la hora del servidor NTP

– Traducir la hora obtenida al formato humano

 

Empecemos a programar!!

Os pongo el código y lo voy comentando detalladamente:

//Declaramos las variables e incluimos librerias

 

#include <Time.h>

#include <SD.h>

#include <SPI.h>

#include <Udp.h>

#include <Ethernet.h>
#define BUFSIZ 100;

/************ ETHERNET CONFIG ************/
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //definimos la MAC
byte ip[] = { 192, 168, 1, 177 };//definimos la IP
String ipString = “192.168.1.177”; //IP en formato String (para pruebas)
Server server = Server(80);// definimos el puerto para las peticiones web
unsigned int localPort = 8888;
byte timeServer[] = {
192, 43, 244, 18}; // IP de time.nist.gov es el servidor NTP utilizado
const int NTP_PACKET_SIZE= 48; // El paquete de tiempo NTP  que recibimos está en los primeros 48 bytes del paquete como podreis ver en la wikipedia

byte packetBuffer[ NTP_PACKET_SIZE]; //buffer para paquetes entrantes y salientes

void setup() {
/* Inicializando Serial para debug */
Serial.begin(9600);
/* Inicialiciando ethernet y server */
Ethernet.begin(mac, ip);
server.begin();
Udp.begin(localPort);

}

void loop()
{

//Aquí va el código del anterior tutorial, el cual me saltaré para centrarnos en lo que nos interesa hoy
String clientline= “”;

…..

header(client, modulo);
body(client, modulo);
pie(client);
client.stop();
delay(1000);
}
}
}
}
void header(Client client, String title){
… el código de la cabecera…
}
String modulos(Client client){
…el código del menú lateral…
}
void body(Client client, String modulo){
… el código del cuerpo de la página…
}

void pie(Client client){
String hora = “”; //definimos la variable de la hora
hora = timestamp(); //llamamos a la función que nos devolverá la hora y asignamos el valor a la anterior variable
client.println(“la hora es: –>” + hora + “<–“); //Mostramos la hora en la web
client.print(“</body></html>”);//cerramos la estructura HTML
}

//Esta es la función para obtener el tiempo y entregar la hora

String timestamp(){
String timestamp = “”;
sendNTPpacket(timeServer); // enviamos un paquete NTP al servidor de tiempo (ver la función más abajo)
delay(500);  //esperamos una respuesta…
if ( Udp.available() ) {  //si recibimos paquete…
Udp.readPacket(packetBuffer,NTP_PACKET_SIZE);  // leemos el paquete del buffer

//El número que nos interesa empieza en el byte 40 del paquete recibido y ocupa 4 bytes, que son dos words. Vamos a extraerlos:
// or two words, long. First, esxtract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combinamos estos dos enteros en un entero largo (Long Integer), que será el tiempo que nos ha devuelto el servidor NTP
unsigned long secsSince1900 = highWord << 16 | lowWord;
//Ahora vamos a convertir el tiempo que nos ha dado el servidor NTP, en tiempo de UNIX, que empieza el 1 de enero de 1970. 70 años de diferencia, que son 2208988800 (veis como era un poco dificil de saber a ojo y que habia que convertir el valor… 😉   )

const unsigned long seventyYears = 2208988800UL;
//restamos 70 años
unsigned long epoch = secsSince1900 – seventyYears;

//Y aquí en la variable “timestamp” creamos una cadena de fecha en formato “dia/mes/año hora:minuto”. Tenemos el tiempo en la variable epoch, y de ahí con las funciones de la librería Time(day, month, year, hour, minute, second) obtenemos los datos que nos van interesando

timestamp = String(day(epoch)) + “/” + String(month(epoch)) + “/” + String(year(epoch)) + ” ” + String(hour(epoch)+2) + “:” + String(minute(epoch)) + “:” + String(second(epoch));
}
return (timestamp);
}

// enviamos una petición NTP al servidor del tiempo en la dirección que nos llega como parámetro
unsigned long sendNTPpacket(byte *address)
{
// ponemos todos los bytes del buffer a 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Inicializamos los valores necesarios para una petición NTP

packetBuffer[0] = 0b11100011;
packetBuffer[1] = 0;
packetBuffer[2] = 6;
packetBuffer[3] = 0xEC;

packetBuffer[12]  = 49;
packetBuffer[13]  = 0x4E;
packetBuffer[14]  = 49;
packetBuffer[15]  = 52;

//todos los campos del paquete NTP tienen valor. Ahora ya lo podemos enviar para solicitar el tiempo al servidor indicado y al puerto 123
Udp.sendPacket( packetBuffer,NTP_PACKET_SIZE,  address, 123); //NTP requests are to port 123
}

 

Espero que os haya sido de interés, de momento vamos preparandonos las funciones que iremos necesitando. En el próximo tutorial veremos como ir almacenando datos en una tarjeta microSD, y nos encontraremos con nuevos problemas…. 🙂

Hasta pronto!

6 Replies to “Domotiza tu casa – Día 5. El tiempo, protocolo NTP”

  1. Hola pedro:

    intento compilar el código y me da un error en la linea

    unsigned long epoch = secsSince1900 – seventyYears;

    ERROR

    sketch_oct29a:167: error: stray ” in program
    sketch_oct29a.cpp: In function ‘void loop()’:
    sketch_oct29a:52: error: ‘index’ was not declared in this scope
    sketch_oct29a.cpp: In function ‘String timestamp()’:
    sketch_oct29a:167: error: expected ‘,’ or ‘;’ before ‘u2013’

    Sabes a puede ser debido??

    Gracias y muy buen trabajo.

  2. En principio podria ser que te hubieras dejado algún “;” o que no este declarada la funcion index. ¿Has copiado y pegado este codigo o has modificado algo?

  3. Hola. He llegado a esta web después de haber visitado unas cuantas… …
    Tengo un proyectillo para controlar un par de persianas, la calefacción y una lámpara (de momento), y en lo que estoy ahora, es en programar la subida y la bajada de las persianas (y el encendido de la lámpara, para simular que estoy en casa cuando estoy de vacaciones).

    Bueno, la parte de programación de las persianas (decirle a qué hora me las ha de subir o bajar) la tengo. Lo que me falta, es que el arduino me compruebe la hora. Tengo un relojillo, pero hace una semana vi esto del NTP (si apago el arduino, el reloj se me va de hora y, o hago una parte para programar el reloj, o o desconecto, lo conecto en el ordenador, lo pongo en hora, lo vuelvo a quitar y lo conecto donde tiene que ir. Nada práctico).

    Ahora tengo que con el NTP y sin el reloj (a malas, con el reloj, y que cada… hora se me actualizase la hora por internet)… bueno, tengo el NTP, pero he visto que solo me mira la hora cuando actualizo la web que tengo en el arduino por la que manejo todo (o si abro la ventana del puerto COM a ver lo que hace).

    Entonces, si abro la web del arduino, me dice que ahora son las… 19:45.37 (la hora que sea), pero un segundo después, el arduino no sabe que ya son las 19:45.38, con lo que el comparador de hora (el if) que me ha de subir o bajar las persianas (o encender la luz, o enceder lo que fuese), no sabe qué hora es, al no ser que yo actualice la web (para eso no hace falta programar nada).

    Qué instrucción, o qué función es la que debería poner, en el loop, para que el arduino fuese sabiendo la hora que es, siempre? He probado a escribir 200 partes del código de lectura del NTP, pero ninguna funciona.

    O sino, cómo puedo, utilizando el reloj, un DS1307, hacer que cada tanto tiempo, se me ponga en hora? Tengo el código de poner en hora el DS1307 y el código de lectura del tiempo por internet, pero como las variables de ambas cosas se llaman hour, minute, second… … he probado a poner hour2 y decir que hour2 = hour, pero entonces no coinciden los tipos, ni poniendo (hour, DEC) ni… … NADA!!!! 🙁

    Espero que me haya explicado y que encuentre alguna solución…

    Muchas gracias.

  4. También he intentado usar algo del now (now.hour, now.minute…) o DateTime y cosas varias que he ido viendo en las webs que he ido visitando, pero nada.

    Gracias y saludos!!!

  5. (Estooo… LO SIENTO MUCHO, elimina mis comentarios, que estoy leyendo el Día 7 -si todavía sigues llevando la web, que he visto que es de 2011-) Gracias de todas formas, voy a ver cómo adecúo la parte del Día 7 a mi proyecto.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *