Sistema de riego sencilla: timelapse

Siempre me gustaron los timelapse, en especial cuando se trata de algún proceso natural donde vemos crecer algo, es por ello que decidí capturar imágenes durante el tiempo que tarde en crecer las lechugas.

Una imagen tomada hoy. La cámara esta fuera de fecha.

Para lograr esto voy a utilizar una cámara ip que compre en Aliexpress hace un tiempo, que utiliza un protocolo llamada RTSP para transmitir video en tiempo real.

Hace un tiempo había armado un video de como capturar imagen de la cámara ip utilizando Python, pueden verlo aquí:

El repositorio del código del ejemplo lo pueden encontrar:
https://github.com/gsampallo/ipcam_python

El mayor problema que tuve en esto fue lograr instalar opencv en la raspberry, si bien existen numerosos tutoriales en internet no quería descargar de cero y tener que compilarlo; opté por instalar la versión para python3 (junto con python3) por medio de apt, más adelante hablara más sobre este tema.

Esta es una primer aproximación, donde arme un pequeño script -llamado creativamente camara.py- que toma las imágenes de la cámara y lo guarda en formato png; las imágenes pesan alrededor de 2mb, será necesario más adelante preparar alguna otra tarea para que comprima las imágenes.

Usando cron se dejo programado en la raspberry (donde corre el script) para que ejecute la captura de imágenes cada 20 minutos; también hay un segundo script en bash que copia las imágenes a una carpeta especifica, las sube a un servidor ftp (para liberar espacio en la raspberry) y luego las elimina.

Cuando tenga imágenes de algunos días, voy a armar un pequeño timelapse de como avanza el proyecto, por lo pronto no queda más que esperar.

UPDATE

La página esta online, pueden verla acá:

https://gsampallo.com/riego/

La imagen se actualiza cada 5′, aún no corregí la fecha de la cámara.

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:


1
sudo apt install -y mosquitto mosquitto-clients

Luego para que se ejecute como servicio:


1
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


1
2
3
4
5
#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:


1
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:


1
[{"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:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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:


1
2
3
4
5
6
7
8
9
10
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.