The image above displays how powerful Ubidots' HTML Canvas Widget is. It allows Ubidots users to create specialized mini-web apps using Ubidots' API REST and a little imagination. With the HTML canvas, users can create presentation user layers (UX) like customized maps or animated business apps.
The HTML canvas is best utilized with a programmed GET request that fits our REST API, but if you need to show real-time values from different variables using many widgets, a 429 response error might be standing in your way. For server security reasons, Ubidots does not allow users to receive hundreds of instant requests from a single device. This is a headache if you wish to develop a customized dashboard using only HTML canvas widgets to show values in real-time. Do not worry, Ubidots is here to help you bypass this 429 Error with ease. In this tutorial we will demonstrate how to implement a quick real-time HTML widget using the socket.IO JS library.
NOTE: This article is intended to be read by users with knowledge of HTML, JS and CSS. If you are not familiar with these languages we strongly advise brushing up on the basics and return to this article once you are feeling more comfortable to code.
Requirements
Ubidots account: Professional plan or above.
1. Socket.IO
Socket.IO is a JS library easy to implement that manages socket connections and messages, thus enabling a bi-directional real-time connection protocol. Ubidots has implemented this real-time protocol within its core servers to easily update devices, to retrieve and store data inside any JS variable, and without the need to implement any requests, using sockets.
2. Architecture
To implement a bi-directional TCP connection using socket.IO you must first publish the variable's ID that you wish to "listen" to in real-time with Ubidots. Once you've published to Ubidots' server which variable you wish to listen, Ubidots will reply with a packet each time the variable is updated (you do not need to ask the server for values, it will send the updated variable to you automatically). Below you can find a helpful diagram of how the listening connection works:
The client publishes the variable ID that it wishes to constantly monitor or "listen". If there is an update to that variable the server will update every subsequent TCP client. The main advantage of this architecture is the always connected and listening server with the Main DB. The main process is implemented by the server and not the browser, resulting in a lightweight communication protocol using socket.IO.
3. Endpoints
Below you will find the two endpoints to implement a TCP connection to Ubidots' server using socket.IO:
To publish the desired variable to listen:
https://industrial.ubidots.com:443/notifications/rt/variables/id/last_value
To un-subscribe for listening a variable:
https://industrial.ubidots.com:443/notifications/unsub/rt/variables/id/last_value
4. Coding
The HTML Canvas widget is divided into three main coding slots: HTML, CSS, and JS. I will not implement any CSS as this tutorial is not intended for the widget's visual design, so we will work only with some of HTML and JS.
HTML
<p id="content"></p>
The HTML is pretty simple for this exchange; we will update a paragraph meta-tag that shows us the data received from the socket.
JS
var socket;
var srv = window.location.hostname + ":443"; //this allows the widget to work at the white label level
var VAR_ID = "5a0f6e7a76254211cac86bea"; // Put here your var Id
var TOKEN = "YOUR-TOKEN" // Put here your token
$(document).ready(function () {
// Implements the connection to the server
socket = io.connect("https://" + srv, { path: '/notifications' });
var subscribedVars = [];
// Function to publish the variable ID
var subscribeVariable = function (variable, callback) {
// Publishes the variable ID that wishes to listen
socket.emit('rt/variables/id/last_value', {
variable: variable
});
// Listens for changes
socket.on('rt/variables/' + variable + '/last_value', callback);
subscribedVars.push(variable);
};
// Function to unsubscribed for listening
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 () {
// Implements the socket connection
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 });
});
});
}
/* Main Routine */
connectSocket();
// Should try to connect again if connection is lost
socket.on('reconnect', connectSocket);
// Subscribe Variable with your own code.
subscribeVariable(VAR_ID, function (value) {
var parsedValue = JSON.parse(value);
console.log(parsedValue);
$('#content').text(value);
})
});
The JS code will make use of the socket.IO library. To better explain the code and its structure we divided it into 5 parts:
var socket;
var = window.location.hostname + ":443";
var VAR_ID = "5a0f6e7a76254211cac86bea"; // Put here your var Id
var TOKEN = "..." // Put here your token
Here we define the variables that will store the socket object, server's dns address, variable ID and your account TOKEN, nothing very impressive.
// Implements the connection to the server
socket = io.connect("https://"+ srv, {path: '/notifications'});
var subscribedVars = [];
// Function to publish the variable ID
var subscribeVariable = function (variable, callback) {
// Publishes the variable ID that wishes to listen
socket.emit('rt/variables/id/last_value', {
variable: variable
});
// Listens for changes
socket.on('rt/variables/' + variable + '/last_value', callback);
subscribedVars.push(variable);
};
This piece of code becomes a little more interesting, using the connect()
method from socket.IO we can connect to the Ubidots server using the specified endpoint. Then, a function to publish the variable ID for listening is implemented using the emit()
method and we publish to the server which variable we want to listen to. With the on()
method we keep listening for any changes between the client and server. The subscribedVars array will store all the variables IDs. We will use it later to implement easily a routine to reconnect in the case of connection lost.
// Function to unsubscribed for listening
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);
}
};
This function, as its name suggests, let us to stop to listen a variable. Using again the emit()
method, we notify to the server that we do not wish to listen to the specified variable anymore.
var connectSocket = function (){
// Implements the socket connection
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 });
});
});
}
The connectSocket()
function lets us implement a connection routine in case we lose connection at any point. Basically, we publish again all the variables stored at the subscribedVars array and tell the server to continue listening. Using the JS method for listening events, once the client or the socket is connected we emit the authentication credentials to keep listening for changes in our variables.
Important note: Due to the asynchronous paradigm of JS, we use the on() method from socket.IO to know when the socket is opened for sending the authentication credentials.
/* Main Routine */
connectSocket();
// Subscribe Variable with your own code.
subscribeVariable(VAR_ID, function(value){
var parsedValue = JSON.parse(value);
console.log(parsedValue);
$('#content').text(value);
})
});
With all our connection functioning now, the main routine becomes pretty simple, after the connection routine we subscribe to our variable ID and simply update any paragraph meta-tag identified as "content" with the results that comes from the server.
Lastly, do not forget to import the necessary JS libraries to run this example:
5. Results
Below you can find the final results of our widget. In real-time, our widget is updating with all data references that come from the server (timestamp, value, variable id and context):
With the completed code, our real-time HTML Canvas widget now reflects on the dashboard and works great! Now it is your turn to give it a try.