Ir al contenido principal
Todas las coleccionesGuías de desarrollador
Widget de HTML Canvas: Agregando tiempo real usando Socket.IO
Widget de HTML Canvas: Agregando tiempo real usando Socket.IO

Usando la biblioteca socket.IO, crea un widget simple en tiempo real con Ubidots y el HTML Canvas.

David Sepúlveda avatar
Escrito por David Sepúlveda
Actualizado hace más de una semana

La imagen de arriba muestra cuán poderoso es el HTML Canvas Widget de Ubidots. Permite a los usuarios de Ubidots crear mini-aplicaciones web especializadas utilizando la API REST de Ubidots y un poco de imaginación. Con el canvas HTML, los usuarios pueden crear capas de usuario de presentación (UX) como mapas personalizados o aplicaciones de negocios animadas.

El canvas HTML se utiliza mejor con una solicitud GET programada que se ajuste a nuestra API REST, pero si necesitas mostrar valores en tiempo real de diferentes variables utilizando muchos widgets, un error de respuesta 429 podría estar en tu camino. Por razones de seguridad del servidor, Ubidots no permite a los usuarios recibir cientos de solicitudes instantáneas desde un solo dispositivo. Esto es un dolor de cabeza si deseas desarrollar un dashboard personalizado utilizando solo widgets de canvas HTML para mostrar valores en tiempo real. No te preocupes, Ubidots está aquí para ayudarte a eludir este Error 429 con facilidad. En este tutorial, demostraremos cómo implementar un widget HTML en tiempo real rápido utilizando la biblioteca JS de socket.IO.

NOTA: Este artículo está destinado a ser leído por usuarios con conocimientos de HTML, JS y CSS. Si no estás familiarizado con estos lenguajes, te recomendamos encarecidamente repasar los conceptos básicos y volver a este artículo una vez que te sientas más cómodo para codificar.

Requisitos

1. Socket.IO

Socket.IO es una biblioteca JS fácil de implementar que gestiona conexiones y mensajes de socket, habilitando así un protocolo de conexión en tiempo real bidireccional. Ubidots ha implementado este protocolo en tiempo real dentro de sus servidores centrales para actualizar fácilmente dispositivos, recuperar y almacenar datos dentro de cualquier variable JS, y sin necesidad de implementar solicitudes, utilizando sockets.

2. Arquitectura

Para implementar una conexión TCP bidireccional utilizando socket.IO, primero debes publicar el ID de la variable que deseas "escuchar" en tiempo real con Ubidots. Una vez que hayas publicado en el servidor de Ubidots qué variable deseas escuchar, Ubidots responderá con un paquete cada vez que la variable se actualice (no necesitas pedirle al servidor los valores, te enviará la variable actualizada automáticamente). A continuación, puedes encontrar un diagrama útil de cómo funciona la conexión de escucha:

El cliente publica el ID de la variable que desea monitorear o "escuchar" constantemente. Si hay una actualización de esa variable, el servidor actualizará cada cliente TCP subsiguiente. La principal ventaja de esta arquitectura es el servidor siempre conectado y escuchando con la Base de Datos Principal. El proceso principal es implementado por el servidor y no por el navegador, resultando en un protocolo de comunicación ligero utilizando socket.IO.

3. Endpoints

A continuación, encontrarás los dos endpoints para implementar una conexión TCP al servidor de Ubidots utilizando socket.IO:

  • Para publicar la variable deseada para escuchar:

https://industrial.ubidots.com:443/notifications/rt/variables/id/last_value

  • Para cancelar la suscripción a una variable:

https://industrial.ubidots.com:443/notifications/unsub/rt/variables/id/last_value

4. Codificación

El widget HTML Canvas se divide en tres espacios principales de codificación: HTML, CSS y JS. No implementaré ningún CSS ya que este tutorial no está destinado al diseño visual del widget, así que trabajaremos solo con algo de HTML y JS.

HTML

<p id="content"></p>

El HTML es bastante simple para este intercambio; actualizaremos una etiqueta de párrafo que nos muestra los datos recibidos del socket.

JS

var socket;var srv = window.location.hostname + ":443"; //esto permite que el widget funcione a nivel de etiqueta blancavar VAR_ID = "5a0f6e7a76254211cac86bea"; // Pon aquí tu ID de variablevar TOKEN = "YOUR-TOKEN"  // Pon aquí tu token$(document).ready(function () {    // Implementa la conexión al servidor    socket = io.connect("https://" + srv, { path: '/notifications' });    var subscribedVars = [];    // Función para publicar el ID de la variable    var subscribeVariable = function (variable, callback) {        // Publica el ID de la variable que desea escuchar        socket.emit('rt/variables/id/last_value', {            variable: variable        });        // Escucha cambios        socket.on('rt/variables/' + variable + '/last_value', callback);        subscribedVars.push(variable);    };    // Función para cancelar la suscripción a la escucha    var unSubscribeVariable = function (variable) {        socket.emit('unsub/rt/variables/id/last_value', {            variable: variable        });        var pst = subscribedVars.indexOf(variable);        if (pst !== -1) {            subscribedVars.splice(pst, 1);        }    };    var connectSocket = function () {        // Implementa la conexión del socket        socket.on('connect', function () {            socket.emit('authentication', { token: TOKEN });        });        window.addEventListener('online', function () {            socket.emit('authentication', { token: TOKEN });        });        socket.on('authenticated', function () {            subscribedVars.forEach(function (variable_id) {                socket.emit('rt/variables/id/last_value', { variable: variable_id });            });        });    }    /* Rutina Principal */    connectSocket();    // Debería intentar conectarse nuevamente si se pierde la conexión    socket.on('reconnect', connectSocket);    // Suscribir Variable con tu propio código.    subscribeVariable(VAR_ID, function (value) {        var parsedValue = JSON.parse(value);        console.log(parsedValue);        $('#content').text(value);    })});

El código JS hará uso de la biblioteca socket.IO. Para explicar mejor el código y su estructura, lo dividimos en 5 partes:

var socket;var = window.location.hostname + ":443";var VAR_ID = "5a0f6e7a76254211cac86bea"; // Pon aquí tu ID de variablevar TOKEN = "..."  // Pon aquí tu token

Aquí definimos las variables que almacenarán el objeto socket, la dirección DNS del servidor, el ID de la variable y tu TOKEN de cuenta, nada muy impresionante.

// Implementa la conexión al servidor     socket = io.connect("https://"+ srv, {path: '/notifications'});     var subscribedVars = [];       // Función para publicar el ID de la variable     var subscribeVariable = function (variable, callback) {         // Publica el ID de la variable que desea escuchar         socket.emit('rt/variables/id/last_value', {             variable: variable         });         // Escucha cambios         socket.on('rt/variables/' + variable + '/last_value', callback);         subscribedVars.push(variable);     };

Este fragmento de código se vuelve un poco más interesante, utilizando el método connect() de socket.IO podemos conectarnos al servidor de Ubidots utilizando el endpoint especificado. Luego, se implementa una función para publicar el ID de la variable para escuchar utilizando el método emit() y publicamos al servidor qué variable queremos escuchar. Con el método on() seguimos escuchando cualquier cambio entre el cliente y el servidor. El array subscribedVars almacenará todos los IDs de las variables. Lo utilizaremos más adelante para implementar fácilmente una rutina para reconectar en caso de pérdida de conexión.

// Función para cancelar la suscripción a la escucha     var unSubscribeVariable = function (variable) {         socket.emit('unsub/rt/variables/id/last_value', {             variable: variable         });         var pst = subscribedVars.indexOf(variable);         if (pst !== -1){             subscribedVars.splice(pst, 1);         }     };

Esta función, como su nombre sugiere, nos permite dejar de escuchar una variable. Usando nuevamente el método emit(), notificamos al servidor que ya no deseamos escuchar la variable especificada.

var connectSocket = function (){    // Implementa la conexión del socket    socket.on('connect', function(){        socket.emit('authentication', {token: TOKEN});     });    window.addEventListener('online', function () {         socket.emit('authentication', {token: TOKEN});     });     socket.on('authenticated', function () {         subscribedVars.forEach(function (variable_id) {         socket.emit('rt/variables/id/last_value', { variable: variable_id });         });     });}

La función connectSocket() nos permite implementar una rutina de conexión en caso de que perdamos la conexión en algún momento. Básicamente, publicamos nuevamente todas las variables almacenadas en el array subscribedVars y le decimos al servidor que continúe escuchando. Usando el método JS para escuchar eventos, una vez que el cliente o el socket están conectados, emitimos las credenciales de autenticación para seguir escuchando cambios en nuestras variables.

Nota importante: Debido al paradigma asíncrono de JS, utilizamos el método on() de socket.IO para saber cuándo el socket está abierto para enviar las credenciales de autenticación.

/* Rutina Principal */connectSocket();// Suscribir Variable con tu propio código.subscribeVariable(VAR_ID, function(value){    var parsedValue = JSON.parse(value);    console.log(parsedValue);        $('#content').text(value);     })});

Con toda nuestra conexión funcionando ahora, la rutina principal se vuelve bastante simple, después de la rutina de conexión nos suscribimos a nuestro ID de variable y simplemente actualizamos cualquier etiqueta de párrafo identificada como "content" con los resultados que vienen del servidor.

Por último, no olvides importar las bibliotecas JS necesarias para ejecutar este ejemplo:

5. Resultados

A continuación, puedes encontrar los resultados finales de nuestro widget. En tiempo real, nuestro widget se está actualizando con todas las referencias de datos que provienen del servidor (marca de tiempo, valor, ID de variable y contexto):

Con el código completado, nuestro widget HTML Canvas en tiempo real ahora se refleja en el dashboard y funciona de maravilla. ¡Ahora es tu turno de intentarlo!

¿Ha quedado contestada tu pregunta?