MQTT a Excel

Un inconveniente que me suelo encontrar al trabajar con sensores remotos es el hecho de monitorear las mediciones y recolectar los datos de forma sencilla. Si bien existen herramientas geniales como ThingSpeak que nos permiten ver los datos en un gráfico; muchas veces trabajamos con equipos que solo implementan un protocolo MQTT y lo necesitamos para operar.

Para ello arme un pequeño programa en Python que permite conectarse a un servidor broker, suscribirse a uno o mas tópicos del servidor e ir registrando en una planilla de cálculo os datos de estos dispositivos remotos.

Además del nombre del servidor, toma el nombre con el que se va a guardar el archivo Excel y la cantidad de registros que deseamos almacenar; si no indicamos este ultimo parámetro la librería solo tomara 10 registros.

Serán los primeros 10 que lleguen, es decir si le indicamos que se suscriba a dos tópicos: TOPIC1 y TOPIC2, y recibimos 9 mensajes de TOPIC1 y solo 1 de TOPIC2 esos serán los 10 registros que se almacenaran en la planilla.

El link al repositorio es el siguiente:
https://github.com/gsampallo/mqtt2excel

Antes de comenzar a utilizarlo será necesario tener instalado Python en la pc además de dos librerías:

1. xlwt Para el manejo de la planilla de cálculo, se instala por medio de pip:

pip install xlwt

2. paho.mqtt brinda la posibilidad de conectarnos a un servidor broker, también lo instalamos por medio de pip:

pip install paho.mqtt

Luego que se haya completado el paso anterior, podemos editar el archivo example.py para adecuarlo a nuestro uso; solo necesitamos modificar en dos puntos:


1
2
3
4
5
6
7
8
9
10
11
12
13
from MQTT2Excel import MQTT2Excel

broker_server = "AQUI INDICAMOS EL SERVIDOR BROKER"

m2e = MQTT2Excel(broker_server,"demo1.xls")

m2e.setRecordsNumber(50) #indicamos que registre 50 lecturas (la suma de todos los mensajes de los topicos)

m2e.addTopics("TOPICO1") #Indicamos el nombre del topico al que queremos suscribirnos
# Si tuvieramos mas simplemente agregamos una linea con el nombre del segundo topico
# m2e.addTopics("TOPICO2")

m2e.start()

De esta forma el programa tomara 50 lecturas y las almacenara en una planilla excel junto con la fecha y hora en que fue recibido el mensaje.

Luego simplemente es cuestion de ejecutar el programa example.py (pueden cambiarle el nombre si lo desean)

Comenzaremos a ver los datos que llegan desde el dispositivo.

Al cabo de un tiempo tendremos completos los 50 registros (salvo que cambiemos la cantidad que requerimos) y el programa se detendrá.

En ese punto ya dispondremos de nuestro archivo excel.

Como se puede apreciar es bastante sencillo de utilizar, quedan algunas cosas por pulir por ejemplo parametrizar si el servidor broker requiere un usuario y clave (aunque solo basta agregar dos lineas); y llegado el caso detectar el tipo de dato que se recibe para formatear la celda, pero no es un problema mayor en mi caso.

Sistema de riego sencillo: el código

En artículos anteriores (Sistema de riego sencillo y el gabinete) fuimos construyendo paso a paso un sistema de riego automatizado para una maceta; en este articulo entraremos en detalle sobre el software utilizado para controlar el hardware.

El software se puede encontrar en el repositorio:
https://github.com/gsampallo/IrrigationSystem

El software se compone de dos partes:

  1. El software que corre en el NodeMCU, que se conecta a un servidor broker, publica cada 5 segundos el valor de la humedad y esta suscrito a un tema, al recibir un valor activa la bomba de agua por unos pocos segundos y al recibir otro valor la apaga.
  2. El software que corre del lado del servidor: lee el valor de la humedad y una vez al dia activa la bomba.

Sobre el software que corre en el nodemcu, solo copio los fragmentos que considero más interesantes:
La función callback (procesa los mensajes que llegan)


1
2
3
4
5
6
7
8
9
10
11
void callback(char* topic, byte* payload, unsigned int length) {

  if (((char)payload[0] == '1')) {
    estadoValvula = true;
    inicioRiego = millis();
  } else if (((char)payload[0] == '2')) {
    Serial.println("Se detiene el riego");
    estadoValvula = false;
    digitalWrite(pinValvula,HIGH);
  }
}

Al recibir el valor 1 en el mensaje cambia el estado a true de la variable global de estadoValvula y asigna a inicioRiego el valor de millis(); esto ultimo es para poder calcular cuanto tiempo estuvo activo el relay que prende la bomba de agua.

Sobre la funcion loop():


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  if(estadoValvula) {
    if ((millis() - inicioRiego) < finRiego) {
      digitalWrite(pinValvula,LOW);
      Serial.println("Regando");
    } else {
      digitalWrite(pinValvula,HIGH);
      estadoValvula = false;
      Serial.println("Se detiene el riego");
      client.publish("MACETA","2");
    }
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    lastDebounceTime = millis();
    int humedad = analogRead(A0);
    snprintf (msg, 75, "%ld", humedad);
   
    client.publish("HUMEDAD",msg);  
  }
}

Tenemos el primer bloque de código donde si el cliente esta desconectado del servidor broker, vuelve a conectarlo por medio de la funcion reconnect() y luego procesa los mensajes del servidor broker (client.,loop).

El segundo bloque de código evalúa la variable estadoValvula, si es true, determina si paso o no el tiempo establecido en finRiego (por defecto son 5 segundos), si aún no transcurrieron los 5 segundos mantiene activo el relay, caso contrario apaga el relay, cambia el estado de la variable estadoValvula y publica en el tema «MACETA» el valor 2.

Esto ultimo es para que los dispositivos que están utilizando ese tema para activar la bomba o no, pueda saber que se apago y cambien el estado de su interfaz (útil para la app MQTT Dash).

El ultimo bloque de código es para publicar el valor del sensor de humedad cada 5 segundos.

Más adelante modificare el código para que el tiempo de riego y de publicación sean parámetros que los tome de la nube y el valor de la humedad se vea reflejado en un canal de ThingSpeak.