Home»Desarrollos»Medidor de consumo V2 – MQTT

Medidor de consumo V2 – MQTT

0
Shares
Pinterest WhatsApp

Tomando como base el proyecto de construcción de un medidor de consumo eléctrico, vamos a ver como podemos programar nuestro pequeño Arduino para trabajar utilizando el protocolo MQTT. En este articulo se cambiará la forma de enviar el consumo eléctrico al servidor y veremos como montar la infraestructura necesaria para trabajar con MQTT.

¿Qué es MQTT?

MQTT es un protocolo de mensajería ligero sobre TCP/IP. Este protocolo permite comunicar distintos dispositivos añadiendo poco peso a la información que deseamos enviar, con lo que es muy recomendable cuando hay mucho tráfico (muchos dispositivos enviando información a la vez) o el ancho de banda es reducido.

Para gestionar estos mensajes tendremos lo denominado «broker». Todos los dispositivos se conectarán a un broker que será el encargado de distribuir los mensajes al resto.

Este protocolo define varios métodos básicos para una publicación/suscripción:

  • Connect: Conexión a broker
  • Disconnect: Desconexión del broker
  • Suscribe: Suscripción a una lista
  • Unsuscribe. Desuscripción de una lista
  • Publish : Publicación ha una lista.

Un dipositivo que quiere enviar información se conectará a un broker y publicará unos datos sobre una lista definida. Un dispositivo que quiera recibir información de otro, se suscribirá a una lista para que el broker le haga llegar la información que se este publicando.

Más sobre MQTT

Elementos necesarios.

Nuestra configuración va a contar con los siguientes elementos:

  • Hardware. Medidor de consumo
    • Estará formado por un Arduino UNO con una interfaz ethernet y los componentes necesarios para conectar la pinza amperímetra.
    • También añadiremos un termómetro para recoger la temperatura ambiente.
  • Software.
    • Como broker utilizaremos Mosquitto. Rápido, ligero y fácil de instalar. También veremos como utilizar RabbitMQ, que además de actuar de broker, permite gestionar un sistema de colas que nos va a dar más posibilidades.
    • Aplicación NodeJS para consumo de los datos enviados por el Arduino

Diseño de nuestro sistema

Este es el diagrama de nuestro sistema:

El Arduino se comunicará de forma analógica con la pinza amperímetra y mediante el protocolo OneWire con el termómetro. Una vez conectado con Mosquitto enviará  un latido a la lista «status/topic». Con la información recogida de los sensores, publicará en las listas «consumo/topic» y «temperatura/topic».

La aplicación NodeJS se suscribirá a las listas consumo/topic y temperatura/topic y cada vez que le llegue un mensaje a alguna de estas listas, lo enviará a los navegadores conectados mediante websockets.

Programación de Arduino

El montaje del hardware con nuestro Arduino va a ser exactamente igual a los paso que ya hemos visto, pero vamos a incorporar un pequeño termómetro que nos irá dando la temperatura ambiental.

El sensor DS18D20 emplea un protocolo OneWire del que Arduino tiene una librería específica y nos permite configurar el pequeño termómetro indicando la precisión que necesitamos y recuperar la temperatura. Este protocolo nos permite conectar varios de estos termómetro utilizando un único cable de datos, lo hacer que co una n una única conexión digital del Arduino podamos trabajar con multitud de termómetros.

En otro artículo veremos como trabajar en detalle con este pequeño termómetro, y como podemos montar una red en nuestra casa para tener controlada la temperatura de todas las habitaciones.

Para trabajar con el protocolo MQTT importaremos la siguientes librerías en nuestro proyecto:

  • UIPEthernet: Librería para trabajar con nuestra interfaz ENC28J60. Github
  • PubSubClient: Librerñia para trabajar con MQTT. Github

Está será la lista de librerías de nuestro proyecto:

#include -SPI.h-
#include -UIPEthernet.h-                              
#include -PubSubClient.h-                                
#include -Wire.h-
#include -EmonLib.h-  
#include -OneWire.h-

Para configurar la interfaz de red y el cliente MQTT utilizaremos las siguientes variables:

byte mac[]      = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
byte ip[]       = { 192, 168, 1, 200 };   
 
byte server[] = { 192, 168, 1, 3 };              
//char server[]   = "xxx.xxxxxxx.xxx";                  
 
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);

Donde indicamos la MAC e IP de nuestro  Arduino, y la IP del broker MQTT. También declaramos los objetos que nos permitirán trabajar con la interfaz de red y el cliente MQTT, PubSubClient. Para crear el cliente debemos indicar los siguientes parámetros:

  • server: IP o nombre del broker
  • 1883: Puerto del broker
  • callback: Función que será llamada cuando se reciba algún mensaje desde el broker. El broker nos enviará mensajes si estamos suscritos a alguna lista.
  • ethClient: Cliente ethernet

En el método setup() inicializamos el cliente MQTT:

  Ethernet.begin(mac, ip);
  if (client.connect("arduinoClient")) {                
     client.publish("status/topic","connected");              
  }

Una vez hemos conectado al broker, publicamos en la lista «status/topic» el texto «connected». Así, si algún otro dispositivos o sistema está suscrito a la lista «status/topic», recibirá un mensaje con el texto «connected» siempre que el Arduino se conecte.

En el método loop() iremos leyendo el termómetro y el consumo de forma periódica, muy similar a como ya lo hacíamos antes, y enviaremos la información al broker con los siguientes métodos:

        client.publish("consumo/topic",PowerChar); 
        client.publish("temperatura/topic",celsiusChar);

Estos dos publish enviarán a 2 listas diferentes el consumo y la temperatura

Por último, verificaremos la conexión al broker por si ha habido algún problema. Volveremos a conectarnos si es necesario, y volveremos a enviar el latido a la lista «status/topic».

if (!client.connected()) {
    if (client.connect("arduinoClient")) {              
       client.publish("status/topic","connected");              
    }
  }

Os podéis descargar el programa completo de la lista dirección: MedidorConsumoMQTT.ino

Puesta en marcha de Mosquitto

La instalación de Mosquitto es muy sencilla, empleando el gestor de paquetes de nuestra distribución linux, en un par de comandos podemos tenerlo en marcha. Para el caso de CentOS, serían los siguientes comandos:

  • Intalar mosquitto: yum install mosquitto
  • Configurar el servicio de mosquitto para que arranque al iniciar la máquina: systemctl enable mosquitto
  • Arrancar mosquitto: systemctl start mosquitto
  • Permitir el acceso al puerto 1883 en nuestro firewall

Para publicar algo en mosquitto tenemos el siguiente comando, indicado la lista con la opción»-t» y el mensaje con la opción «-m»:

  • mosquitto_pub -t ‘temperatura/topic’ -m ’25’

Para suscribirnos a una lista

  • mosquitto_sub -v -t ‘temperatura/topic’

Si hay alguien publicando en la lista ‘temperatura/topic’ veríamos por consola algo parecido a esto:

El valor 25 es el enviado de forma manual con el comando «mosquitto_pub», el resto de valores es el Arduino publicando en la misma lista.

Aplicación NodeJS

La idea de este post no es explicar como se desarrolla sobre NodeJS, sino como conectarnos a Mosquitto y consumir la información enviada por Arduino. Existen cientos de tutoriales que os puede introducir a este framework.

La aplicación NodeJS levantará un servidor web con soporte de Websockets, se conectará a Mosquitto a las listas de consumo y temperatura, e irá enviando a cada uno de los clientes conectados por websocket los datos actualizados.

Incluiremos la librería mqtt en nuestro programa y conectaremos con el broker. En mi caso se encuentran en la misma máquina, con lo que la dirección es localhost.

var mqtt = require('mqtt')
var client  = mqtt.connect('mqtt://localhost')

Nos suscribiremos a las listas «consumo/topic» y «temperatura/topic»

client.on('connect', function () {
  client.subscribe('consumo/topic')
  client.subscribe('temperatura/topic')
})

Para cada mensaje, lo tratamos y montamos un mensaje JSON que enviaremos a los clientes:

client.on('message', function (topic, message) {
  // message is Buffer 
  if(topic == 'consumo/topic') {
 	data = '{"irms":"'+message.toString()+'"}';
	irms = message.toString();
  } else {
      data = '{"temperatura":"'+message.toString()+'"}';
	temperatura = message.toString();
  }
 
  updateSockets(data);
})

La función updateSockets() se encarga de enviar el JSON a cada cliente conectado.

El resto de código es para la gestión de los clientes por websocket, con lo que no es interesante comentarlo para el tema que nos trata de MQTT.

Aquí tenéis el programa completo:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var path = require('path');
var mqtt = require('mqtt')
var client  = mqtt.connect('mqtt://localhost')
var connectionsArray = [];
 
var temperatura=0;
var irms=0;
 
client.on('connect', function () {
  client.subscribe('consumo/topic')
  client.subscribe('temperatura/topic')
})
 
client.on('message', function (topic, message) {
  // message is Buffer 
  if(topic == 'consumo/topic') {
 	data = '{"irms":"'+message.toString()+'"}';
	irms = message.toString();
  } else {
      data = '{"temperatura":"'+message.toString()+'"}';
	temperatura = message.toString();
  }
 
  updateSockets(data);
})
 
 
io.on('connection', function(socket){
	console.log('Number of connections:' + connectionsArray.length);
 
	socket.on('disconnect', function(){
		var socketIndex = connectionsArray.indexOf(socket);
    		console.log('socketID = %s got disconnected', socketIndex);
    		if (~socketIndex) {
      			connectionsArray.splice(socketIndex, 1);
	    	}
	});
 
 	console.log('A new socket is connected!');
 	connectionsArray.push(socket);
 
        data = '{"irms":"'+irms+'"}';
	 updateSockets(data);
 
      data = '{"temperatura":"'+temperatura+'"}';
	  updateSockets(data);
 
 
});
 
 
app.get('/', function (req, res) {
    res.sendFile(path.join(__dirname,'index.html'));
})
 
 
http.listen(3000, function(){
  console.log('listening on *:3000');
});
 
 
 
var updateSockets = function(data) {
  // adding the time of the last update
  data.time = new Date();
  console.log(data);
  connectionsArray.forEach(function(tmpSocket) {
    tmpSocket.emit('notification', data);
  });
};
 
console.log("Server started successfully!");

Sencillo cliente Websocket por javascript

Os dejo un sencillo cliente javascript para el tratamiento de la información, utilizado para mostrar los gráficos en tiempo real que podéis ver en la columna derecha de mi sitio web. Con Socket.IO abriremos un websocket, trataremo el mensaje recibido y utilizaremos la librería JustGage para dibujar un gráfico muy resultón.

<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.4/raphael-min.js"></script>
<script src="//cdn.jsdelivr.net/justgage/1.0.1/justgage.min.js"></script>
 
<script>
  var socket = io();
  socket.on('notification', function(msg){
          obj = JSON.parse(msg);
          if(obj.temperatura) {
                gTemperatura.refresh(obj.temperatura);
          }
          if(obj.irms) {
                gConsumo.refresh(obj.irms);
          }
  });
 
 
        var gTemperatura = new JustGage({
            id: "gaugeTemperatura",
            value: 0,
            min: 10,
            max: 30,
            title: "Temperatura ºC"
        });
 
        var gConsumo = new JustGage({
            id: "gaugeConsumo",
            value: 0,
            min: 0,
            max: 3000,
            title: "Consumo Wh"
        });
 
</script>

Próximos pasos

Más adelante veremos como instalar y configurar RabbitMQ para funcionar como broker y contar con una serie de colas que irán guardando los mensajes enviados por Arduino hasta que algún cliente los consumo o trate. Daros cuenta que Mosquitto solo es un broker que distribuye los mensajes pero no los almacena, con lo que la información siempre es en tiempo real.

También veremos como suscribirse desde Arduino a alguna lista para poder enviarle acciones que deba realizar.

 

Previous post

Receptor para sensores meteorlógicos Oregon

Next post

LoRa - Long Range (1/2)

1 Comment

  1. Dario
    17 septiembre, 2017 at 3:28 pm — Responder

    Excelente. Gracias por compartir

Leave a reply

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *