{"id":1276,"date":"2012-11-21T02:32:36","date_gmt":"2012-11-21T01:32:36","guid":{"rendered":"http:\/\/www.zigbe.net\/?p=1276"},"modified":"2012-11-21T02:32:36","modified_gmt":"2012-11-21T01:32:36","slug":"la-web-en-tiempo-real-long-poll-en-ajax-con-arduino","status":"publish","type":"post","link":"https:\/\/blog.whatsbee.net\/?p=1276","title":{"rendered":"La web en tiempo real, long poll en Ajax con Arduino"},"content":{"rendered":"<p><!--:en-->&nbsp;<\/p>\n<p><!--:--><!--:es-->Yo tampoco entiendo el t\u00edtulo&#8230;..<\/p>\n<p>Este art\u00edculo nace de una necesidad, que todav\u00eda no est\u00e1 resuelta del todo. Como habr\u00e9is podido ver \u00faltimamente trabajo en \u00abrematar\u00bb el gateway para Opendomo. Tal como os comentaba el interfaz se carga en el cliente, el cliente pide al gateway informaci\u00f3n por Ajax de forma as\u00edncrona y, una vez la recibe, la aplicaci\u00f3n Javascript que corre en el cliente se encarga de generar la p\u00e1gina escribiendo en el DOM y de actualizar los datos. Aqu\u00ed empieza el problema.<\/p>\n<p>Desde el cliente te conectas al Gateway (sin problemas), el Gateway redirige al cliente a una p\u00e1gina p\u00fablica de Internet pasando la IP del Gateway como par\u00e1metro (porque un ATMEGA 328 no tiene capacidad para servir el contenido). El cliente descarga los ficheros de la p\u00e1gina p\u00fablica la primera vez que se conecta (las siguientes los tiene en su cach\u00e9, por lo que no es preciso tener una conexi\u00f3n con Internet). Los ficheros contienen el interfaz vac\u00edo, los gr\u00e1ficos 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\u00f3n y otro con el contenido de los nodos y los puertos, con esa informaci\u00f3n construye la p\u00e1gina y la actualiza en el navegador.<\/p>\n<p>En este punto ya tenemos la aplicaci\u00f3n con todos los datos en la pantalla.<\/p>\n<p>Ahora empieza lo bueno, necesitamos que nos llegue al navegador cualquier actualizaci\u00f3n de los puertos y que se refresquen de forma inmediata.<\/p>\n<p>Primera opci\u00f3n: disparar polls al servidor de forma peri\u00f3dica, cada x segundos se solicita un nuevo Json con los puertos que se han actualizado desde la \u00faltima petici\u00f3n. El gran inconveniente de este sistema es que si se retrasa alguna petici\u00f3n se puede solapar con las siguientes, eso provoca m\u00e1s retraso y pueden acumularse muchas.<\/p>\n<p>Segunda opci\u00f3n: disparamos los polls al cabo de un tiempo predefinido despu\u00e9s de recibir la petici\u00f3n anterior. Con respecto a la opci\u00f3n anterior tiene la ventaja de que nunca se van a acumular las peticiones, si disparamos cada dos segundos y una petici\u00f3n tarda tres en ser respondida la siguiente se solicitar\u00e1 dos segundos m\u00e1s tarde de la recepci\u00f3n.<\/p>\n<p>Tanto en una como en otra los puertos tardan un poco en actualizarse, en funci\u00f3n de los retrasos en la red, lo que esperas cuando pulsas un bot\u00f3n es que el cambio se refleje inmediatamente en el interfaz, por lo que he decidido mejorarlo.<\/p>\n<p>Como ya sabr\u00e9is HTTP es un protocolo \u00absessionless\u00bb, por lo que no es posible mantener una conexi\u00f3n 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\u00f3n parece una t\u00e9cnica que se llama Long Poll.<\/p>\n<p>Tercera opci\u00f3n Long Poll: Desde el cliente hacemos la petici\u00f3n 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\u00f3n, si se supera el timeout sin que se haya producido un evento desde el Javascript lanzamos otra petici\u00f3n.<\/p>\n<div id=\"attachment_1277\" style=\"width: 506px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/blog.whatsbee.net\/wp-content\/uploads\/2012\/11\/PubSub_longpoll.jpg\"><img aria-describedby=\"caption-attachment-1277\" loading=\"lazy\" class=\"size-full wp-image-1277\" title=\"PubSub_longpoll\" src=\"http:\/\/blog.whatsbee.net\/wp-content\/uploads\/2012\/11\/PubSub_longpoll.jpg\" alt=\"\" width=\"496\" height=\"232\" srcset=\"https:\/\/blog.whatsbee.net\/wp-content\/uploads\/2012\/11\/PubSub_longpoll.jpg 496w, https:\/\/blog.whatsbee.net\/wp-content\/uploads\/2012\/11\/PubSub_longpoll-300x140.jpg 300w\" sizes=\"(max-width: 496px) 100vw, 496px\" \/><\/a><p id=\"caption-attachment-1277\" class=\"wp-caption-text\">Long Poll<\/p><\/div>\n<p>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.<\/p>\n<p>El primer problema viene de tener una conexi\u00f3n abierta, pueden cruzarse una petici\u00f3n de la aplicaci\u00f3n con una respuesta pendiente, por lo que decido utilizar dos sockets diferentes, uno para la comunicaci\u00f3n normal y otro para los long poll, las primeras ir\u00e1n por el puerto 80 y las segundas por el 1730. He ido avanzando y obteniendo progresos, pero las librer\u00edas ethernet de Arduino parecen tener dificultades para manejar comunicaci\u00f3n en dos sockets de forma simult\u00e1nea (si&#8230;. ya se que el manual del chip Wiznet dice que hasta cuatro, pero no parece funcionar). llevo unos d\u00edas sin progresos, por lo que es posible que, de momento, opte por la segunda opci\u00f3n y deje que la tercera madure sola en mi mente.<\/p>\n<p>En el camino he intentado multitud de opciones, utilizar timer interruptions, poner varios loops, etc. en todos los casos con los mismos problemas.<\/p>\n<p>Seguiremos informando.<!--:--><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Yo tampoco entiendo el t\u00edtulo&#8230;.. Este art\u00edculo nace de una necesidad, que todav\u00eda no est\u00e1 resuelta del todo. Como habr\u00e9is podido ver \u00faltimamente trabajo en \u00abrematar\u00bb el gateway para Opendomo. Tal como os comentaba el interfaz se carga en&hellip; <br \/><a class=\"read-more-button\" href=\"https:\/\/blog.whatsbee.net\/?p=1276\">Leer m\u00e1s<\/a><\/p>\n","protected":false},"author":1,"featured_media":1277,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0},"categories":[15,2,7,21,9,11],"tags":[35,39,50,88,98,126,160,173,197],"_links":{"self":[{"href":"https:\/\/blog.whatsbee.net\/index.php?rest_route=\/wp\/v2\/posts\/1276"}],"collection":[{"href":"https:\/\/blog.whatsbee.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.whatsbee.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.whatsbee.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.whatsbee.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1276"}],"version-history":[{"count":0,"href":"https:\/\/blog.whatsbee.net\/index.php?rest_route=\/wp\/v2\/posts\/1276\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.whatsbee.net\/index.php?rest_route=\/wp\/v2\/media\/1277"}],"wp:attachment":[{"href":"https:\/\/blog.whatsbee.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1276"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.whatsbee.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1276"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.whatsbee.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1276"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}