Introducción Teórica
Fundamentos de MQTT y Seguridad TLS/SSL en Comunicaciones IoT
¿Qué es MQTT?
MQTT (Message Queuing Telemetry Transport) es un protocolo de mensajería ligero diseñado específicamente para dispositivos con recursos limitados y conexiones de red de baja velocidad. En el contexto de la mecatrónica y el Internet de las Cosas (IoT), MQTT se ha convertido en el estándar de facto para la comunicación entre dispositivos y servidores.
Características Clave de MQTT:
- Protocolo publish-subscribe: Desacopla emisores y receptores
- Ligero: Mínimo overhead de red (2 bytes para headers)
- Calidad de Servicio (QoS): 3 niveles de garantía de entrega
- Persistencia: Mensajes retenidos y sesiones limpias
- Last Will Testament: Notificación automática de desconexión
Arquitectura MQTT
Mosquitto, HiveMQ
ESP32 Sensors
Dashboard
Seguridad: TLS/SSL en MQTT
TLS/SSL Fundamentals
TLS (Transport Layer Security) y su predecesora SSL (Secure Sockets Layer) son protocolos criptográficos que proporcionan comunicaciones seguras sobre redes no confiables. En MQTT, TLS/SSL garantiza:
- Confidencialidad: Cifrado de datos en tránsito
- Integridad: Verificación de que los datos no han sido alterados
- Autenticación: Verificación de identidad del servidor y cliente
Amenazas sin TLS/SSL
Caso de Uso Industrial
Sistema de Automatización de Fábrica
En una fábrica automatizada moderna, cientos de sensores y actuadores se comunican constantemente mediante MQTT:
- Sensores de temperatura: Monitoreo de hornos industriales
- Sensores de presión: Sistemas hidráulicos y neumáticos
- Actuadores de válvulas: Control de flujo de materiales
- Motores de producción: Control de velocidad y posición
Riesgos sin TLS/SSL:
- 🔥 Sobrecalentamiento no detectado
- 💥 Sobrepresurización de sistemas
- ⚠️ Parada no autorizada de producción
- 💸 Pérdidas económicas millonarias
Explicación Técnica Detallada
Implementación de MQTT con TLS/SSL en ESP32 usando Arduino IDE
ESP32 y Comunicación Segura
El ESP32 es un microcontrolador de bajo costo con capacidades integradas de Wi-Fi y Bluetooth, convirtiéndolo en la opción ideal para aplicaciones IoT industriales. Su arquitectura dual-core permite manejar simultáneamente la comunicación segura TLS/SSL y el procesamiento de datos de sensores.
Requisitos para MQTT con TLS/SSL:
📚 Librerías Necesarias:
WiFi.h
- Conectividad Wi-FiWiFiClientSecure.h
- TLS/SSLPubSubClient.h
- Cliente MQTTArduinoJson.h
- Manejo JSON
🔐 Certificados Requeridos:
- CA Certificate: Autoridad certificadora
- Client Certificate: Identidad del ESP32
- Private Key: Clave privada del cliente
Especificaciones ESP32
Implementación Completa
Cliente MQTT Seguro para ESP32
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
// ==================== CONFIGURACIÓN DE RED ====================
const char* ssid = "TU_WIFI_SSID";
const char* password = "TU_WIFI_PASSWORD";
// ==================== CONFIGURACIÓN MQTT SEGURO ====================
const char* mqtt_server = "mqtt.industrialiot.com";
const int mqtt_port = 8883; // Puerto seguro MQTT sobre TLS
const char* mqtt_username = "esp32_client";
const char* mqtt_password = "secure_password_2024";
const char* client_id = "ESP32_Factory_001";
// ==================== CERTIFICADOS TLS ====================
const char* ca_cert = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n" \
"ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" \
"... [certificado completo aquí] ...\n" \
"-----END CERTIFICATE-----\n";
// ==================== OBJETOS PRINCIPALES ====================
WiFiClientSecure espClient;
PubSubClient client(espClient);
// ==================== VARIABLES DE SENSORES ====================
float temperature = 0.0;
float humidity = 0.0;
unsigned long lastSensorRead = 0;
const unsigned long sensorInterval = 30000; // 30 segundos
// ==================== CONFIGURACIÓN INICIAL ====================
void setup() {
Serial.begin(115200);
Serial.println("🚀 ESP32 MQTT TLS/SSL Client v2.0");
// Inicializar pines de sensores
pinMode(2, OUTPUT); // LED indicador
// Conectar a WiFi
setupWiFi();
// Configurar cliente MQTT seguro
setupMQTTSecure();
Serial.println("✅ Sistema iniciado correctamente");
}
// ==================== CONFIGURACIÓN WIFI ====================
void setupWiFi() {
Serial.print("🌐 Conectando a WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(1000);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n✅ WiFi conectado!");
Serial.print("📍 IP address: ");
Serial.println(WiFi.localIP());
Serial.print("📡 Signal strength: ");
Serial.println(WiFi.RSSI());
} else {
Serial.println("\n❌ Error: No se pudo conectar a WiFi");
ESP.restart();
}
}
// ==================== CONFIGURACIÓN MQTT SEGURO ====================
void setupMQTTSecure() {
Serial.println("🔐 Configurando conexión MQTT segura...");
// Configurar certificado CA para validar servidor
espClient.setCACert(ca_cert);
// Opcional: Configurar certificado de cliente para autenticación mutua
// espClient.setCertificate(client_cert);
// espClient.setPrivateKey(client_key);
// Configurar servidor MQTT
client.setServer(mqtt_server, mqtt_port);
client.setCallback(messageCallback);
// Buffer más grande para mensajes JSON
client.setBufferSize(1024);
Serial.println("✅ Configuración MQTT completada");
}
// ==================== CALLBACK PARA MENSAJES RECIBIDOS ====================
void messageCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("📨 Mensaje recibido en tópico: ");
Serial.println(topic);
// Convertir payload a string
String message = "";
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.print("💬 Mensaje: ");
Serial.println(message);
// Procesar comandos remotos
processRemoteCommand(topic, message);
}
// ==================== PROCESAMIENTO DE COMANDOS REMOTOS ====================
void processRemoteCommand(String topic, String message) {
if (topic.endsWith("/commands")) {
JsonDocument doc;
deserializeJson(doc, message);
String command = doc["cmd"];
if (command == "restart") {
Serial.println("🔄 Comando de reinicio recibido");
delay(1000);
ESP.restart();
}
else if (command == "led_on") {
digitalWrite(2, HIGH);
Serial.println("💡 LED encendido por comando remoto");
}
else if (command == "led_off") {
digitalWrite(2, LOW);
Serial.println("💡 LED apagado por comando remoto");
}
}
}
// ==================== BUCLE PRINCIPAL ====================
void loop() {
// Mantener conexión MQTT
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
// Leer sensores cada 30 segundos
if (millis() - lastSensorRead > sensorInterval) {
readSensors();
publishSensorData();
lastSensorRead = millis();
}
delay(100); // Pequeño delay para estabilidad
}
// ==================== RECONEXIÓN MQTT ====================
void reconnectMQTT() {
Serial.println("🔄 Intentando reconexión MQTT...");
while (!client.connected()) {
Serial.print("🔌 Conectando a broker MQTT: ");
Serial.println(mqtt_server);
if (client.connect(client_id, mqtt_username, mqtt_password)) {
Serial.println("✅ Conectado al broker MQTT!");
// Suscribirse a tópicos de comandos
String commandTopic = String("factory/esp32/") + client_id + "/commands";
client.subscribe(commandTopic.c_str());
Serial.println("📥 Suscrito a: " + commandTopic);
// Publicar mensaje de conectividad
publishConnectionStatus(true);
} else {
Serial.print("❌ Error de conexión MQTT, rc=");
Serial.println(client.state());
Serial.println("🔄 Reintentando en 5 segundos...");
delay(5000);
}
}
}
// ==================== LECTURA DE SENSORES ====================
void readSensors() {
// Simular lectura de sensores (reemplazar con código real)
temperature = 22.5 + random(-50, 50) / 10.0; // Simular variación
humidity = 65.0 + random(-100, 100) / 10.0;
// Parpadear LED para indicar lectura
digitalWrite(2, HIGH);
delay(100);
digitalWrite(2, LOW);
}
// ==================== PUBLICACIÓN DE DATOS ====================
void publishSensorData() {
JsonDocument doc;
// Crear payload JSON con datos del sensor
doc["device_id"] = client_id;
doc["timestamp"] = millis();
doc["temperature"] = temperature;
doc["humidity"] = humidity;
doc["wifi_rssi"] = WiFi.RSSI();
doc["free_heap"] = ESP.getFreeHeap();
doc["uptime"] = millis() / 1000;
String jsonString;
serializeJson(doc, jsonString);
// Publicar en múltiples tópicos
String dataTopic = String("factory/sensors/") + client_id + "/data";
if (client.publish(dataTopic.c_str(), jsonString.c_str(), true)) { // retained=true
Serial.println("📤 Datos publicados: " + jsonString);
} else {
Serial.println("❌ Error al publicar datos");
}
}
// ==================== PUBLICAR ESTADO DE CONEXIÓN ====================
void publishConnectionStatus(bool connected) {
JsonDocument doc;
doc["device_id"] = client_id;
doc["connected"] = connected;
doc["timestamp"] = millis();
doc["ip_address"] = WiFi.localIP().toString();
String jsonString;
serializeJson(doc, jsonString);
String statusTopic = String("factory/status/") + client_id;
client.publish(statusTopic.c_str(), jsonString.c_str(), true);
Serial.println(connected ? "🟢 Estado: Conectado" : "🔴 Estado: Desconectado");
}
Análisis del Código
🔐 Características de Seguridad:
- Certificado CA: Validación del servidor
- Puerto 8883: MQTT sobre TLS/SSL
- Autenticación: Usuario y contraseña
- Mensajes retenidos: Persistencia de estado
⚡ Optimizaciones:
- Reconexión automática: Tolerancia a fallas
- Buffer expandido: Mensajes JSON grandes
- Watchdog: Reinicio automático
- Telemetría: Monitoreo de sistema
Ejercicios Prácticos Visuales
Implementaciones paso a paso de MQTT seguro en diferentes escenarios
Objetivo: Desarrollar un sensor IoT que publique datos de temperatura y humedad en un broker MQTT seguro usando cifrado TLS/SSL.
Materiales Requeridos:
- ESP32 DevKit V1
- Sensor DHT22 (±0.5°C precisión)
- Resistor pull-up 4.7kΩ
- Protoboard y cables jumper
- Fuente 5V/1A
Especificaciones Técnicas:
- Protocolo: MQTT 3.1.1 sobre TLS 1.2
- Frecuencia: Lecturas cada 10 segundos
- QoS: Nivel 1 (At least once)
- Payload: JSON con timestamp
- Retained: Último valor persistente
Resultados Esperados:
Datos cifrados de temperatura y humedad publicados cada 10s en tópico sensors/dht22/{device_id}/data
con validación de integridad TLS.
Objetivo: Implementar un sistema de control remoto seguro que reciba comandos cifrados vía MQTT y controle actuadores industriales.
Componentes Electrónicos:
- ESP32 con módulo TLS hardware
- Relé 5V/10A (control cargas AC)
- LED RGB indicador de estado
- Buzzer piezo (alertas sonoras)
- Optoacoplador 4N35 (aislación)
Características de Seguridad:
- Autenticación mutua: Client + Server certificates
- Command validation: Hash SHA-256
- Timeout protection: Auto-desconexión 30s
- Fail-safe: Estado seguro en caso de falla
Objetivo: Desarrollar una estación de monitoreo industrial completa con múltiples sensores, actuadores y comunicación MQTT segura tolerante a fallos.
Sensores Integrados:
- 📡 DHT22 - Temp/Humedad ambiente
- 🌊 Ultrasonido - Nivel de tanques
- ⚡ ACS712 - Corriente eléctrica
- 💨 MQ-135 - Calidad del aire
- 📈 MPU6050 - Vibración/Inclinación
Control de Actuadores:
- 🔵 Válvulas solenoides (4x)
- 🟢 Motores paso a paso (2x)
- 🔴 Alarms & Warning lights
- 📢 Sirenas industriales
- 🖥️ Display información local
Arquitectura de Tópicos:
factory/line1/station_{id}/
sensors/temperature
- Datos térmicossensors/vibration
- FFT Analysisactuators/valves
- Control hidráulicoalerts/critical
- Emergenciasstatus/heartbeat
- Keep-alive
Proyecto Aplicado
Sistema Integral de Monitoreo Industrial con MQTT Seguro
Sistema de Monitoreo de Planta Industrial
Implementación completa de una solución IoT industrial que integra múltiples sensores críticos y actuadores de control, comunicándose a través de MQTT con cifrado TLS/SSL end-to-end. El sistema proporciona monitoreo en tiempo real, alertas automáticas y control remoto seguro para aplicaciones de manufactura crítica.
Características Destacadas
- 🔒 Seguridad Enterprise: TLS 1.3 con autenticación mutua
- 📊 Analytics en Tiempo Real: InfluxDB + Grafana
- 🚨 Sistema de Alertas: SMS/Email/Slack integration
- ⚡ Alta Disponibilidad: Cluster MQTT redundante
- 📱 Dashboard Responsive: Control desde cualquier dispositivo
- 🔄 OTA Updates: Actualización firmware remota
- 💾 Data Persistence: Buffer local + Cloud backup
- 🔧 Mantenimiento Predictivo: ML para detección anomalías
Métricas del Sistema
Integración Sensores/Actuadores
Sensores Críticos
Control de Actuadores
Lista de Materiales
- ESP32 WROOM-32D (x3) - $45
- Raspberry Pi 4 (Broker) - $85
- Power Supply 24V/5A - $35
- DS18B20 (x8) - $40
- Pressure transmitter - $120
- Current clamp - $65
Roadmap de Implementación
Fase de Diseño e Infraestructura
Configuración del broker MQTT seguro, generación de certificados TLS, diseño de la topología de red industrial y definición de tópicos MQTT.
Desarrollo del Firmware ESP32
Implementación del cliente MQTT seguro, integración de drivers de sensores, sistema de logging local y protocolo de reconexión automática.
Integración y Testing
Pruebas de carga del sistema MQTT, validación de seguridad TLS, testing de tolerancia a fallos y benchmarking de performance.
Despliegue en Producción
Instalación en ambiente industrial, configuración de monitoring y alertas, documentación técnica y capacitación del personal.
Evaluación y Troubleshooting
Diagnóstico avanzado, solución de problemas y criterios de evaluación profesional
Problemas Comunes y Soluciones Expertas
Error de Conexión MQTT Broker
CRÍTICOSíntomas: client.connect() retorna false, código de error -2 o -4
🔧 Diagnóstico paso a paso:
- Verificar conectividad básica:
ping mqtt.broker.com
- Validar puerto TLS:
telnet mqtt.broker.com 8883
- Debug certificado CA:
espClient.setInsecure(); // Solo para testing
- Verificar credenciales: Usuario/contraseña correctos
- Revisar Client ID: Debe ser único por conexión
Fallo en Validación de Certificados TLS/SSL
ALTOSíntomas: "SSL certificate verify failed", handshake_failure
🔍 Verificaciones:
- Certificado CA válido y actualizado
- Formato PEM correcto (\n incluidos)
- Fecha de expiración del certificado
- CN del certificado coincide con hostname
🛠️ Herramientas de Debug:
// Habilitar debug SSL
espClient.setDebugMsgTypes(SSL_INFO);
// Verificar memoria heap
Serial.println(ESP.getFreeHeap());
// Test certificado online
openssl s_client -connect broker:8883
Agotamiento de Memoria Heap
MEDIOSíntomas: Crashes aleatorios, guru meditation error, reconnect loops
⚡ Optimizaciones de Memoria:
client.setBufferSize(512); // Reducir si es necesario
const char* ca_cert PROGMEM = "...";
// Usar streaming en lugar de buffer completo
yield(); // En loops largos
Criterios de Evaluación
🔒 Seguridad (40%)
⚡ Funcionalidad (35%)
🔧 Código (25%)
📊 Cálculo de Calificación:
Nota = (Seg×0.4) + (Func×0.35) + (Code×0.25)