Este proyecto implementa un sistema IoT utilizando el protocolo MQTT para comunicación entre dispositivos. Utiliza una Raspberry Pi 5 como broker MQTT, una ESP32 con sensores y actuadores como cliente, y Node-RED para visualización y control en tiempo real.
- Objetivo Principal: Aprender a crear un broker y containers con comunicación MQTT para la interconección de diferentes dispositivos.
- Objetivos Secundarios:
- Crear un broker.
- Crear Docker containers que contengan sistemas y a su vez que se conecten al broker.
- Aplicarlo de forma física en una maqueta.
- Realizar pruebas de estabilidad.
- Documentar el procedimiento para futuros proyectos que utilicen este tipo de protocolo.
Toda la gestión de tareas, sprints y seguimiento de issues se maneja a través de nuestro tablero de GitHub Projects.
- 🎯 Descripción y objetivos
- 📊 Gestión del Proyecto
- 👥 Equipo y Responsables
- 🛠️ Stack Tecnológico y Componentes
- 📁 Estructura del Repositorio
⚠️ Aviso de buenas prácticas- Arquitectura del proyecto
- 🚀 Instalación y Puesta en Marcha
- 1. Configuración Raspberry pi 5
- 2. Configuración del Broker MQTT en Raspberry Pi
- 3. Configuración de Mosquitto
- 4. Probar el Broker
- 5. Configuración de Node-RED en Raspberry Pi
- 5.1. Instalación de Node-RED
- 5.2. Configuraciones de seguridad de Node-RED
- 5.2. Configuraciones de control de versiones GIT de Node-RED
- 5.3. Configuraciones de nombre del archivo de flows
- 5.4. Seleccionar tema y texto del editor
- 5.5. Habilitar nodos Function
- 5.6. Configurar inicio automático
- 5.7. Iniciar Node-RED
- 5.8. Instalar Nodes necesarios
- 5.8. Acceder al directorio de Node-RED
- 5.9. Instalar node-red-dashboard
- 5.10. Instalar node-red-contrib-mqtt-broker
- 6. Acceder a Node-RED
- 💡 Uso y Operación
- 📚 Documentación Adicional
- ⚖️ Licencia
| Nombre | Rol en el Proyecto | GitHub |
|---|---|---|
| Addi Trejo | Desarrollador | @Additrejo |
- OS: Raspberry Pi OS (64-bit Bullseye o posterior)
- Broker: Mosquitto MQTT
- Dockers: Docker y Docker Compose
- Programación: Node Red, RealVNC Viewer, Geany.
- Interfaz Visual: RealVNC Viewer,
- Navegador/Dashboard: Navegador de internet.
- Simulación: Cisco Packet Tracer.
- Microcontrolador: Raspberry pi 5, ESP32.
- Sensores: SR04(Distancia), DTH11 (Temperatura),
Una descripción de alto nivel de las carpetas más importantes para que cualquiera pueda encontrar lo que busca.
Estas son las instrucciones paso a paso sobre como usar un protocolo MQTT en una Raspberri Pi 5 y diferentes componentes, está pensando para que cualquier miembro del laboratorio pueda configurar el entorno para trabajar en este proyecto.
Para este ejemplo usaremos una Raspberri pi 5. Si es la primera vez usando la placa revisar la documentación de configuraciónes básicas en Raspberry PI 5 ya que son necesarias para el despliegue de este proyecto, así como revisar la documentación al final del repositorio ante cualquier duda.
Clona este repositorio: git clone https://github.com/LINX-ICN-UNAM/MQTT_Test
Todo esto con el fin de mantener el repositorio original funcional.
┌─────────────────┐ MQTT ┌─────────────────┐ HTTP/WebSocket ┌─────────────────┐
│ ESP32 DevKit │◀────────────────▶│ Raspberry Pi 5 │◀──────────────────▶│ Node-RED │
│ (Cliente) │ │ (Broker MQTT) │ │ (Dashboard) │
│ │ │ │ │ │
│ • Sensores │ │ • Mosquitto │ │ • Visualización │
│ • Actuadores │ │ • Docker │ │ • Control │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Es necesario conectarse al escritorio de la raspberry Pi 5 de manera remota a traves de RealVNC Viewer en tu PC.
Conexión RealVNC Viewever a PC.
Mosquitto es un broker MQTT de código abierto y muy popular, desarrollado por la fundación Eclipse. Su nombre completo es Eclipse Mosquitto.
Broker MQTT ligero y eficiente: Implementa los protocolos MQTT (versiones 3.1, 3.1.1 y 5.0) de forma optimizada para bajo consumo de recursos. Ideal para sistemas embebidos, servidores de baja potencia o entornos con alta concurrencia de clientes.
Multiplataforma: Funciona en Linux, Windows, macOS y sistemas embebidos como Raspberry Pi.
Funcionalidades estándar y extendidas: Soporta QoS 0, 1 y 2. Incluye autenticación (usuarios/contraseñas, TLS/SSL) y ACLs para control de acceso. Bridge o puente entre brokers para interconectar redes MQTT. Persistencia de mensajes (opcional). WebSockets para conexiones desde navegadores web.
Herramientas incluidas: Viene con clientes CLI (mosquitto_pub y mosquitto_sub) para pruebas y depuración.
sudo apt update
sudo apt upgrade -ysudo apt install -y mosquitto mosquitto-clientssudo systemctl enable mosquittosudo systemctl start mosquittosudo nano /etc/mosquitto/mosquitto.conf- Permitir conexiones anónimas (para desarrollo)
allow_anonymous true- Escuchar en todas las interfaces
listener 1883 0.0.0.0- Persistencia de mensajes
persistence true
persistence_location /var/lib/mosquitto/- Log
log_dest file /var/log/mosquitto/mosquitto.logDeben quedar de la siguiente forma:
Nota: Ctrl + O (Guardar) Enter (Confirmar nombre del archivo) Ctrl + X (Salir)
sudo systemctl restart mosquittomosquitto_sub -h localhost -t "test"mosquitto_pub -h localhost -t "test" -m "Hello MQTT"Obtendremos el mensaje enviado por sub en el pub.
Instalar Node-RED
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)Aceptamos los cambios.
Se tienen que instalar todas las dependencias sin errores:
Como podemos ver, nos ha asignado el localhost:1880
También nos da una advertencia de seguridad la cual nos recomienta configurar.
Ejecuta el siguiente comando.
node-red admin initPor el momento no lo configuraremos.
lo dejamos predefnido flows.json Nos pedirá agregar una passphrase para encriptar las credenciales. Por el momento lo dejaremos así, aun que si constituye en riesgo de seguridad.
Seleccionamos los dos por default que nos recomienda.
Permite módulos externos para flexibilidad. permiten escribir código JavaScript personalizado. Esta opción controla si ese código puede usar.
- Más poder y flexibilidad.
- Puedes acceder a archivos del sistema.
- Puedes hacer peticiones HTTP complejas.
- Puedes conectar a bases de datos.
- Necesario para muchas integraciones avanzada.
- Código malicioso podría acceder al sistema
- Podría eliminar archivos si hay bugs
- Mayor superficie de ataque
- Usuario podría ejecutar código peligroso
No (NO PERMITIR) - SEGURIDAD:
- Sandbox completo, más seguro
- Ataques limitados incluso si hay vulnerabilidad
- Ideal para entornos multi-usuario
- No podrás usar módulos npm en Functions
- Menos flexibilidad para integraciones
- Muchos flows avanzados no funcionarán
Pregunta clave:
- ¿Vas a conectar Node-RED con: Bases de datos? → Necesitas Yes
- APIs externas? → Necesitas Yes
- Archivos locales? → Necesitas Yes
- Solo flows simples sin código? → No está bien
sudo systemctl enable nodered.servicesudo systemctl start nodered.servicehttp://localhost:1880Nos mostrará la ventana de iniciar sesión.
Abrir cualquier navegador y agregar la siguiente ruta.
http://[IP_RASPBERRY_PI]:1880Agregar las credenciales establecidas.
Una vez en Node Red se hace una prueba con cualquier sensor, en este caso usaremos el acelerometro MPU6050.
- Ejecutar en la terminal de la raspberry pi el siguiente comando:
sudo apt update
sudo apt install python3-paho-mqtt
donde: paho-mqtt: Para la comunicación MQTT.
Comprobar si se instaló correctamente con el siguiente comando:
pip3 list | grep pahosudo raspi-configNavega a Interface Options -> I2C -> Yes para habilitarlo. Luego, reinicia.
En este caso estaremos usando un sensor MPU6050.
Pinout
VCC (sensor) a un pin 3.3V de la Pi.
GND (sensor) a un pin GND de la Pi.
SCL (sensor) al pin GPIO 3 (SCL) de la Pi.
SDA (sensor) al pin GPIO 2 (SDA) de la Pi.
Crea un nuevo archivo, por ejemplo, acelerometro_mqtt.py, y pega el siguiente código. Este ejemplo está escrito para un sensor MPU6050 genérico, pero deberás adaptar la parte de la lectura si tu sensor es de otro modelo.
import paho.mqtt.client as mqtt
import smbus2
import time
import json
import math
# --- Configuración del Sensor (MPU6050) ---
MPU6050_ADDR = 0x68 # Dirección I2C del MPU6050
POWER_MGMT_1 = 0x6B
ACCEL_XOUT_H = 0x3B
bus = smbus2.SMBus(1) # Usa el bus I2C-1 de la Raspberry Pi
# Despertar el MPU6050 (escribe 0 en el registro de gestión de energía)
bus.write_byte_data(MPU6050_ADDR, POWER_MGMT_1, 0)
# --- Configuración MQTT ---
MQTT_BROKER = "localhost" # Dirección de tu broker MQTT (Mosquitto en la misma Pi)
MQTT_PORT = 1883
MQTT_TOPIC = "sensor/acelerometro" # Topic donde se publicarán los datos
INTERVALO_SEGUNDOS = 1 # Frecuencia de lectura y envío
# Función para leer datos "crudos" del sensor
def read_raw_data(addr):
# Leer dos bytes (high y low) y combinarlos
high = bus.read_byte_data(MPU6050_ADDR, addr)
low = bus.read_byte_data(MPU6050_ADDR, addr+1)
value = (high << 8) | low
# Convertir a valor con signo (complemento a dos)
if value > 32768:
value = value - 65536
return value
# Configuración del cliente MQTT
client = mqtt.Client()
try:
client.connect(MQTT_BROKER, MQTT_PORT, 60)
print(f"Conectado al broker MQTT {MQTT_BROKER}:{MQTT_PORT}")
except Exception as e:
print(f"Error al conectar al broker: {e}")
exit(1)
print(f"Publicando en topic '{MQTT_TOPIC}' cada {INTERVALO_SEGUNDOS} segundo(s)...")
try:
while True:
# Leer acelerómetro (ejes X, Y, Z)
accel_x = read_raw_data(ACCEL_XOUT_H)
accel_y = read_raw_data(ACCEL_XOUT_H + 2)
accel_z = read_raw_data(ACCEL_XOUT_H + 4)
# Opcional: Convertir a gravedades (g)
# Dividir por la escala (por defecto 16384 para +-2g)
# ax = accel_x / 16384.0
# ay = accel_y / 16384.0
# az = accel_z / 16384.0
# Crear un payload en formato JSON
payload = json.dumps({
"x": accel_x,
"y": accel_y,
"z": accel_z
# "x_g": round(ax, 3),
# "y_g": round(ay, 3),
# "z_g": round(az, 3)
})
# Publicar el mensaje
result = client.publish(MQTT_TOPIC, payload)
status = result.rc
if status == mqtt.MQTT_ERR_SUCCESS:
print(f"Enviado: {payload}")
else:
print(f"Error al enviar el mensaje, código: {status}")
time.sleep(INTERVALO_SEGUNDOS)
except KeyboardInterrupt:
print("Detenido por el usuario.")
finally:
bus.close()
client.disconnect()
print("Conexión cerrada.")Nota importante: Este script es un punto de partida. Dependiendo de tu sensor específico, la dirección I2C, los registros a leer y la fórmula de conversión pueden variar.
Al ejecutar el script podemos ver en el script los valores obtenidos del sensor:
Ahora configuraremos Node-RED para que se suscriba al topic MQTT y muestre los valores en un gauge.
Se tiene que ver el siguiente panel:
- En Node-RED, ve al menú (esquina superior derecha) → "Manage palette"
- Ve a la pestaña "Install"
- Busca @flowfuse/node-red-dashboard
- Haz clic en "Install"
- Arrastra un nodo mqtt in desde la categoría "network" al área de trabajo.
- Haz doble click sobre el nodo y verás las propiedades.
- Propiedades:
- Server: Asegúrate de que apunte a tu broker MQTT. Si es el mismo equipo, debe decir localhost:1883.
- Si no ves el servidor, haz doble clic en el nodo y añade uno nuevo con localhost y 1883.
Las propiedades del nodo deben quedar de la siguiente forma:
- Action: Subscribe to single topic.
- Topic: sensor/acelerometro (el mismo que usaste en el script Python).
- Output: "a parsed JSON object" (para que interprete automáticamente el JSON que enviamos).
- Haz clic en "Done".
Para separar los ejes. Arrastra un nodo function desde la categoría "function". Este nodo tomará el objeto JSON completo y lo dividirá en tres mensajes separados, uno para cada eje.
- Arrastra el nodo de función al panel.
- Doble click sobre el para editarlo.
- En la pestaña configuración agregar 3 salidas (cada una es para un eje x,y,z).
- En la pestaña en mensaje ("On Message") agregar el siguiente código:
// Asumiendo que msg.payload tiene {x: valor, y: valor, z: valor}
var ejeX = { payload: msg.payload.x, topic: "ejeX" };
var ejeY = { payload: msg.payload.y, topic: "ejeY" };
var ejeZ = { payload: msg.payload.z, topic: "ejeZ" };
// Envía los tres mensajes en orden
return [ejeX, ejeY, ejeZ];*Da click en Done ("Hecho")
Arrastra tres nodos gauge desde la categoría "dashboard" al área de trabajo.
Paso 1: Configurar el primer gauge (Eje X)
-
Programar el ESP32 (El Recolector de Datos). prepararemos la ESP32 DevKit para que lea el MPU6050 y envíe los datos a la Raspberry Pi.
El MPU6050 se comunica mediante el protocolo I2C. Las conexiones son:
Pin MPU6050 Pin ESP32 DevKit V1 VCC 3.3V GND GND SCL GPIO 22 SDA GPIO 21 -
Librerias en Arduino IDE.
- Adafruit MPU6050 de Adafruit (esta incluirá automáticamente Adafruit Unified Sensor y Adafruit BusIO como dependencias).
- PubSubClient de Nick O'Leary. Esta es la librería que usaremos para la comunicación MQTT.
- Código para el ESP32
Abre un nuevo sketch y pega el siguiente código.
Recuerda cambiar las variables de WIFI_SSID, WIFI_PASSWORD y la IP de tu Raspberry Pi por las tuyas.
Este código hace lo siguiente:
- Conecta el ESP32 a tu red Wi-Fi.
- Inicializa el sensor MPU6050.
- Se conecta al broker MQTT en tu Raspberry Pi.
- En un bucle continuo, lee la aceleración y la temperatura (el MPU6050 también tiene sensor de temperatura) del sensor
- Publica estos datos en dos temas MQTT distintos cada 2 segundos.
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
// === CONFIGURACIÓN WI-FI ===
const char* ssid = "TU_SSID";
const char* password = "TU_CONTRASENA";
// === CONFIGURACIÓN MQTT (RASPBERRY PI) ===
const char* mqtt_server = "192.168.1.X"; // <<<--- ¡LA IP DE TU RASPBERRY PI!
const int mqtt_port = 1883;
const char* mqtt_topic_accel = "casa/esp32/mpu6050/accel";
const char* mqtt_topic_temp = "casa/esp32/mpu6050/temp";
// Objetos
WiFiClient espClient;
PubSubClient client(espClient);
Adafruit_MPU6050 mpu;
// Variables para tiempo
unsigned long lastMsg = 0;
const long interval = 2000; // Publicar cada 2 segundos
// === FUNCIÓN PARA CONECTAR A WI-FI ===
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Conectando a ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi conectado");
Serial.print("Dirección IP ESP32: ");
Serial.println(WiFi.localIP());
}
// === FUNCIÓN PARA RECONECTAR AL BROKER MQTT ===
void reconnect() {
while (!client.connected()) {
Serial.print("Intentando conexión MQTT...");
String clientId = "ESP32_MPU6050_";
clientId += String(random(0xffff), HEX);
if (client.connect(clientId.c_str())) {
Serial.println("conectada");
} else {
Serial.print("falló, rc=");
Serial.print(client.state());
Serial.println(" intentando de nuevo en 5 segundos");
delay(5000);
}
}
}
// === SETUP ===
void setup() {
Serial.begin(115200);
// Inicializar MPU6050
if (!mpu.begin()) {
Serial.println("No se encontró el sensor MPU6050. Revisa el cableado.");
while (1) {
delay(10);
}
}
Serial.println("MPU6050 encontrado!");
// Configurar rangos del sensor (opcional, valores por defecto)
mpu.setAccelerometerRange(MPU6050_RANGE_2_G);
mpu.setGyroRange(MPU6050_RANGE_250_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
// Conectar a WiFi
setup_wifi();
// Configurar servidor MQTT
client.setServer(mqtt_server, mqtt_port);
}
// === LOOP PRINCIPAL ===
void loop() {
// Reconectar a MQTT si es necesario
if (!client.connected()) {
reconnect();
}
client.loop(); // Mantener la comunicación MQTT activa
unsigned long now = millis();
if (now - lastMsg > interval) {
lastMsg = now;
// Obtener nuevos eventos del sensor
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
// --- Publicar datos de aceleración (como JSON) ---
String accelPayload = "{\"x\":";
accelPayload += a.acceleration.x;
accelPayload += ",\"y\":";
accelPayload += a.acceleration.y;
accelPayload += ",\"z\":";
accelPayload += a.acceleration.z;
accelPayload += "}";
client.publish(mqtt_topic_accel, accelPayload.c_str());
Serial.print("Aceleración publicada: ");
Serial.println(accelPayload);
// --- Publicar datos de temperatura (como string simple) ---
String tempPayload = String(temp.temperature);
client.publish(mqtt_topic_temp, tempPayload.c_str());
Serial.print("Temperatura publicada: ");
Serial.println(tempPayload);
}
}-
Visualizar en Node-RED (Dashboard)
Con la Raspberry Pi lista y el ESP32 enviando datos, el último paso es crear el "cuadro de mandos" en Node-RED.Crear el Flujo
En tu navegador, ve a http://:1880. Vamos a construir el flujo arrastrando nodos desde la izquierda y conectándolos.Necesitaremos:
- 2 nodos mqtt in (de la sección "network").
- 2 nodos json (de la sección "parser").
- 2 nodos chart (de la sección "dashboard").
- 1 nodo gauge (de la sección "dashboard").
Varios nodos function (opcional, para procesar datos).
- Arrastra un nodo mqtt in al canvas.
- Haz doble clic en él. En "Server", añade una nueva conexión a tu Raspberry Pi (localhost:1883).
- En "Topic", escribe: casa/esp32/mpu6050/accel.
- En "Output", selecciona "a parsed JSON object". Así Node-RED convertirá automáticamente el JSON {"x":..., "y":..., "z":...} que envía el ESP32 en un objeto que podemos usar.
- Ponle nombre "Aceleración RAW".
Separar Ejes X, Y, Z (Opcional pero recomendado):
- La salida del nodo MQTT ya es un objeto con msg.payload.x, msg.payload.y, msg.payload.z. Para graficarlos por separado, podemos usar nodos function.
- Arrastra tres nodos function. Conéctalos en paralelo a la salida del nodo MQTT.
- En el primer function, escribe el siguiente código para quedarnos solo con el eje X y asignarlo a msg.payload:
// Código para el Eje X msg.payload = msg.payload.x; msg.topic = "Eje X"; return msg;
Haz lo mismo para los otros dos nodos, cambiando msg.payload.x por msg.payload.y y msg.payload.z, y el msg.topic en consecuencia.
Nodos Chart (Gráficos):
-
Arrastra tres nodos chart (de la sección dashboard). Conecta cada uno a la salida de cada nodo function que creamos.
-
Haz doble clic en el primero (Eje X). En la pestaña "Appearance", asígnale un Grupo. Si es la primera vez, tendrás que crear uno nuevo: ve a la pestaña "Dashboard" (en la barra lateral derecha) y crea una nueva pestaña (Tab) y un nuevo grupo (Group). Luego vuelve al nodo y selecciona ese grupo.
-
En la pestaña "Appearance", ponle etiqueta como "Aceleración Eje X". Puedes ajustar el rango del eje Y (por ejemplo, de -15 a 15) y el número de puntos a mostrar.
-
Desplegar (Deploy):
Haz clic en el botón rojo "Deploy" en la esquina superior derecha.
-
Ver los Datos en Vivo Ahora, abre una nueva pestaña en tu navegador y ve a http://:1880/. ¡Deberías ver tu dashboard con los gráficos de aceleración actualizándose en tiempo real
Enlaces a documentación más detallada, que no encaja en el README.
Este proyecto está bajo la licencia Space Instrumentation Laboratory, LINX. Institute of Nuclear Sciences ICN, UNAM. All rights reserved..