Una forma de mostrar información de equipos electrónicos con internet de las cosas (IoT), son las páginas web. de ahí, la importancia de conocer como inplementar IoT en páginas web. En este apartado mostraremos como usar el protocolo MQTT para internet de las cosas (IoT), en páginas web con el lenguaje javascript.
MQTT (Message Queuing Telemetry Transport) es un protocolo de mensajes usado para internet de las cosas (IoT). Este protocolo se basa en datos transmitidos usando el protocolo internet. Los datos (mensajes) transmitidos por el protocolo MQTT, tienen 2 partes: uno: el “tópico” y el otro: el “valor”. La siguiente figura muestra como un sensor de temperatura envía datos al tópico: “temperature”:
Los datos o mensajes son recibidos por un programa llamado: “Broker MQTT” instalado en un servidor, el cual se encarga de recibirlos y transmitirlos a quienes quieren leer el mensaje. Para esto, el protocolo MQTT, maneja el concepto de: publicador/suscriptor. Así, el “publicador” es quien envía el mensaje al broker y el “suscriptor” es quien lee los mensajes de el bróker como muestra la siguiente imagen:
Es importante notar que tanto el publicador, como el suscriptor, deben estar utilizando el mismo tópico para que el mensaje llegue a los suscriptores. En el ejemplo anterior, fue usado el tópico: “Temperatura”. Tome nota que los tópicos son sensibles a letras mayúsculas y minúsculas, es decir, el bróker es sensible a mayúsculas y minúsculas (case sensitive). Por ejemplo: el tópico “Temperatura”, es diferente del tópico: “temperatura”. También, es posible agruparlos, de una manejar similar a como se manejan los archivos en un computador. Vea los siguientes ejemplos de tópicos:
casa/cocina/temperatura
casa/jardin/humedad
maquina/sensor/proximidad
Como MQTT usa el protocolo TCP/IP como base para transmitir y recibir mensajes, la implementación es relativamente sencilla, en las aplicaciones que las van a usar, porque el transporte y dirección de los mensajes, los maneja el protocolo de internet: “TCP/IP”. Observa la siguiente imagem:
La siguiente imagen muestra de manera diagramática, un mensaje MQTT, donde podemos notar la cabecera para el protocolo IP y los datos del mensaje MQTT:
Para desarrollar la página web, de este apartado, usaremos el lenguaje: “JavaScript”.
JavaScript es un lenguaje interpretado y usa “script”; ahí, se puede escribir el código. Las páginas web que usan JavaScript, son compuestas básicamente por un documento: “html” y un script, como se muestra en la siguiente figura:
El archivo “html” es dirigido a la presentación de la página web y el script es dirigido al comportamiento. El archivo o documento “html” está formado por etiquetas y elementos. Las etiquetas siempre van entre los caracteres: “<>”. Hay etiquetas de apertura y etiquetas de cierre. Observa la siguiente figura:
En esta figura, se representó un elemento del tipo: “button”, el cual tiene una etiqueta de apertura, un atributo, un contenido y una etiqueta de cierre. La mayoría de elementos usados en el documento “html”, contienen la etiqueta de apertura y la de cierre, pero, algunos elementos solo necesitan de la etiqueta de apertura. Para comenzar a escribir en “html”, puede usar cualquier editor de texto. Hay algunos editores como “visual studio code”, Notepad++, Sublime Text, etc, que son muy utilizados para editar lenguaje “html”. Para el siguiente ejemplo puede usar una carpeta y archivo como se muestra a continuación:
El lenguaje “html” más básico para una página web, está formado por las siguientes etiquetas:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
</body>
</html>
Las etiquetas: “<html> </html> ” forman todo el documento “html”, el cual está formado por dos partes: la cabecera (head) y el cuerpo (body). En la cabecera normalmente se colocan directivas para el navegador, como, por ejemplo: donde encontrar algún archivo que clase de set de caracteres usar, el título de la página web, etc.
El siguiente es el programa más básico en “html”:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h3>Hello world.</h3>
</body>
</html>
Dentro de la etiqueta: “<body>”, se ha utilizado un elemento de título: “<h3>” con el contenido: “Hello world”. Los elementos de título van desde: “<h1>” hasta “<h6>". La salida que produce el anterior programa en el navegador, será así:
Hay un elemento para párrafos, llamado: “<p> ”. El siguiente es un programa usando el elemento para párrafos:
La salida que produce el navegador, para el anterior programa, seria así:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>Hello world.</p>
</body>
</html>
En el siguiente programa “html”, se ha usado un elemento de título y un elemento de párrafo:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h3>Hello world.</h3>
<p>Welcome</p>
</body>
</html>
La salida producida en el navegador, para el anterior programa, seria así:
Los scripts de javascript, se pueden ejecutar en el documento “html” de la página web, pero lo más práctico y recomendado es usar un archivo aparte para el script. También, es recomendado crear una pasta o carpeta para contener los scripts. En el siguiente ejemplo creamos una pasta llamada: “js” para almacenar los scripts. Ese es el método que usaremos en este capítulo. Para referenciar un script desde el documento “html”, es usada la etiqueta: “<script>". Dentro de esta etiqueta es usado el atributo: “src” para indicar la ruta y el nombre del archivo. Para el siguiente ejemplo, use el atributo así:
src=”js/hello_world__web.js”
Usted puede dar el nombre que dese y mantener ese nombre durante el desarrollo del tema. Mas para el desarrollo de este apartado use algunos nombres de carpetas y script, para ser más didáctico. Las siguientes son las carpetas y archivos usados:
hllo_world_web.js
index.html
El siguiente programa referencia un script y lo ejecuta en el navegador:
<!DOCTYPE html>
<html>
<head>
<script src="/js/hello_world__web.js"></script>
</head>
<body>
</body>
</html>
El script, tiene una sentencia para escribir en el documento un texto. Observe el script:
document.write("Hello from script.")
La salida que muestra el navegador seria así:
"Hello from script"
Si por acaso, la página no funciona como esperado, hay una herramienta de desarrollo en el propio navegador, la cual se muestra cuando se presiona la tecla: “F12”, como se muestra en la siguiente imagen:
Esta herramienta tiene una consola de salida para mostrar información o cualquier problema que se pueda presentar. Yo he modificado en nombre del script, con el propósito de que vea como el navegador dice que no pudo encontrar el archivo. El nombre del archivo que no encontró es mostrado a la parte derecha de la consola, como se muestra en la siguiente imagen:
Ahora, es necesario decirle al lenguaje “html”, para descargar el script que contienen las funciones MQTT. Esto se hace con la etiqueta <script> así:
<script src=https://cdnjs.cloudflare.com/ajax/libs/mqtt/4.3.7/mqtt.js></script>
Para el siguiente ejemplo se pueden usar carpetas y archivos como mostrado a continuación:
Con este elemento <script> se puder obtener la biblioteca MQTT y comenzar a usar en el script. El lengaje "html" para esto, seria así:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mqtt/4.3.7/mqtt.js">
</script>
<script src="/js/mqtt_min__web.js"></script>
</head>
<body>
<h3 id="state"></h3>
</body>
</html>
Script:
var client = mqtt.connect("ws://test.mosquitto.org:8080/mqtt")
function EventoConectar(){
client.subscribe("x1x2x3x4/temp", function (err) {
if(!err){
client.publish("x1x2x3x4/temp", "30")
}
})
}
function EventoMensaje(topic, message){
if(topic == "x1x2x3x4/temp"){
document.getElementById("state").innerHTML = message
}
}
client.on("connect", EventoConectar)
client.on("message", EventoMensaje)
En el script, lo primero que se hace es crear una variable: “cliente” del broker MQTT. Esto se hace con la línea:
var client = mqtt.connect(“ws://test.mosquitto.org:8080/mqtt)
Para el propósito de este apartado, usaremos el broker: “mosquitto”, el cual es gratuito y puede ser usado para propósitos generales y pruebas.
El script crea dos eventos: un evento para cuando se haya hecho la conexión con el broker, la cual se hace con la línea:
client.on(“connect”, EventoConectar)
El otro evento es para cuando llegue algún mensaje del broker; esto se hace con la línea:
client.on(“message”, EventoMensaje)
Una vez nos hayamos conectado con el broker, hacemos una subscription al tópico: “x1x2x3x4/temp”. Esto se hace con la línea:
client.subscribe(“x1x2x3x4/temp”, function (err) {
Si la suscripción tuvo éxito, entonces hacemos una publicación al tópico: “x1x2x3x4/temp”. Esto se hace con la línea:
client.publish(“x1x2x3x4/temp”, “30”)
Cuando el broker retorne el mensaje al tópico: “x1x2x3x4/temp”, será llamada la función: “EventoMensaje(topic, message)”. Dentro de esta función es evaluado el tópico para que sea el mismo: “x1x2x3x4/temp” y si es así, entonces es mostrado en el navegador. Para esto hemos creado en el documento “html”, un elemento de título “h3” y se le ha dada un atributo con un identificador (id) llamado: “state”. Esto se hizo con la línea:
<h3 id=”state”></h3>
Así cuando recibimos un mensaje del broker, lo podemos mostrar en este elemento de título. Esto se hace con la línea:
document.getElementById(“state”).InnerHTML = message
Como hicimos una publicación al tópico: “x1x2x3x4/temp”, con un valor de: “30”, el navegador, muestra ese valor en la pantalla.
Cuando se desarrolla alguna aplicación en JavaScript es normal utilizar una herramienta llamada: “consola”, donde podemos ver y observar, como se está ejecutando el programa. Para esto es necesario usar la función de la consola así.
console.log(“”)
Dentro de los patentices de la función: “console.log()”, se escribe lo que deseamos observar en la consola, cuando esta función es ejecutada. Para el siguiente ejemplo se puede crear carpetas y archivos como sigue:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mqtt/4.3.7/mqtt.js">
</script>
<script src="/js/mqtt_min_log__web.js"></script>
</head>
<body>
<h3 id="state"></h3>
</body>
</html>
var client = mqtt.connect("ws://test.mosquitto.org:8080/mqtt")
function EventoConectar(){
console.log("connected.")
client.subscribe("x1x2x3x4/temp", function (err) {
console.log("subscribe to: x1x2x3x4/temp.")
if(!err){
client.publish("x1x2x3x4/temp", "30")
console.log("public to: x1x2x3x4/temp.")
}
})
}
function EventoMensaje(topic, message){
if(topic == "x1x2x3x4/temp"){
console.log("receive from the topic: " + topic + " the value: " + message)
document.getElementById("state").innerHTML = message
}
}
client.on("connect", EventoConectar)
client.on("message", EventoMensaje)
En el navegador se presiona la tecla: “F12” y podemos observar en la consola, los respectivos “logs” que se hicieron en el programa:
En los scripts es común el uso de variables para guardar los datos del programa que se está ejecutando. En el siguiente script, se ha creados dos variables llamadas:
• thisTopic
• value
Estas variables se han inicializado con los siguientes valores:
thisTopic = “x1x2x3x4/temp”
value = “17”
Para el siguiente ejemplo se pueden usar carpetas y archivos como se muestra:
Observa en el siguiente script, como se usan las variables para ejecutar el programa:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mqtt/4.3.7/mqtt.js">
</script>
<script src="/js/mqtt_min_var__web.js"></script>
</head>
<body>
<h3 id="state"></h3>
</body>
</html>
Script:
var client = mqtt.connect("ws://test.mosquitto.org:8080/mqtt")
thisTopic = "x1x2x3x4/temp"
value = "17"
function EventoConectar(){
console.log("connected.")
client.subscribe(thisTopic, function (err) {
console.log("subscribe to: " + thisTopic)
if(!err){
client.publish(thisTopic, value)
console.log("public to: " + thisTopic)
}
})
}
function EventoMensaje(topic, message){
if(topic == thisTopic){
console.log("receive from the topic: " + topic +
" the value: " + message)
document.getElementById("state").innerHTML = message
}
}
client.on("connect", EventoConectar)
client.on("message", EventoMensaje)
La salida en el navegador y en la consola, es el mismo del programa anterior como se muestra en la siguiente imagen:
Como los navegadores son usados en el mundo entero, es común haber muchos formatos de caracteres. Para el caso de este programa es necesario usar el formato: “utf-8”. Para esto usamos el elemento <meta> con un atributo llamado: “charset”. Esta línea se coloca en la cabecera (head) del documento:
<meta charset="utf-8">
Así, el navegador, no muestra caracteres extraños cuando digitemos en las variables algún texto con tildes u otros caracteres poco comunes.
Otra técnica usada cuando se desarrollan programas es usar variables para indicarnos el estado de un programa. Así, por ejemplo, cuando se ejecute un determinado bloque de código, podemos incrementar un contador o asignar algún dato a una variable y saber en el navegador lo que ha sucedido. Para el caso de este programa, hemos agregado las siguientes variables, para ver el estado del programa:
let connected = “No”
let subs = 0
let pubs = 0
let topics_temp = 0
let topics_totals = 0
La variable: “connected”, la usamos para saber si el programa se pudo comunicar con el broker. La variable: “subs” es un contador que se incrementa cuando el programa hace una suscripción en el broker. La variable: “pubs” es un contador que se incrementa cuando el programa hace una publicación en el broker. La variable: “topics_temp” es un contador que se incrementa cuando el programa recibe un mensaje del broker, con el tópico: “x1x2x3x4/temp”. La variable: “topics_totals” es un contador que se incrementa cuando el programa recibe cualquier mensaje del broker. Así, podemos incrementar los contadores en sus debidos lugares donde tiene efecto cada propósito y llamar la función: “update()”, la cual se encarga de dar formato a estas variables y mostrarlas en el elemento de párrafo con el identificador: “state”.
Para el siguiente ejemplo se puede hacer carpetas y archivos como sigue:
El programa para hacer esto, sería el siguiente:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/mqtt/4.3.7/mqtt.js">
</script>
<script src="/js/mqtt_min_state__web.js"></script>
</head>
<body>
<p id="state"></p>
</body>
</html>
Script
var client = mqtt.connect("ws://test.mosquitto.org:8080/mqtt")
const thisTopic = "x1x2x3x4/temp"
const value = "17"
let connected = "No"
let subs = 0
let pubs = 0
let topics_temp = 0
let topics_totals = 0
function update(){
str = "State:: connected: " + connected +
" subs: " + subs + " pubs: " + pubs +
" topics_temp: " + topics_temp +
" topics_totals: " + topics_totals
document.getElementById("state").innerHTML = str
}
function EventoConectar(){
console.log("connected.")
connected = "Yes"
update()
client.subscribe(thisTopic, function (err) {
console.log("subscribe to: " + thisTopic)
subs += 1
update()
if(!err){
client.publish(thisTopic, value)
console.log("public to: " + thisTopic)
pubs += 1
update()
}
})
}
function EventoMensaje(topic, message){
topics_totals += 1
update()
if(topic == thisTopic){
console.log("receive from the topic: " + topic +
" the value: " + message)
topics_temp += 1
update()
}
}
client.on("connect", EventoConectar)
client.on("message", EventoMensaje)
El navegador, ahora nos muestra una línea con información del estado del programa como muestra la siguiente figura:
El próximo paso, es agregar dos botones al documento “html” con sus respectivos eventos en el script. Para hacer esto usaremos el elemento: “<button>”, en el documento “html” así:
<button onclick= ”subscription()”> Subscription </button>
<button onclick= ”publication()”> Publication </button>
En el script se crean dos funciones que se llaman cuando es presionado el botón. Cada botón tiene su respectiva función: “onclick”. El elemento <br> es para que el navegador genere un espacio entre los botones. Este elemento, no necesita de una etiqueta de cierre, como se muestra en el siguiente programa:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/mqtt/4.3.7/mqtt.js">
</script>
<script src="/js/mqtt_min_btns__web.js"></script>
</head>
<body>
<p id="state"></p>
<button onclick="subscription()">Subscription</button>
<br>
<br>
<button onclick="publication()">Publication</button>
</body>
</html>
Script
var client = mqtt.connect("ws://test.mosquitto.org:8080/mqtt")
const thisTopic = "x1x2x3x4/temp"
const value = "17"
let connected = "No"
let subs = 0
let pubs = 0
let topics_temp = 0
let topics_totals = 0
function subscription(){
}
function publication(){
}
function update(){
str = "State:: connected: " + connected +
" subs: " + subs + " pubs: " + pubs +
" topics_temp: " + topics_temp +
" topics_totals: " + topics_totals
document.getElementById("state").innerHTML = str
}
function EventoConectar(){
console.log("connected.")
connected = "Yes"
update()
client.subscribe(thisTopic, function (err) {
console.log("subscribe to: " + thisTopic)
subs += 1
update()
if(!err){
client.publish(thisTopic, value)
console.log("public to: " + thisTopic)
pubs += 1
update()
}
})
}
function EventoMensaje(topic, message){
topics_totals += 1
update()
if(topic == thisTopic){
console.log("receive from the topic: " + topic +
" the value: " + message)
topics_temp += 1
update()
}
}
client.on("connect", EventoConectar)
client.on("message", EventoMensaje)
El navegador muestra los botones como se ve en la siguiente imagen:
En el siguiente programa, se han retirado la suscripción y la publicación de las funciones: “EventoConectar” y “EventoMensaje” y se han escrito en los eventos de los botones como se muestra a continuación:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/mqtt/4.3.7/mqtt.js">
</script>
<script src="/js/mqtt_min_btns__web.js"></script>
</head>
<body>
<p id="state"></p>
<button onclick="subscription()">Subscription</button>
<br>
<br>
<button onclick="publication()">Publication</button>
</body>
</html>
Script
var client = mqtt.connect("ws://test.mosquitto.org:8080/mqtt")
const thisTopic = "x1x2x3x4/temp"
const value = "17"
let connected = "No"
let subs = 0
let pubs = 0
let topics_temp = 0
let topics_totals = 0
function subscription(){
client.subscribe(thisTopic, function (err) {
console.log("subscribe to: " + thisTopic)
subs += 1
update()
})
}
function publication(){
client.publish(thisTopic, value)
console.log("public to: " + thisTopic)
pubs += 1
update()
}
function update(){
str = "State:: connected: " + connected +
" subs: " + subs + " pubs: " + pubs +
" topics_temp: " + topics_temp +
" topics_totals: " + topics_totals
document.getElementById("state").innerHTML = str
}
function EventoConectar(){
console.log("connected.")
connected = "Yes"
update()
}
function EventoMensaje(topic, message){
topics_totals += 1
update()
if(topic == thisTopic){
console.log("receive from the topic: " + topic +
" the value: " + message)
topics_temp += 1
update()
}
}
client.on("connect", EventoConectar)
client.on("message", EventoMensaje)
La siguiente es la salida del navegador para el anterior programa. Observa que ahora los contadores se incrementan cuando son presionados los botones y en la consola se observa la respectiva acción:
Vamos a agregar tres cajas de texto para poder editar los tópicos y el valor a publicar. Para esto usamos el elemento: “<input>”, así:
<input type=”text” value=”Type here the topic”>
El elemento <input> no tiene etiqueta de cierre. El siguiente programa crea las cajas de texto:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/mqtt/4.3.7/mqtt.js">
</script>
<script src="/js/mqtt_min_btns__web.js"></script>
</head>
<body>
<p id="state"></p>
<input type="text" value="Type here the topic">
<button onclick="subscription()">Subscription</button>
<br>
<br>
<input type="text" value="Type here the topic">
<br>
<br>
<input type="text" value="Type here the value">
<button onclick="publication()">Publication</button>
</body>
</html>
El navegador muestra la página con los elementos: caja de texto, así:
Ahora, se le da un identificador a cada caja de texto, para poderlas usar en el script. También agregamos dos elementos de título para separar la sección de suscripción y publicación, así:
<h3> Subcription </h3>
<h3> Publicationtion </h3>
Agregamos un párrafo, para ver el tópico y su valor, cuando el broker envía un mensaje, así:
<p id=””subscriptionReceive”> receive from the topic: </p>
El programa sería el siguiente:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/mqtt/4.3.7/mqtt.js">
</script>
<script src="/js/mqtt_min_btns__web.js"></script>
</head>
<body>
<p id="state"></p>
<h3>Subscription:</h3>
<p>Topic:</p>
<input type="text" id="subscriptionTopicText" value="Type here the topic sub">
<button onclick="subscription()">Subscription</button>
<br>
<p id="subscriptionReceive">receive from the topic:</p>
<br>
<br>
<h3>Publication:</h3>
<p>Topic:</p>
<input type="text" id="publicationTopicText" value="Type here the topic pub">
<br>
<br>
<p>Message:</p>
<input type="text" id="publicationMessageText" value="Type here the message pub">
<button onclick="publication()">Publication</button>
</body>
</html>
Script
var client = mqtt.connect("ws://test.mosquitto.org:8080/mqtt")
var subscriptionTopicTextElem
let connected = "No"
let subs = 0
let pubs = 0
let topics_temp = 0
let topics_totals = 0
function subscription(){
subscriptionTopicTextElem = document.getElementById("subscriptionTopicText")
client.subscribe(subscriptionTopicTextElem.value, function (err) {
console.log("subscribe to: " + subscriptionTopicTextElem.value)
subs += 1
update()
})
}
function publication(){
var publicationTopicTextElem = document.getElementById("publicationTopicText")
var publicationMessageTextElem = document.getElementById("publicationMessageText")
client.publish(publicationTopicTextElem.value, publicationMessageTextElem.value)
console.log("public to: " + publicationTopicTextElem.value)
pubs += 1
update()
}
function update(){
str = "State:: connected: " + connected +
" subs: " + subs + " pubs: " + pubs +
" topics_temp: " + topics_temp +
" topics_totals: " + topics_totals
document.getElementById("state").innerHTML = str
}
function EventoConectar(){
console.log("connected.")
connected = "Yes"
update()
}
function EventoMensaje(topic, message){
topics_totals += 1
update()
if(topic == subscriptionTopicTextElem.value){
resultStr = "receive from the topic:: " + "'" + topic + "'" +
" the message:: " + "'" + message+ "'"
console.log(resultStr)
document.getElementById("subscriptionReceive").innerHTML = resultStr
topics_temp += 1
update()
}
}
client.on("connect", EventoConectar)
client.on("message", EventoMensaje)
El navegador muestra los elementos así:
Se puede probar suscribirse y publicar en el tópico que desee. Tenga en cuenta que, para recibir algún mensaje, el tópico debe ser el mismo. Si por acaso recibe mensajes con valores diferentes, es porque alguien está publicando en un tópico similar.
Como podemos ver, incluir mensajes MQTT en una página web, es relativamente sencillo. Se pueden hacer muchas pruebas y observar el funcionamiento. Tener en cuenta que MQTT, usa colas o filas (Queues) en su protocolo, por eso, los mensajes siempre llegan. Buenos proyectos con MQTT.