Comunicar una página web con websockets en el ESP8266


Seguimos con las entradas del ESP8266 viendo los ampliamente oídos, amados, y a veces poco entendidos Websockets.

Las últimas entradas de esta serie de tutoriales dedicados al ESP8266 hemos visto cómo comunicar una página web con el ESP8266 como backend. Empezamos viendo los formularios web como una forma sencilla. Pero ya hemos dicho que son un mecanismo anticuado y que obliga al cliente a refrescar la página web al enviar información.

En la entrada anterior vimos una forma mucho más conveniente con peticiones Ajax. Las peticiones Ajax permiten tramitar una solicitud al servidor sin recargar la página. Pero tienen la desventaja de que el servidor no tienen un mecanismo para llamar al cliente y, además, son relativamente lentos porque tienen que generar una conexión en cada petición.

En esta entrada vamos a ver los websockets, otro mecanismo de comunicación entre el cliente y el servidor, que permite una comunicación bidireccional y con bajo lag.

Anuncio:

Los websockets son una "versión moderna" de los sockets tradicionales que funcionan sobre HTTP, y están diseñados para funcionar en aplicaciones web. En un websocket se crea una conexión entre el cliente y el servidor que se mantiene abierta. Por este motivo tienen un lag mucho menos, y la comunicación puede realizarse en ambas direcciones.

Sin embargo, hay que descartar que los websockets no son la solución definitiva o que sustituya a Ajax, sino que son tecnologías compatibles. Incluso es posible aplicaciones híbridas, que emplean ambas soluciones simultáneamente.

Los websockets son adecuados para aplicaciones que requieran una alta velocidad de refresco (captura de datos en tiempo real, control de sistemas de luces, controlar un motor, etc) y donde sea necesaria una comunicación rápida desde el servidor al cliente.

Sin embargo, mantener la conexión abierta supone un consumo de recursos, lo que se traduce en una menor cantidad de clientes que podemos atender frente a una solución basada en un API servido a través de Ajax.

Y ya vale de introducción. Nos metemos en un ejemplo de Websockets en el ESP8266. Vamos a hacer el mismo ejemplo que hicimos en la entrada sobre Ajax, simplemente actualizando un número en la página web con el valor de 'millis()' obtenido desde el servidor. Un ejemplo mínimo que permite ilustrar la comunicación sin despistar con elementos adicionales.

De hecho, vamos a ver dos ejemplos sobre el mismo código (el primero de ellos está comentado). En ambos casos el cliente va a realizar una conexión de websocket, y la diferencia es:

    • Ejemplo 1: El cliente enviará datos periódicamente, y recibe 'millis()' como respuesta
    • Ejemplo 2: El servidor usa un broadcast para informar a los clientes del valor de 'millis()'
El ejemplo 1 está comentado en el código. Tal cuál está, el código ejecuta el ejemplo 2, que emplea broadcast.

Vamos a ver cómo queda nuestro código. Nuestro bucle principal queda de la siguiente forma.

En primer lugar, vemos que hemos añadido las dependencias adicionales a la librería 'WebSocketsServer.h' y referencias a 'WebSockets.hpp' referencia a 'ESP8266_Utils_WS.hpp' que va a contener código repetitivo relativo al uso de Websockets.

Por otro lado, vemos que en el loop llamamos a 'websocket.loop()', que gestiona el proceso de Websockets. Y también tenemos parte del código del ejemplo 2, donde el servidor usa la función 'broadcastTXT(...);' para informar a todos los clientes del valor de 'millis()'.

Nuestro fichero 'server.hpp' queda muy simplificado. No tenemos endpoints, y simplemente servimos el contenido desde el SPIFFS.

Respecto al fichero 'ESP8266_Utils_WS.hpp', contiene código que podemos reutilizar para su uso con Websockets.

En este fichero, en primer lugar definimos un nuevo Websocket asociado al puerto 81. Al final, tenemos la función 'InitWebSockets()', que inicia el Websocket y asocia la función de callback 'webSocketEvent(...)' a los eventos de websockets.

En la función de callback, discriminamos el tipo de evento recibido. En caso de que sea un texto recibido, generamos una respuesta con 'ProcessRequest()' y la enviamos al cliente.

Finalmente, tenemos el archivo 'WebSockets.hpp', que contiene la definición de nuestro 'API' websocket. Aquí definimos la función 'ProcessRequest()', que hemos empleado en el fichero anterior. En este ejemplo, simplemente devolvemos el valor de 'millis()' codificado como string.

Por su parte, el fichero 'index.html' es exactamente igual al que vimos en el ejemplo Ajax.

Lo que cambia es el fichero 'main.js', que queda de la siguiente forma.

En este código en Javascript, vemos que tenemos la función 'updateCounterUI(...)' que ya usamos en el ejemplo anterior, y que simplemente actualiza el div counter con el valor oportuno.

Por otro lado, creamos un Websocket a la dirección del servidor en el puerto 81. A continuación asociamos los distintos eventos a sus funciones de callback. En particular, el evento 'onmessage()' lanza la función 'updateCounterUI(...)' con el valor recibido.

En el ejemplo 2, en el que el servidor hace un broadcast a todos los clientes, no es necesario más código que este.

En el ejemplo 1, en el que el cliente realiza periódicamente peticiones al servidor, tenemos el código comentado en el evento 'onopen'. Aquí, definimos un temporizador cada 100ms, para enviar un texto (en este caso, un texto vacio), al servidor y "provocar" que nos envie la respuesta.

Subimos todo al ESP8266 y accedemos a la página web, para ver que, efectivamente, el valor de 'millis()' se actualiza correctamente. Igual que en el caso de Ajax pero muchísimo más rápido.

¡Ya hemos terminado! Ya hemos visto cómo hacer formularios web, cómo usar peticiones Ajax y cómo usar Websockets, como formas de comunicar el frontend con el ESP8266 como backend.

En la próxima entrada veremos cómo hacer Websockets asíncronos, y en la siguiente conexiones UDP. ¡Hasta pronto!

Descarga el código

Todo el código de esta entrada está disponible para su descarga en GitHub.

Si te ha gustado esta entrada y quieres leer más sobre ESP8266 puedes consultar la sección
tutoriales de ESP8266

Anuncio:

Previous Cómo instalar MySQL en Raspberry Pi
Next Librería de Arduino Easing
1000