Cami Can Calders, 8 2º-2ª | 08173 Sant Cugat del Valles info@bmotes.com 932504996

WhatsBee blog

La web en tiempo real, long poll en Ajax con Arduino

 

Yo tampoco entiendo el título…..

Este artículo nace de una necesidad, que todavía no está resuelta del todo. Como habréis podido ver últimamente trabajo en «rematar» el gateway para Opendomo. Tal como os comentaba el interfaz se carga en el cliente, el cliente pide al gateway información por Ajax de forma asíncrona y, una vez la recibe, la aplicación Javascript que corre en el cliente se encarga de generar la página escribiendo en el DOM y de actualizar los datos. Aquí empieza el problema.

Desde el cliente te conectas al Gateway (sin problemas), el Gateway redirige al cliente a una página pública de Internet pasando la IP del Gateway como parámetro (porque un ATMEGA 328 no tiene capacidad para servir el contenido). El cliente descarga los ficheros de la página pública la primera vez que se conecta (las siguientes los tiene en su caché, por lo que no es preciso tener una conexión con Internet). Los ficheros contienen el interfaz vacío, los gráficos y los programas de Javascript. Lo primero que hace el programa de Javascript es solicitar al gateway un par de JSON, uno con la configuración y otro con el contenido de los nodos y los puertos, con esa información construye la página y la actualiza en el navegador.

En este punto ya tenemos la aplicación con todos los datos en la pantalla.

Ahora empieza lo bueno, necesitamos que nos llegue al navegador cualquier actualización de los puertos y que se refresquen de forma inmediata.

Primera opción: disparar polls al servidor de forma periódica, cada x segundos se solicita un nuevo Json con los puertos que se han actualizado desde la última petición. El gran inconveniente de este sistema es que si se retrasa alguna petición se puede solapar con las siguientes, eso provoca más retraso y pueden acumularse muchas.

Segunda opción: disparamos los polls al cabo de un tiempo predefinido después de recibir la petición anterior. Con respecto a la opción anterior tiene la ventaja de que nunca se van a acumular las peticiones, si disparamos cada dos segundos y una petición tarda tres en ser respondida la siguiente se solicitará dos segundos más tarde de la recepción.

Tanto en una como en otra los puertos tardan un poco en actualizarse, en función de los retrasos en la red, lo que esperas cuando pulsas un botón es que el cambio se refleje inmediatamente en el interfaz, por lo que he decidido mejorarlo.

Como ya sabréis HTTP es un protocolo «sessionless», por lo que no es posible mantener una conexión abierta y que el gateway le mande las notificaciones cuando se produzcan los eventos. Esto se ha resuelto en HTML5 con los websockets, pero parece ambicioso utilizarlos en un Arduino por cuestiones de espacio, la mejor solución parece una técnica que se llama Long Poll.

Tercera opción Long Poll: Desde el cliente hacemos la petición Ajax estableciendo un timeout de 30 segundos o de un minuto, el gateway no responde hasta que se produce el evento, en el mismo momento en el que se produce el evento el Gateway responde a la petición, si se supera el timeout sin que se haya producido un evento desde el Javascript lanzamos otra petición.

Long Poll

Las primeras pruebas son sencillamente impresionantes, impresionan por la poca costumbre que tengo de ver cosas en un navegador en tiempo real, pero ahora nos queda implementarlo en el gateway.

El primer problema viene de tener una conexión abierta, pueden cruzarse una petición de la aplicación con una respuesta pendiente, por lo que decido utilizar dos sockets diferentes, uno para la comunicación normal y otro para los long poll, las primeras irán por el puerto 80 y las segundas por el 1730. He ido avanzando y obteniendo progresos, pero las librerías ethernet de Arduino parecen tener dificultades para manejar comunicación en dos sockets de forma simultánea (si…. ya se que el manual del chip Wiznet dice que hasta cuatro, pero no parece funcionar). llevo unos días sin progresos, por lo que es posible que, de momento, opte por la segunda opción y deje que la tercera madure sola en mi mente.

En el camino he intentado multitud de opciones, utilizar timer interruptions, poner varios loops, etc. en todos los casos con los mismos problemas.

Seguiremos informando.

1 Comentario

  1. cosmopaco

    Impresionante.

    Eres una máquina.

Dejar un comentario