Continuación de la entrada anterior: #7 Curso IoT con Arduino y ESP8266 WiFi: Ejemplo cliente -> Enviar datos
5.8.3) Cliente: Obtención de fecha y hora desde servidor web
Una vez que ya controlamos la forma en la que se envían datos desde Arduino el segundo paso lógico es la obtención de información desde internet hasta nuestro Arduino, parte que nos saltamos en el ejemplo anterior para hacerlo más sencillo y que veremos a continuación.
En concreto vamos a conectarnos a un servidor PHP que contiene un fichero en PHP desarrollado por nosotros y que al ejecutarlo nos devuelve la fecha y la hora en un formato concreto, que nos permitirá leer fácilmente cada dato para pintarlo en el monitor Serial de Arduino.
Para el curso no es necesario que contéis con un servidor PHP, aunque si tenéis interés podéis obtener uno gratuito desde hostinger, pues los ficheros necesarios para las pruebas estarán disponibles en el mío.
1 2 3 4 5 6 7 8 |
<?php // Código completo 5.1: https://goo.gl/qtIQ0m // Código en el servidor: https://giltesa.com/ard/ntp.php header("Content-Type: text/plain;charset=us-ascii "); $dt = new DateTime(null, new DateTimeZone('Europe/Madrid')); echo $dt->format('Y m d H i s'); ?> |
El código PHP superior se encarga de sacar la hora del sistema e imprimirla como página web, si accedemos al segundo enlace desde el navegador de internet o desde Arduino, como se verá en el código siguiente, podremos obtener la fecha y la hora.
En cuanto al código que debemos grabar esta vez en el Arduino cambia un poco, como no es necesario enviar datos se ha eliminado esa parte, pero también se ha añadido una nueva función para recibir datos, el resto es muy parecido por ello se explicara las grandes diferencias, el código completo está disponible desde el enlace en Github.
[notification type=»alert-info» close=»false» ]Actualización 2018/02/19: El código no esta preparado para conexiones seguras, por tanto desde que instale un certificado SSL en el blog el código ha dejado de poder conectarse, puedes arreglar el código para darle esa compatibilidad o usar este servidor php alternativo.[/notification]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// Código completo 5.2: https://goo.gl/PFKnon void loop() { time = millis(); if( time - previousTime > SENDTIME ) { previousTime = time; if( !send(IP, PORT, SERVICE) ) pc.println(" Error en el envio" ); else if( !receiveData() ) pc.println(" Error al recuperar los datos"); else { pc.print(" Fecha actual: "); pc.print(year); pc.print("/"); pc.print(month); pc.print("/"); pc.print(day); pc.print(" "); pc.print(hour); pc.print(":"); pc.print(minutes); pc.print(":"); pc.println(seconds); } } } |
En el loop volvemos a tener un if con la condición necesaria para que el código se ejecute solo cada cierto periodo de tiempo, esta vez está definido en 10 segundos.
Una vez dentro en otro if se comprueba si la conexión ha salido mal, en caso contrario con un else if se comprueba si la recepción ha salido mal, y en caso contrario, con un else, es que todo ha salido bien, tanto la conexión con el servidor como la recepción de los datos por lo que lo único que queda es pintarlos por pantalla.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
boolean receiveData() { //+IPD,19:2015 08 23 21 14 47CLOSED if( wifi.find("IPD") && wifi.parseInt() == 19 ) { year = wifi.parseInt(); month = wifi.parseInt(); day = wifi.parseInt(); hour = wifi.parseInt(); minutes = wifi.parseInt(); seconds = wifi.parseInt(); cleanWiFiBuffer(); return true; } return false; } |
Para la recepción de los datos se usa la función receiveData que se encarga de chequear que los datos son correctos y de guardarlos en variables.
En verde se puede ver un ejemplo de lo que recibiremos como entrada de datos: El IPD nos indica que hay información para leer, el 19 indica que hay 19 bytes para leer, el carácter : indica el inicio de los datos y por último el CLOSED indica el final.
Dentro del if podemos leer los datos de forma muy cómoda mediante el método parseInt que leerá todos los caracteres numéricos hasta encontrarse uno que no lo sea y entonces nos devolverá ese número leído.
Tras leer todos los datos y guardarlos en variables es necesario vaciar el buffer para que no se quede el texto CLOSED estorbando en la próxima ejecución.
Tras grabarlo en el Arduino este es el resultado:
Todo funciona bien hasta el receiveData, que me devuelve un error al recuperar los datos. Si elimino del if el wifi.parseInt() == 19, lo único que me devuelve es Fecha actual: 215/0/0 0:0:0 ¿Alguna solución? Gracias!!
Te debería estar devolviendo también el texto «+IPD,19:» que indica que hay una respuesta para leer y 19 caracteres, en este caso, de información para leer.
Si no entra con el 19 es porque el servidor php te esta devolviendo algo distinto a este formato: «2015 08 23 21 14 47» que es el que espera el código.
Imprime todo el contenido del buffer directamente por pantalla en vez de leer sus datos, así sabrás la información que realmente estas recibiendo.
Saludos.
Buenas, cuando me aparece Fecha actual: 215/0/0 0:0:0 , y cuando imprimo el buffer directamente me sale 13 siempre, no sale ningún texto, agradecería alguna ayuda. Gracias!
Hola Roldan,
Acabo de caer que cuando hice el código el blog no tenia HTTPS, ahora si, puede que ahora no os este devolviendo datos porque el modulo no es capaz de hacer conexiones seguras (cuando se usa el módulo directamente, sin Arduino, es necesario usar librerías distintas, por lo que imagino que usando el módulo junto al Arduino varié algo también).
Prueba a usar esta otra dirección: giltesa.esy.es/ntp.php y/o a imprimir por el monitor serial los datos que recuperas en la linea 141 añadiendo: wifi.readString()
Saludos,
puedo tener acceso al ESP8266 estando conectado a una red diferente a la que se encuentra conectado el modulo (Ej: Si la aplicación la tengo en mi casa y yo estoy en el trabajo)
Hola Gabriel,
Si se puede hacer sin ningún problema pero necesitas configurar el router para que todas las peticiones web que entran por el puerto 80 las redireccione al ESP8266. También tendrás que configurar una IP local fija en el router para que el ESP8266 tenga siempre la misma IP y la redirección de puertos funcione correctamente.
Saludos.
Buenas tardes, no me funciona con ninguna direccion. primero lo hice con giltesa.com/ard/ntp.php y aparecia un error al recuperar los datos. Luego intente con giltesa.esy.es/ntp.php y tampoco funcionó, aparece CLOSED y despues dice que hubo un error al recuperar los datos. Soy de Colombia, no se si algo afecta mi uubicación con el servidor al cual se hace la peticion.
Hola Juan Carlos,
Mi web ahora usa HTTPS, cuando publique la entrada no lo usaba, entonces ahora el código tienes que adaptarlo para que pueda conectarse a páginas seguras.
Por tanto en vez de usar la clase WiFiClient tienes que usar WiFiClientSecure, aquí tienes un ejemplo:
https://giltesa.com/2016/10/23/cliente-ntp-con-placa-wemos-d1-para-mostrar-la-hora-en-un-lcd
Saludos.
Muchas gracias, excelente ejemplo
Buenas, todos los cursos han estado muy buenos. Pero al momento de pedir los datos recibo «error al recuperar los datos». Me di cuenta de que cambio el servidor a HTTPS, pero no entendí como adaptar el código de ejemplo que entregaste (https://giltesa.com/2016/10/23/cliente-ntp-con-placa-wemos-d1-para-mostrar-la-hora-en-un-lcd). En el se ocupa la librería ESP8266WiFi, pero no se de donde puedo descargarla.
Saludos y buen día.
Hola Egbusch,
Las entradas de este curso son usando el ESP8266 como modulo WiFi junto al Arduino, y el enlace que has puesto es para usar el ESP8266 SIN Arduino.
En el caso del enlace se trata de una placa Wemos D1, las librerías se instalan solas cuando instalas la placa en el IDE de Arduino, por defecto el IDE solo sirve para placas Arduino pero se pueden instalar mas para que sea compatible para otras como es el caso.
Aquí explican como instalar la placa: https://github.com/esp8266/Arduino
Después para soportar HTTPS hay que usar la clase WiFiClientSecure en vez de WiFiClient.
En cuanto a las entradas del curso, creo que bastaría con cambiar el puerto del 80 al 443, pero no estoy seguro. Puedes usar un servidor no seguro y ya esta. Aquí tengo el ejemplo de la hora:
Saludos.
Estoy usando las entradas del curso. Aún hay algo que no me queda claro, es un servidor seguro o no seguro ?? Significa que si utilizo ip y port 443 debería funcionar ?? No logro establecer la conexión TCP con , obteniendo «Envio Error», también intente con el puerto 80 y tampoco se conecto. Cuando uso giltesa.com con puerto 80 se conecta pero recibo “error al recuperar los datos”, al poner un wifi.readString() en receiveData() obtengo +IPD,239:<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML en vez de la fecha.
Gracias por responder tan rápido 🙂 !
Estoy usando las entradas del curso (con arduino pro mini). Aún me queda una duda sobre este tópico, cuando se llama un ip HTTPS hay que utilizar el puerto 443 en vez del 80? esa es la única diferencia en implementación?? En este caso se esta utilizando un servidor HTTPS o HTTP ?? Cuando intento establecer la conexión TCP para esta actividad se debe usar como ip y puerto 80 o 443 ?? Tengo el problema de que con ambos me imprime un error de «Envio Error». Por otro lado, si utilizo como ip giltesa.com y puerto 80, se conecta pero me devuelve otro error “error al recuperar los datos”. Usando wifi.readString() en receiveData() puedo ver que me devuelve +IPD,239:<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML.
Gracias por la rápida respuesta 🙂 !
Que sea seguro o no seguro te lo indica el protocolo de la URL:
Para las no seguras, , debes usar el puerto 80.
Para las seguras, https://giltesa.com/ard/ntp.php, el puerto 443 (aunque no sé si tendrás que tocar mas el código o no).
Puedes añadir al código impresiones Serial.print para ver qué te esta devolviendo la llamada y no limitar tu información al error «error al recuperar datos».
Saludos.
Edit:
En la recepción de datos donde recuperas
"+IPD,239: el IPD indica que has recuperado datos correctamente y el 239 son los caracteres/bytes recuperados. Después de los : ya empiezan los datos... ¿No tienes más información después de "
Estoy teniendo exactamente el mismo problema, obteniendo lo mismo que usted obtuvo. Cómo solucionó el problema?
Esto me devuelve al conectarme con , https://giltesa.com/ard/ntp.php
400 Bad Request
400 Bad Request
nginx
Hola Daniel, sucede por lo que comente en los comentarios a otro usuario. El blog antes no tenia certificado SSL y ahora si lo tiene, entonces el código esta intentando hacer una conexión no segura a un servidor seguro. Para solucionarlo puedes modificar el código para que haga conexiones seguras o puedes usar el servidor php alternativo
Quizás con cambiar el puerto de 80 a 443 ya te funcione… no lo he probado.
Saludos.