Leyendo datos de Thingspeak con MicroPython

Thingspeak es una de las plataformas más sencillas de utilizar cuando se incursiona en el mundo IoT, por un lado tenemos la potencia de Matlab que ayuda mucho si deseamos realizar algún análisis posterior a recabar los datos y por el otro su simpleza para utilizarla: solo basta registrarnos obtener un key e invocar a la librería adecuada.

En esta oportunidad nos interesa leer datos de Thingspeak desde MicroPython, tomaremos datos de un canal publico:

https://thingspeak.com/channels/548625/

Ofrece temperatura y humedad, datos sencillos, pero que nos sirven para testear el funcionamiento.

Thingspeak tiene la funcionalidad que ofrece la información de los canales públicos por medio de un JSON, desde donde podremos leer los datos, para acceder a los datos utilizaremos la url: https://api.thingspeak.com/channels/548625/feeds.json

(Simplemente luego del nro. del canal agregamos feeds.json)

Si la abrimos en el navegador, tendremos todos los datos publicados desde las ultimas horas, debemos tener en cuenta de ajustar la fecha y hora a la zona horaria correspondiente.

Si empleamos la web http://jsonviewer.stack.hu/ podremos ver el json en un formato que resulta mas fácil de interpretar, solo debemos presionar el botón «Load JSON Data» y copiar la url, debemos reemplazar https por http, puesto que jsonviewer no soporte https; luego tendremos un vista como la siguiente:

Como solo nos interesa la ultima medición emplearemos el argumento result para que nos devuelva solo un resultado:
https://api.thingspeak.com/channels/548625/feeds.json?results=1

Para leer los datos realizamos:

import json
import network
import urequests
import wlan

wlan.do_connect()

consulta = urequests.get("https://thingspeak.com/channels/548625/feeds.json?results=2")
data = consulta.json()

temp = data["feeds"][0]["field1"]

print("Temperatura: ",temp)

Raspberry Pi: MQTT Bridge

La historia es la siguiente: tengo varios dispositivos en casa que están conectados a un servidor broker en la nube, cuando por algún motivo no hay conexión a internet quedan totalmente offline y no se los puede controlar.

Una posible solución a esto, es utilizar de manera local una raspberry pi como servidor broker, que los dispositivos se conecten a ella y de esa forma controlar los eventos y las acciones que se produzcan en ellos. La ventaja es que eliminamos la necesidad de la conexión a un servidor externo, la contra es que perdemos la posibilidad de controlarlos de manera remota. Si no estoy conectado al WiFi de mi casa, no los puedo activar o recibir datos de los mismos.

La solución que quiero probar es realizar un punto intermedio, en donde los dispositivos se conecten a la raspberry pi dentro de la red local; la raspberry controle todos los eventos relacionados con los mismos; pero a la vez está se encuentre conectado (suscripta si utilizamos el termino correcto) a un servidor broker en la nube; de esta forma mantenemos el funcionamiento de los equipos en caso que se corte internet (las ordenes las tenemos que dar a la raspberry y ya no al servidor en la nube) y podemos darle instrucciones a los dispositivos desde cualquier lugar.

¿Como arrancamos?

Lo primero va a ser instalando Raspbian en la Raspberry Pi,, no voy a entrar en detalles puesto que existen numerosos tutoriales online donde se explican paso por paso.

Como segundo paso es instalar Mosquitto:

sudo apt install -y mosquitto mosquitto-clients

Luego para que se ejecute como servicio:

sudo systemctl enable mosquitto.service

No voy a entrar en el detalle de como securizar Mosquitto, en este punto solo necesitamos que se ejecute en la Raspberry Pi.

MQTT Bridge

MQTT Bridge es el termino utilizado para esta metodología que les comentaba; de esta forma se logra que por medio de la configuración de uno de los brokers (el que esta dentro de nuestra red lan) lograr nuestro objetivo.

Debemos modificar el archivo de configuración de Mosquitto en la raspberry pi, ubicado en /etc/mosquitto/mosquitto.conf

#Connection BrokerLan
connection bridge-01
address 198.41.30.241:1883

topic DEMO/LUCES both 0 "" ""

La primer linea indica el nombre de la conexion, luego especificamos cual es el servidor broker al que desemos conectarnos y que puerto.

En el ejemplo utilizamos la dirección IP del broker publico de Eclipse: iot.eclipse.org

Luego debemos indicar cuales son los tópicos sobre los cuales deseamos realizar el puente; en nuestro caso utilizaremos uno llamado DEMO/LUCES; indicamos el sentido: both, es decir que seria bidireccional tanto si lo cambiamos de manera local como remota, se publicara el mensaje en ambos brokers. También podemos indicar si es in o out. Luego indicamos el valor de QOS. Finalmente podemos remapear el topico a otro dependiendo de lo que busquemos; en nuestro caso dejamos «» para mantener el mismo.

Guardamos el archivo, y luego debemos reiniciar Mosquitto para que tome los cambios. Aquí podríamos darnos por hecho, configurando los dispositivos en nuestro hogar para que se conecten a la Raspberry Pi en lugar del servidor en la nube, podríamos tener todo funcionando.

¿Como lo probamos?

Quienes tengan experiencia utilizando node-red o configurando dispositivos con servicios broker podrian omitir esta prueba y simplemente configurarlos. Vemos un sencillo ejemplo, aunque algo extenso, de como trabaja Mosquitto en modo Bridge.

Utilizaremos Node-RED para publicar los mensajes en el servidor broker de la nube, los cuales serán retransmitidos por el servidor Mosquitto de la RPI a un nodemcu conectado en nuestra lan.

Para verificar el funcionamiento utilizaremos Node-Red en la misma Raspberry, para iniciarlo tenemos que ir al menu Inicio – Programming – Node-RED

Se abrira una terminal, y luego de que cargue los componentes podremos conectarnos a Node-Red; hay que tener en cuenta que el servicio solo esta disponible mientras que tengamos prendida la Raspberry Pi, si la apagamos debemos volver a iniciarlo. Para iniciarlo como servicio debemos ejecutar desde la terminal:

sudo systemctl enable nodered.service

Una vez que esta corriendo, abrimos un navegador y nos conectamos a la ip de la raspberry mas el puerto por defecto de Node-Red 1880.

Desde el menú de la izquierda, dentro del apartador Input, elegimos el item inject y lo arrastramos al área de trabajo:

Lo configuramos de la siguiente manera:


De la misma forma, agregamos un segundo nodo Inject pero lo configuramos con el valor de false y el nombre off.

Luego buscamos en el menu de la izquierda nuevamente, dentro del apartado output, el node llamada mqtt, lo conectamos a ambos nodos y lo configuramos para que se conecte al servidor publico de eclipse:


En las propiedades del nodo, indicamos que el topico que vamos a utilizar es DEMO/LUCES

Por ultimo desde el apartado de input buscamos el nodo mqtt, lo agregamos al area de trabajo, luego buscamos en el apartado de output el nodo debug y lo conectamos al mismo. Al nodo de mqtt lo configuramos para que se conecte al servidor broker local (la propia raspberry) y utilice le tópico DEMO/LUCES (de la misma manera que lo hicimos en el ejemplo anterior).

Va a quedar armado algo asi:

Para quienes quieran avanzar mas rapido y no tener que agregar nodo por nodo, puede importar todo el flujo de datos desde le Menu Import – Clipboard:

[{"id":"2f15244e.d6d11c","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"c199590a.8f9278","type":"inject","z":"2f15244e.d6d11c","name":"on","topic":"DEMO/LUCES","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":80,"wires":[["6cb4d45a.3bc25c"]]},{"id":"b19ada37.dccef8","type":"inject","z":"2f15244e.d6d11c","name":"off","topic":"DEMO/LUCES","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":140,"wires":[["6cb4d45a.3bc25c"]]},{"id":"6cb4d45a.3bc25c","type":"mqtt out","z":"2f15244e.d6d11c","name":"","topic":"DEMO/LUCES","qos":"","retain":"","broker":"bb0be034.08a1b","x":410,"y":120,"wires":[]},{"id":"17be2189.41824e","type":"mqtt in","z":"2f15244e.d6d11c","name":"","topic":"DEMO/LUCES","qos":"2","datatype":"auto","broker":"7e629599.3fb36c","x":140,"y":240,"wires":[["b96b0d7a.27869"]]},{"id":"b96b0d7a.27869","type":"debug","z":"2f15244e.d6d11c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":420,"y":240,"wires":[]},{"id":"bb0be034.08a1b","type":"mqtt-broker","z":"","name":"eclipse","broker":"iot.eclipse.org","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"7e629599.3fb36c","type":"mqtt-broker","z":"","name":"localhost","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]

En este punto, si tocamos cualquiera de los nodos para inyectar datos (on/off) veremos en el panel de debug los datos recibidos en nuestro broker local, como se refleja los datos que publicamos en el servidor publico.

Utilizaremos un nodemcu con MicroPython, que solo tendrá conectado un led:

y el siguiente programa corriendo:

import wlan
from machine import Pin
import time
from umqtt.simple import MQTTClient

wlan.do_connect()

led = Pin(4,Pin.OUT,0)

def encender(topico,mensaje):
    print(mensaje)
    if(mensaje == b'true'):
        led.on()
    if(mensaje == b'false'):
        led.off()

cliente = MQTTClient('micropython/cliente1','RASPBERRY_IP')
cliente.set_callback(encender)
cliente.connect()
cliente.subscribe(b"DEMO/LUCES")

while True:
    cliente.check_msg()
    time.sleep_ms(100)

Hay que recordar cambiar ‘RASPBERRY_IP’ por la dirección IP de la raspberry. También debemos agregar el archivo wlan para conectarse a nuestra red wifi:

def do_connect():
    import network
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('connecting to network...')
        wlan.connect('essid', 'password')
        while not wlan.isconnected():
            pass
    print('network config:', wlan.ifconfig())

Reemplazando essid y password por los correctos.

Luego que tengamos corriendo el programa en nuestro nodemcu, al inyectar los datos en el servidor broker publico veremos como el led se enciende o apaga dependiendo lo que ingresemos.

De esta forma podemos utilizar la Raspberry Pi como Bridge entre los dispositivos locales y un servidor en la nube.