miércoles, 27 de marzo de 2019

Revisión de datos con Raspberry pi y Grafana (II)

Raspberry Pi
Grafana

En esta segunda parte nos vamos a centrar en la instalacion y configuracion de Grafana.
Como ya avanzabamos en la primera parte de este articulo, Grafana es un software libre basado en licencia de Apache 2.0,2​ que permite la visualización y el formato de datos métricos. Permite crear cuadros de mando y gráficos a partir de múltiples fuentes.
Grafana tiene una documentación, a mi parecer, bastante completa, a la cual podemos acceder desde el apartado "Docs"
Para instalar Grafana en nuestra Raspberry Pi seguiremos los pasos detallados en el apartado de "Instalación para Ubuntu/Debian", en mi caso he optado por la instalación a través de repositorio APT.

Creamos el archivo:
# sudo nano /etc/apt/sources.list.d/grafana.list 
y añadimos
deb https://packages.grafana.com/oss/deb stable main
Agregamos la clave GPG
# curl https://packages.grafana.com/gpg.key | sudo apt-key add -
Actualizamos los repositorios
# sudo apt-get update
Instalamos Grafana
# sudo apt-get install grafana
Arrancamos el servicio
# sudo service grafana-server start
para que Grafana se habilite en el arranque
# sudo service grafana-server start

Para acceder a Grafana basta con teclear

http: // localhost: 3000 en nuestro navegador, nos solicita usuario y contraseña, por defecto admin/admin aunque nos pedirá que cambiemos la contraseña esta primera vez que entremos.


Una vez accedemos al escritorio


Desde aquí, podemos realizar todas las operaciones disponibles, por ejemplo, administrar usuarios, equipos, plugins, contraseñas....

Lo primero que vamos ha realizar, sera añadir un origen de datos, en nuestro caso MySQL, para ello, vamos a configuración y seleccionamos la opción "Data sources".
Nos muestra las opciones disponibles.


Seleccionamos MySQL
completamos los datos que solicita, "Host", "database", "user", "password".


Continuamos añadiendo un panel, este accederá a nuestra BBDD y realizara la lectura de los datos que seleccionemos, como puedes comprobar, realiza una Query de SQL, pero con el "Constructor" se convierte en una tarea para cualquiera, aunque no sepas nada de SQL.


Daremos formato al panel.


Y por ultimo, completamos nombre y resumen.


Guardaremos el panel mediante la opción correspondiente del menú superior.


Mediante el apartado de opciones del panel podemos configurar diferentes opciones del panel.


Y finalmente, visualizaremos de la siguiente forma al añadir varios paneles.


Otro tipo de panel que podemos definir es del tipo "Gráfico"


para ello, definiremos un tipo de panel nuevo, y seleccionamos "Choosse Visualization"


Aquí seleccionamos el tipo de gráfico que deseamos, "Graph"


Vamos rellenando opciones, Origen de datos


Modo de visualización y tipo de valores a visualizar




Damos nombre y definición al panel


y salvamos.

Bien, hasta aquí esta aproximación a Grafana, como has podido ir viendo, admite muchas opciones y visualizaciones, para ello, te recomiendo que veas la documentación que esta disponible en la misma web de grafana.

Revisión de datos con Raspberry pi y Grafana (I)

Raspberry Pi
Grafana

Lo reconozco, Grafana me ha sorprendido y he querido realizar este articulo para explicar como ha sido esta aproximación.
Lo primero, ¿que es Grafana? Pues se trata de un software libre, basado en Apache y nos permite la visualización de datos mediante cuadros de mando.
De una forma mas clara, nos sirve para mostrar gráficas de nuestros datos "IOT".
Aprovechando que tenia un nuevo sensor, um BME280, el cual recoge temperatura, humedad y presión atmosférica, he realizado un pequeño proyecto para tener esta primera toma de contacto con Grafana, Vamos con ello.
Básicamente, lo que vamos ha realizar es tomar los datos del sensor BME280, mostrarlos en pantalla y registrarlos en una Base de datos MySQL para luego, mediante Grafana acceder a ellos y analizar estos datos.

En esta primera parte nos vamos a centrar en como conectar el BME280 y el programa necesario para obtener los datos del sensor.

¿que necesitamos?

  • Raspberry Pi
  • Sensor BME280
  • Cables de conexión
  • Protoboard

El esquema de conexión es el siguiente:


Este sensor admite conexiones por I2C o por SPI, en este caso he optado por I2C, no olvidéis activar este tipo de conexión en las opciones de configuración de vuestra Raspberry, Preferencias - Configuración de Raspberry Pi - Interfaces.

Crearemos nuestra base de datos MySQL, para ello utilizaremos PhpMyAdmin. puedes revisar la instalación en la entrada anterior del blog:

Servidor Web con Raspberry Pi y Arduino (II)


la base de datos la he llamado "BME280", contiene una sola tabla "Valores" y los campos contenidos son:

  • Id  - INT(11)
  • Temperatura  - Float (10,2)
  • Humedad  - Float (10,2)
  • Presion  - Float (10,2)
  • Altitud  - Float (10,2)
  • Registro  - Timestamp
En el repositorio de Github podéis encontrar el archivo BME280.sql para crear esta tabla


Para el código, teniendo en cuenta que se ejecutara en Raspberry he utilizado Python, este es el ejecutable completo:

import mysql.connector
import time 
import board
import busio
import adafruit_bme280
i2c = busio.I2C(board.SCL, board.SDA)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)
bme280.sea_level_pressure = 1013.25

while True:
   Temperatura = "%0.2f" % bme280.temperature 
   Humedad = "%0.2f" % bme280.humidity
   Presion = "%0.2f" % bme280.pressure
   Altitud = "%0.2f" % bme280.altitude 

   print ("\nTemperatura: " + Temperatura + " ºC")
   print ("Humedad: " + Humedad + " % H")
   print ("Presión: " + Presion + " hPa")
   print ("Altitud: " + Altitud + " metros")

   con = mysql.connector.connect(host='localhost', database='BME280', user='TU_USER', password='TU_CONTRASEÑA')
   cursor= con.cursor()
   cursor.execute("INSERT INTO Valores (Temperatura, Humedad, Presion, Altitud) VALUES (%s, %s, %s, %s)" %(Temperatura, Humedad, Presion, Altitud))

   con.commit()
   cursor.close()
   con.close()
   time.sleep(60)

A tener en cuenta, tendremos que instalar dos librerías:

  • MySQL Connector (en mi caso, al utilizar Thonny Python IDE, he instalado la librería mediante la utilidad que incorpora, Tools-Manage Plugin pero con el comando: pip3 install mysql-connector se realizara la instalación)
  • Adafruit bme280 (Esta librería también es posible realizar la instalación desde Thonny Python IDE)
una vez conectado, creada la base de datos y salvado el archivo "BME280_MySQL.py", podremos ejecutarlo mediante:

 #python3 BME280_MySQL.py

nos mostrara en pantalla, cada 60 segundos, los valores correspondientes a temperatura, humedad, presión atmosférica y altitud.
También, para comprobarlo deberemos ir a "phpmiadmin", no estará registrando el la base de datos BME280 estos valores.

Para comprobar la dirección I2C de nuestro sensor usaremos el comando:
i2cdetect -y 1
esto nos mostrara una tabla con las direcciones asignadas.

En /usr/local/lib/python3.5/dist-packages encontramos el fichero adafruit_bme280.py por defecto, la dirección asignada es:

_BME280_ADDRESS = const(0x76) 

Si no coincide con la mostrada por el comando i2cdetect podemos modificar el fichero.
Bien, hasta aquí esta primera parte, continuamos en:

Revisión de datos con Raspberry pi y Grafana (II)



viernes, 25 de enero de 2019

Servidor Web con Raspberry Pi y Arduino (Bonus)


Para la instalación del Servidor FTP debemos abrir una ventana de consola y teclear:

# sudo apt-get install proftpd

Después de aceptar la instalación, tendremos el servidor FTP funcionando.
para este servidor, como para el resto, podemos acceder a webmin, navegar al apartado de servidores y realizar cambios en la configuración.
No tenemos mas que configurar un cliente FTP, por ejemplo Filezilla, para acceder via FTP desde cualquier otra maquina.

Para la instalación del IDE Arduino, debemos teclear en una ventana de consola:

# sudo apt-get install arduino arduino-core 

esto nos creara un acceso directo al programa en el grupo de "Programación".
Para conectar nuestro arduino por el puerto serie, a traves del USB, a Raspberry,normalmente, usaremos el dispositivo /dev/ttyACM0
para asegurarnos, teclear desde consola
# ls /dev/tty* 

sin conectar Arduino, conectar ahora Arduino y volver a teclear

# ls /dev/tty* 

el dispositivo nuevo es el que conecta nuestra Raspberry con Arduino.

 La instalación de Fritzing la podemos realizar desde:
Preferencias
 Add - Revome Software
en el campo de Búsqueda escribimos Fritzing
Seleccionar las 3 opciones que nos muestra y "Apply"

O bien tecleamos en una ventana de consola:

# sudo apt-get install fritzing, fritzing-data

(Debemos instalar, por una parte programa y por otra la base "parts").
Esto nos crea un acceso directo en el grupo "Programación".

Para terminar, os dejo algunos comandos útiles a la hora de Instalar / Actualizar programas.

# sudo apt-get update Actualiza las listas de repositorios

# sudo apt-get upgrade Actualiza los paquetes instalados desde repositorios modificando, si es necesario dependencias.

# sudo apt-get autoremove Quita paquetes que no se están usando.

# sudo apt --fix-broken install Repara dependencias de paquetes rotas.

# sudo apt-get dist-upgrade Actualiza los paquetes instalados desde repositorios.

Y recordar siempre, que es conveniente realizar copia de la tarjeta SD, como hemos descrito en la primera entrada, así, podremos recuperar los puntos de instalación en cualquier momento.

Servidor Web con Raspberry Pi y Arduino (V)


Comenzamos esta 5 entrada creando la base de datos donde vamos a almacenar los datos del sensor DHT22 conectado a Arduino, para ello, accedemos a "PHPMyAdmin" de nuestra Raspberry, abrimos ventana de navegador, también se ha creado un acceso directo en el grupo de "Programación", en la dirección escribimos:

localhost/phpmyadmin

nos solicita los datos de conexión


 y accedemos a la pantalla general, aqui seleccionamos "Bases de datos" y en el cuadro para crear escribimos:
Datos_Casa 
y pulsamos en crear


Una vez creada la base de datos, la seleccionamos y accedemos a ella.
Vamos a la opción del menú superior "Importar"


Aquí debemos seleccionar el fichero "Datos_Casa.sql" (incluido en el enlace de descarga)

pulsamos "Continuar".

Esto nos importara dos tablas, Temperatura y Humedad, las cales constan de cuatro campos:


  • Id (Campo automático, se trata de un indice)
  • Sonda (Recoge el identificador del sensor, en este caso siempre sera "DHT22")
  • Temperatura / Humedad (Recoge el valor reportado por Arduino)
  • Registro (Recoge fecha y hora de la toma del valor)


Para publicar la web, debemos copiar el contenido del la carpeta "Web" del compartido del proyecto en la ruta /var/www/html de nuestra Raspverry.
quedando:

  • /var/www/html
    • asset
    • Includes
    • actual.php
    • enlaces.php
    • index.php

En el fichero "enlaces.php" debemos editar las direcciones IP que hacen las diferentes llamadas.
Al igual, en el fichero "Conexion.login.php", deberemos modificar para que estas direcciones sean las correspondientes a nuestra Raspberry.
Para realizar la grafica hemos utilizado la biblioteca JavaScript "highcharts".
Para realizar el contador de la medida actual hemos utilizado la biblioteca "zingchart".
Para el diseño del frontend hemos utilizado "Paper Dashboard 2" de "Creative Tim"

Puedes descargar todos los ficheros del proyecto desde el siguiente enlace:

Si descargas el fichero comprimido, este incluye todos los contenidos, puede comprobar su integridad con:
MD5 Sum: 3ef7748a9f032f2e9c5164d79613fb95

Como punto final, te remito a la ultima entrada de la serie, la hemos llamado "Bonus"

Servidor Web con Raspberry Pi y Arduino (IV)


Comenzamos con esta cuarta entrada de la serie


Vamos a importar el Flow a Node-Red,
para ello, accedemos al menú, seleccionamos "Import" y "Clipboard"


Pegamos el código en el cuadro, seleccionamos "new flow" y pulsamos en "Import"



Aqui os dejo el codigo a seleccionar y pegar en Node-Red:

[
    {
        "id": "dfe6370a.f00358",
        "type": "tab",
        "label": "Principal",
        "disabled": false,
        "info": "#Flujo principal"
    },
    {
        "id": "b7eb854a.f45398",
        "type": "tab",
        "label": "Dashboard Principal",
        "disabled": false,
        "info": ""
    },
    {
        "id": "2b414f0b.a48fc",
        "type": "tab",
        "label": "Dashboard Gráficas",
        "disabled": false,
        "info": "Toda la lógica para hacer el **Dashboard**"
    },
    {
        "id": "b9524c18.77f51",
        "type": "tab",
        "label": "Debug",
        "disabled": false,
        "info": "Hacer debug de diversas variables"
    },
    {
        "id": "4c96b4f7.55223c",
        "type": "subflow",
        "name": "Subflow 2",
        "info": "Ejemplo que entra un dato y saca dos",
        "in": [
            {
                "x": 121,
                "y": 224,
                "wires": []
            }
        ],
        "out": [
            {
                "x": 458,
                "y": 335,
                "wires": [
                    {
                        "id": "4c96b4f7.55223c",
                        "port": 0
                    }
                ]
            },
            {
                "x": 459,
                "y": 131,
                "wires": [
                    {
                        "id": "4c96b4f7.55223c",
                        "port": 0
                    }
                ]
            }
        ]
    },
    {
        "id": "ceaaef77.911d5",
        "type": "mqtt-broker",
        "z": "",
        "name": "",
        "broker": "XXX.XXX.XXX.XXX",
        "port": "1883",
        "clientid": "",
        "usetls": false,
        "compatmode": true,
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "closeTopic": "",
        "closePayload": "",
        "willTopic": "",
        "willQos": "0",
        "willPayload": ""
    },
    {
        "id": "6f470621.f90a18",
        "type": "ui_group",
        "z": "",
        "name": "Arduino MQTT demo",
        "tab": "6f94a243.eb5c3c",
        "disp": true,
        "width": "20",
        "collapse": false
    },
    {
        "id": "217efb02.050674",
        "type": "ui_base",
        "theme": {
            "name": "theme-dark",
            "lightTheme": {
                "default": "#0094CE",
                "baseColor": "#0094CE",
                "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
                "edited": true,
                "reset": false
            },
            "darkTheme": {
                "default": "#097479",
                "baseColor": "#097479",
                "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
                "edited": true,
                "reset": false
            },
            "customTheme": {
                "name": "Untitled Theme 1",
                "default": "#4B7930",
                "baseColor": "#4B7930",
                "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
            },
            "themeState": {
                "base-color": {
                    "default": "#097479",
                    "value": "#097479",
                    "edited": false
                },
                "page-titlebar-backgroundColor": {
                    "value": "#097479",
                    "edited": false
                },
                "page-backgroundColor": {
                    "value": "#111111",
                    "edited": false
                },
                "page-sidebar-backgroundColor": {
                    "value": "#000000",
                    "edited": false
                },
                "group-textColor": {
                    "value": "#0eb8c0",
                    "edited": false
                },
                "group-borderColor": {
                    "value": "#555555",
                    "edited": false
                },
                "group-backgroundColor": {
                    "value": "#333333",
                    "edited": false
                },
                "widget-textColor": {
                    "value": "#eeeeee",
                    "edited": false
                },
                "widget-backgroundColor": {
                    "value": "#097479",
                    "edited": false
                },
                "widget-borderColor": {
                    "value": "#333333",
                    "edited": false
                },
                "base-font": {
                    "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
                }
            },
            "angularTheme": {
                "primary": "indigo",
                "accents": "blue",
                "warn": "red",
                "background": "grey"
            }
        },
        "site": {
            "name": "Node-RED Dashboard",
            "hideToolbar": "false",
            "allowSwipe": "false",
            "allowTempTheme": "true",
            "dateFormat": "DD/MM/YYYY",
            "sizes": {
                "sx": 48,
                "sy": 48,
                "gx": 6,
                "gy": 6,
                "cx": 6,
                "cy": 6,
                "px": 0,
                "py": 0
            }
        }
    },
    {
        "id": "6f94a243.eb5c3c",
        "type": "ui_tab",
        "z": "",
        "name": "Home",
        "icon": "dashboard",
        "order": 1
    },
    {
        "id": "8e98db81.56b278",
        "type": "ui_tab",
        "z": "",
        "name": "Graficas",
        "icon": "dashboard",
        "order": 2
    },
    {
        "id": "c459d64a.e76478",
        "type": "ui_group",
        "z": "",
        "name": "Sonda 1",
        "tab": "8e98db81.56b278",
        "order": 2,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "5a6e8e22.04dee",
        "type": "MySQLdatabase",
        "z": "",
        "host": "XXX.XXX.XXX.XXX",
        "port": "3306",
        "db": "Datos_Casa",
        "tz": ""
    },
    {
        "id": "d8de668d.fa0568",
        "type": "ui_group",
        "z": "",
        "name": "Sonda 2",
        "tab": "8e98db81.56b278",
        "order": 2,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "5e903ef1.5a837",
        "type": "ui_group",
        "z": "",
        "name": "Sonda 2",
        "tab": "6f94a243.eb5c3c",
        "order": 3,
        "disp": true,
        "width": "10",
        "collapse": false
    },
    {
        "id": "f2df5ea4.c9069",
        "type": "ui_group",
        "z": "",
        "name": "LED",
        "tab": "6f94a243.eb5c3c",
        "order": 4,
        "disp": true,
        "width": "10",
        "collapse": false
    },
    {
        "id": "17717577.6514fb",
        "type": "inject",
        "z": "dfe6370a.f00358",
        "name": "Temperatura",
        "topic": "Temperatura",
        "payload": "25.5",
        "payloadType": "num",
        "repeat": "",
        "crontab": "",
        "once": false,
        "x": 277.7500457763672,
        "y": 343.58331298828125,
        "wires": [
            [
                "d556c662.1be7f8"
            ]
        ]
    },
    {
        "id": "d556c662.1be7f8",
        "type": "mqtt out",
        "z": "dfe6370a.f00358",
        "name": "",
        "topic": "Temperatura",
        "qos": "",
        "retain": "",
        "broker": "ceaaef77.911d5",
        "x": 581.5000457763672,
        "y": 343.58331298828125,
        "wires": []
    },
    {
        "id": "b6c85aea.284958",
        "type": "debug",
        "z": "b9524c18.77f51",
        "name": "",
        "active": false,
        "console": "false",
        "complete": "false",
        "x": 510,
        "y": 100,
        "wires": []
    },
    {
        "id": "fda3eb3c.7ce8b8",
        "type": "mqtt in",
        "z": "b9524c18.77f51",
        "name": "Hora",
        "topic": "Hora",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 150,
        "y": 40,
        "wires": [
            [
                "b6c85aea.284958"
            ]
        ]
    },
    {
        "id": "f9740df2.c76c",
        "type": "mqtt in",
        "z": "b9524c18.77f51",
        "name": "",
        "topic": "reconnect",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 160,
        "y": 340,
        "wires": [
            [
                "b6c85aea.284958"
            ]
        ]
    },
    {
        "id": "731d7b1f.6fe284",
        "type": "mqtt in",
        "z": "b9524c18.77f51",
        "name": "",
        "topic": "Temp_1",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 150,
        "y": 160,
        "wires": [
            [
                "b6c85aea.284958"
            ]
        ]
    },
    {
        "id": "db21aff1.900f5",
        "type": "mqtt in",
        "z": "b9524c18.77f51",
        "name": "",
        "topic": "Hum_1",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 150,
        "y": 280,
        "wires": [
            [
                "b6c85aea.284958"
            ]
        ]
    },
    {
        "id": "55e3e329.c3feac",
        "type": "inject",
        "z": "b7eb854a.f45398",
        "name": "Hora",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "repeat": "10",
        "crontab": "",
        "once": true,
        "x": 150,
        "y": 40,
        "wires": [
            [
                "143bf9e7.cdee46"
            ]
        ]
    },
    {
        "id": "5a214c2b.be8a74",
        "type": "ui_text",
        "z": "b7eb854a.f45398",
        "group": "6f470621.f90a18",
        "order": 2,
        "width": "0",
        "height": "0",
        "name": "",
        "label": "Hora",
        "format": "{{msg.payload}}",
        "layout": "row-left",
        "x": 570,
        "y": 40,
        "wires": []
    },
    {
        "id": "20973c46.723cb4",
        "type": "ui_chart",
        "z": "2b414f0b.a48fc",
        "name": "",
        "group": "d8de668d.fa0568",
        "order": 2,
        "width": 0,
        "height": 0,
        "label": "Sonda 2 - 1h",
        "chartType": "line",
        "legend": "true",
        "xformat": "HH:mm:ss",
        "interpolate": "linear",
        "nodata": "",
        "dot": false,
        "ymin": "",
        "ymax": "",
        "removeOlder": 1,
        "removeOlderPoints": "",
        "removeOlderUnit": "3600",
        "cutout": 0,
        "useOneColor": false,
        "colors": [
            "#1f77b4",
            "#aec7e8",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "useOldStyle": false,
        "x": 398,
        "y": 93,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "fee6c30c.1ed07",
        "type": "ui_text",
        "z": "2b414f0b.a48fc",
        "group": "d8de668d.fa0568",
        "order": 3,
        "width": 0,
        "height": 0,
        "name": "",
        "label": "Temperatura Sonda 2",
        "format": "{{msg.payload}}",
        "layout": "row-spread",
        "x": 428,
        "y": 53,
        "wires": []
    },
    {
        "id": "271da9f3.b155c6",
        "type": "mqtt in",
        "z": "2b414f0b.a48fc",
        "name": "Temperatura DHT22",
        "topic": "Temp_1",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 158,
        "y": 53,
        "wires": [
            [
                "20973c46.723cb4",
                "fee6c30c.1ed07",
                "62583c71.138354"
            ]
        ]
    },
    {
        "id": "de93b3.4a4cdc5",
        "type": "mqtt in",
        "z": "2b414f0b.a48fc",
        "name": "Humedad DHT22",
        "topic": "Hum_1",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 158,
        "y": 113,
        "wires": [
            [
                "e80c3f9f.b6203",
                "20973c46.723cb4",
                "62583c71.138354"
            ]
        ]
    },
    {
        "id": "e80c3f9f.b6203",
        "type": "ui_text",
        "z": "2b414f0b.a48fc",
        "group": "d8de668d.fa0568",
        "order": 4,
        "width": 0,
        "height": 0,
        "name": "",
        "label": "Humedad Sonda 2",
        "format": "{{msg.payload}}",
        "layout": "row-spread",
        "x": 418,
        "y": 173,
        "wires": []
    },
    {
        "id": "abec0c3.bc40bf",
        "type": "ui_gauge",
        "z": "b7eb854a.f45398",
        "name": "UMBRAL",
        "group": "5e903ef1.5a837",
        "order": 3,
        "width": 0,
        "height": 0,
        "gtype": "gage",
        "title": "UMBRAL",
        "label": "ºC",
        "format": "{{value}}",
        "min": "10",
        "max": "40",
        "colors": [
            "#ff0000",
            "#008000",
            "#ff0000"
        ],
        "seg1": "20",
        "seg2": "26",
        "x": 341,
        "y": 182,
        "wires": []
    },
    {
        "id": "ae72ea77.2e8d68",
        "type": "mqtt in",
        "z": "b7eb854a.f45398",
        "name": "Umbral DHT22",
        "topic": "Umbral_1",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 161,
        "y": 182,
        "wires": [
            [
                "abec0c3.bc40bf"
            ]
        ]
    },
    {
        "id": "bdd46432.726528",
        "type": "mqtt out",
        "z": "b7eb854a.f45398",
        "name": "Umbral sonda DHT22",
        "topic": "Umbral_1",
        "qos": "",
        "retain": "",
        "broker": "ceaaef77.911d5",
        "x": 381,
        "y": 122,
        "wires": []
    },
    {
        "id": "e437b9ef.3e44e8",
        "type": "ui_slider",
        "z": "b7eb854a.f45398",
        "name": "",
        "label": "Temperatura",
        "group": "5e903ef1.5a837",
        "order": 4,
        "width": 0,
        "height": 0,
        "passthru": false,
        "topic": "",
        "min": "10",
        "max": "40",
        "step": 1,
        "x": 151,
        "y": 122,
        "wires": [
            [
                "bdd46432.726528"
            ]
        ]
    },
    {
        "id": "bf3f21cd.fa629",
        "type": "ui_template",
        "z": "b7eb854a.f45398",
        "group": "6f470621.f90a18",
        "name": "",
        "order": 1,
        "width": 0,
        "height": 0,
        "format": "<div ng-bind-html=\"msg.payload\"></div>\n<h3>Demo de Arduino con MQTT</h3>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "templateScope": "local",
        "x": 140,
        "y": 389,
        "wires": [
            []
        ]
    },
    {
        "id": "62583c71.138354",
        "type": "ui_chart",
        "z": "2b414f0b.a48fc",
        "name": "Grafica Sonda 2 24h",
        "group": "d8de668d.fa0568",
        "order": 1,
        "width": 0,
        "height": 0,
        "label": "Sonda 2 - 24h",
        "chartType": "line",
        "legend": "true",
        "xformat": "HH:mm:ss",
        "interpolate": "linear",
        "nodata": "",
        "dot": false,
        "ymin": "",
        "ymax": "",
        "removeOlder": "1",
        "removeOlderPoints": "",
        "removeOlderUnit": "86400",
        "cutout": 0,
        "useOneColor": false,
        "colors": [
            "#1f77b4",
            "#aec7e8",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "useOldStyle": false,
        "x": 428,
        "y": 133,
        "wires": [
            [],
            []
        ]
    },
    {
        "id": "9dcbd007.65e29",
        "type": "mqtt in",
        "z": "b7eb854a.f45398",
        "name": "",
        "topic": "Temp_1",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 130,
        "y": 269,
        "wires": [
            [
                "2df771ec.acdc3e"
            ]
        ]
    },
    {
        "id": "2df771ec.acdc3e",
        "type": "ui_gauge",
        "z": "b7eb854a.f45398",
        "name": "",
        "group": "5e903ef1.5a837",
        "order": 1,
        "width": "3",
        "height": "3",
        "gtype": "donut",
        "title": "Temperatura",
        "label": "ºC",
        "format": "{{value}}",
        "min": "10",
        "max": "50",
        "colors": [
            "#ff0000",
            "#008000",
            "#ff0000"
        ],
        "seg1": "20",
        "seg2": "26",
        "x": 350,
        "y": 269,
        "wires": []
    },
    {
        "id": "1fdf1760.a7fe29",
        "type": "mqtt in",
        "z": "b7eb854a.f45398",
        "name": "",
        "topic": "Hum_1",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 130,
        "y": 329,
        "wires": [
            [
                "d179f3c6.d19ed"
            ]
        ]
    },
    {
        "id": "d179f3c6.d19ed",
        "type": "ui_gauge",
        "z": "b7eb854a.f45398",
        "name": "",
        "group": "5e903ef1.5a837",
        "order": 2,
        "width": "3",
        "height": "3",
        "gtype": "donut",
        "title": "Humedad",
        "label": "%",
        "format": "{{value}}",
        "min": "10",
        "max": "100",
        "colors": [
            "#ff0000",
            "#008000",
            "#ff0000"
        ],
        "seg1": "20",
        "seg2": "80",
        "x": 340,
        "y": 329,
        "wires": []
    },
    {
        "id": "15f9632c.bf513d",
        "type": "mqtt in",
        "z": "dfe6370a.f00358",
        "name": "Temperatura DHT22",
        "topic": "Temp_1",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 171,
        "y": 79,
        "wires": [
            [
                "cceda73e.0b95e8",
                "a6bde7.dfba1218"
            ]
        ]
    },
    {
        "id": "74cf6080.9caf7",
        "type": "mqtt in",
        "z": "dfe6370a.f00358",
        "name": "Humedad DHT22",
        "topic": "Hum_1",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 171,
        "y": 139,
        "wires": [
            [
                "97826e8a.7c92c"
            ]
        ]
    },
    {
        "id": "cceda73e.0b95e8",
        "type": "function",
        "z": "dfe6370a.f00358",
        "name": "Make query",
        "func": "var newMsg = { payload: msg.payload };\nnewMsg.topic=\"insert into Temperatura (Sonda,Temperatura) values ('DHT22',\"+newMsg.payload+\")\";\nreturn newMsg;",
        "outputs": 1,
        "noerr": 0,
        "x": 411,
        "y": 79,
        "wires": [
            [
                "1e65aa70.440f06"
            ]
        ]
    },
    {
        "id": "1e65aa70.440f06",
        "type": "mysql",
        "z": "dfe6370a.f00358",
        "mydb": "5a6e8e22.04dee",
        "name": "",
        "x": 671,
        "y": 39,
        "wires": [
            []
        ]
    },
    {
        "id": "97826e8a.7c92c",
        "type": "function",
        "z": "dfe6370a.f00358",
        "name": "Make query",
        "func": "var newMsg = { payload: msg.payload };\nnewMsg.topic=\"insert into Humedad (Sonda,Humedad) values ('DHT22',\"+newMsg.payload+\")\";\nreturn newMsg;",
        "outputs": 1,
        "noerr": 0,
        "x": 411,
        "y": 139,
        "wires": [
            [
                "1e65aa70.440f06"
            ]
        ]
    },
    {
        "id": "143bf9e7.cdee46",
        "type": "moment",
        "z": "b7eb854a.f45398",
        "name": "",
        "topic": "",
        "input": "",
        "inputType": "msg",
        "inTz": "Etc/UTC",
        "adjAmount": "0",
        "adjType": "hours",
        "adjDir": "add",
        "format": "DD-MM-YYYY HH:mm:ss",
        "locale": "POSIX",
        "output": "",
        "outputType": "msg",
        "outTz": "Europe/Madrid",
        "x": 380,
        "y": 40,
        "wires": [
            [
                "5a214c2b.be8a74",
                "b818bbba.1eeae8"
            ]
        ]
    },
    {
        "id": "b818bbba.1eeae8",
        "type": "mqtt out",
        "z": "b7eb854a.f45398",
        "name": "",
        "topic": "Hora",
        "qos": "",
        "retain": "",
        "broker": "ceaaef77.911d5",
        "x": 570,
        "y": 80,
        "wires": []
    },
    {
        "id": "a6bde7.dfba1218",
        "type": "function",
        "z": "dfe6370a.f00358",
        "name": "Comprueba Umbral Sonda DHT22",
        "func": "if (msg.payload > 26) {\n    msg.payload = true;\n}\nelse {\n    msg.payload = false;\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 431,
        "y": 261,
        "wires": [
            [
                "32ad5c4c.419fd4"
            ]
        ]
    },
    {
        "id": "32ad5c4c.419fd4",
        "type": "mqtt out",
        "z": "dfe6370a.f00358",
        "name": "Alarma Sonda DHT22",
        "topic": "Alarma_1",
        "qos": "",
        "retain": "",
        "broker": "ceaaef77.911d5",
        "x": 741,
        "y": 259,
        "wires": []
    },
    {
        "id": "b0c2a902.6c0918",
        "type": "mqtt in",
        "z": "b7eb854a.f45398",
        "name": "",
        "topic": "Alarma_1",
        "qos": "2",
        "broker": "ceaaef77.911d5",
        "x": 145,
        "y": 444,
        "wires": [
            [
                "cad55396.2fc84"
            ]
        ]
    },
    {
        "id": "16b31ebe.e74741",
        "type": "ui_text",
        "z": "b7eb854a.f45398",
        "group": "f2df5ea4.c9069",
        "order": 0,
        "width": 0,
        "height": 0,
        "name": "",
        "label": "LED 1",
        "format": "<font color={{msg.color}} ><i class=\"fa fa-circle\" style=\"font-size:24px;\"></i></font>",
        "layout": "row-left",
        "x": 515,
        "y": 444,
        "wires": []
    },
    {
        "id": "cad55396.2fc84",
        "type": "function",
        "z": "b7eb854a.f45398",
        "name": "Color LED 1",
        "func": "if (msg.payload == 'true'){\n    msg.color = 'red';\n}\nelse{\n    msg.color = 'green';\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 355,
        "y": 444,
        "wires": [
            [
                "16b31ebe.e74741"
            ]
        ]
    },
    {
        "id": "fa93024d.bfe57",
        "type": "ui_button",
        "z": "b7eb854a.f45398",
        "name": "",
        "group": "f2df5ea4.c9069",
        "order": 0,
        "width": "2",
        "height": "1",
        "passthru": false,
        "label": "{{msg.payload}}",
        "color": "",
        "bgcolor": "{{msg.background}}",
        "icon": "",
        "payload": "",
        "payloadType": "str",
        "topic": "",
        "x": 135,
        "y": 504,
        "wires": [
            [
                "3447aa08.cf7fe6"
            ]
        ]
    },
    {
        "id": "3447aa08.cf7fe6",
        "type": "function",
        "z": "b7eb854a.f45398",
        "name": "ON-OFF",
        "func": "var myCount = flow.get(\"estado\")||\"OFF\";\n\nif (myCount == 'ON'){\n    flow.set(\"estado\",\"OFF\");\n    msg.payload = 'OFF';\n    msg.background = 'red';\n}\nelse{\n    flow.set(\"estado\",\"ON\");\n    msg.payload = 'ON';\n    msg.background = 'green';\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 345,
        "y": 504,
        "wires": [
            [
                "5e786d21.facb94",
                "fa93024d.bfe57"
            ]
        ]
    },
    {
        "id": "5e786d21.facb94",
        "type": "mqtt out",
        "z": "b7eb854a.f45398",
        "name": "",
        "topic": "Aviso",
        "qos": "",
        "retain": "",
        "broker": "ceaaef77.911d5",
        "x": 515,
        "y": 504,
        "wires": []
    }
]

Bien, ahora debemos modificar la IP, tanto del BROKER MQTT como de la conexión a la BBDD.
también es necesario asignar el usuario y la contraseña en las dos conexiones.

Para el proyecto, en la parte de Arduino, vamos a utilizar:
  • Arduino Mega (también es posible utilizar Uno)
  • Una Ethernet Shield
  • 3 LED's en mi caso he elegido de diferentes colores para distinguir mas fácilmente las señales que se reciben
  • 3 Resistencias 330 Ohmios
  • Un sensor DHT-22
  • Cables de conexion
  • Una Protoboard
  • Cable USB alimentación / Datos
  • Cable Ethernet
Este es el esquema de conexiones en Arduino



aquí os dejo el código para el Sketch en el IDE de Arduino:

/*
  demo-mqtt para implementar un sistema de aviso de temperaturas
  El montaje consiste en:
  -  Arduino Mega
  -  Ethernet Shield
  -  Una sonda DHT22 conectada al pin 7
  -  Un led bicolor (Rojo/Verde) conectado a los pines 22 y 23
  Topics suscritos:
  - umbral_1
    Topics publicados:
  - Temp_1
  - Hum_1
  - reconnect
*/

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Timer.h>  //librería https://github.com/JChristensen/Timer 
#include <dht.h>  //librería https://github.com/jecrespo/DHTlib

#define PIN_Sensor_Sonda_1 7
#define PIN_LED_1 2
#define PIN_LED_2 3
#define PIN_AVISO 5

Timer t;

dht sonda_1;

unsigned long int anterior = 0;

// Update these with values suitable for your network.
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(XXX, XXX, XXX, XXX); // Direccion de red para Arduino
IPAddress server(XXX, XXX, XXX, XXX); // Direccion de red de Raspberry Pi

// Respuesta de los topic a los que me he subscrito en la función reconnect
void callback(char* topic, char* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
  payload[length] = '\0'; //Para que pueda convertir correctamente a String

  //analizar el topic y el payload para ejecutar lo necesario con String
  String topic_S = topic;
  String payload_S = payload;

  if (topic_S == "Alarma_1") {
    if (payload_S == "false") {
      digitalWrite(PIN_LED_2, HIGH);
      digitalWrite(PIN_LED_1, LOW);
    }
    else
      digitalWrite(PIN_LED_2, LOW);
      digitalWrite(PIN_LED_1, HIGH);
  }
  if (topic_S == "Aviso") {
    if (payload_S == "ON") {
      digitalWrite(PIN_AVISO, HIGH);
    }
    else
      digitalWrite(PIN_AVISO, LOW);
  }
}

EthernetClient ethClient;
PubSubClient client(ethClient);

// Función reconexión que se ejecuta en el loop si pierdo conexión
// En reconnect también me subscribo a los topics y publico que me he reiniciado
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("arduinoClientED", "USUARIO_MQTT", "CONTRASEÑA_MQTT")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("reconnect", "Arduino Connect!!!");
      // ... and resubscribe
      
      client.subscribe("Umbral_1");
      client.subscribe("Alarma_1");
      client.subscribe("Aviso");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

// Función que publica cada 10 segundos la temperatura en los topics
void sendTemperatures () {
  Serial.println("Send Temperatures...");
    int resultado_1 = sonda_1.read22(PIN_Sensor_Sonda_1);
  
  if (resultado_1 == DHTLIB_OK) {
    char buffer_t[6];
    char buffer_h[6];
    float temperatura_1 = sonda_1.temperature;
    float humedad_1 = sonda_1.humidity;
    float1char(temperatura_1, buffer_t);
    float1char(humedad_1, buffer_h);
    Serial.println("-- Sonda 1 --");
    Serial.print(temperatura_1);
    Serial.print(" -> ");
    Serial.println(buffer_t);
    Serial.print(humedad_1);
    Serial.print(" -> ");
    Serial.println(buffer_h);
    client.publish("Temp_1", buffer_t);
    client.publish("Hum_1", buffer_h);
  }
  else {
    //publicar en contador, ver si podría se algo como añadir 1 al topic
    switch (resultado_1)
    {
      case DHTLIB_ERROR_CHECKSUM:
        Serial.println("Checksum error,\t");
        break;
      case DHTLIB_ERROR_TIMEOUT:
        Serial.println("Time out error,\t");
        break;
      default:
        Serial.println("Unknown error,\t");
        break;
    }
    
  }
}

void setup()
{
  Serial.begin(9600);
  pinMode(PIN_LED_1,OUTPUT);
  pinMode(PIN_LED_2,OUTPUT);
  pinMode(PIN_AVISO,OUTPUT);

  t.every((1 * 60 * 60 * 1000UL), sendTemperatures); // Enviamos valores cada hora

  client.setServer(server, 1883);
  client.setCallback(callback);

  Ethernet.begin(mac);
  // Allow the hardware to sort itself out
  delay(1500);
}

void loop()
{
  t.update();

  if (!client.connected()) {
    reconnect();
  }

  client.loop();
}

int float1char(float number, char* buffer_c) { //Solo para número de 99.99 hasta 0. buffer[6]={'2','6','.','3','5',\0}
  if ((number > 99.99) || (number < 0))
    return 0;

  int entero = floor(number);
  int decimal = round((number - entero) * 100);

  int decenas = int(floor(entero / 10));
  int unidades = int(floor(entero - (decenas * 10)));
  int decimal_1 = int(floor(decimal / 10));
  int decimal_2 = int(floor(decimal - (decimal_1 * 10)));

  //sumo 48 para obtener el código ascii del número
  buffer_c[0] = char(decenas + 48);
  buffer_c[1] = char(unidades + 48);
  buffer_c[2] = '.';
  buffer_c[3] = char(decimal_1 + 48);
  buffer_c[4] = char(decimal_2 + 48);
  buffer_c[5] = '\0';
  return 1;
}

Y recordar, que es conveniente realizar copia de la tarjeta SD, como hemos descrito en la primera entrada, así, podremos recuperar los puntos de instalación en cualquier momento.

Continuamos en la siguiente entrada de la serie, la Entrada 5.