Conectar a MyQttHub con MQTT sobre WebSocket seguro (WSS)


#1

Conectar a MyQttHub con MQTT sobre WebSocket seguro (WSS)

El nodo público node02.myqtthub.com acepta conexiones MQTT sobre WebSocket cifrado (WSS) en el puerto 443, el mismo que usa la web. Esto añade una tercera forma de conectarse, junto a las que ya existían:

Transporte Endpoint Para qué sirve
MQTT node02.myqtthub.com:1883 Dispositivos y servidores en red de confianza
MQTT sobre TLS node02.myqtthub.com:8883 Dispositivos y servidores, cifrado
MQTT sobre WebSocket + TLS wss://node02.myqtthub.com/mqtt Navegadores y redes restrictivas

Cuándo conviene usar WebSocket

Hay dos casos en los que es la única opción práctica:

  1. Desde un navegador. El JavaScript de una página no puede abrir un socket TCP, así que un panel web, un dashboard o una aplicación que corra en el navegador sólo puede hablar MQTT a través de WebSocket.
  2. Detrás de una red restrictiva. Muchas redes corporativas, wifis de hoteles y accesos móviles sólo dejan salir por el 443. Como el WSS viaja por ese puerto y es indistinguible de tráfico HTTPS, atraviesa esos filtros donde el 1883 o el 8883 quedarían bloqueados.

Si tus dispositivos están en una red donde puedes abrir el 8883, ese sigue siendo el camino más directo. WebSocket añade una pequeña sobrecarga por el entramado de los mensajes.

Datos de conexión

URL           : wss://node02.myqtthub.com/mqtt
Host          : node02.myqtthub.com
Puerto        : 443
Ruta          : /mqtt
Subprotocolo  : mqtt
Versión MQTT  : 3.1.1
Credenciales  : Client ID, usuario y contraseña del dispositivo

Las credenciales son las mismas que usarías por el 8883: el Client ID, el usuario y la contraseña del dispositivo dado de alta en tu hub. No hay que crear nada nuevo para usar WebSocket.

Tres detalles que evitan la mayoría de los problemas:

  • La ruta /mqtt es obligatoria. Conectar a wss://node02.myqtthub.com/ sin ella no funciona.
  • Usa wss://, nunca ws://. Una página servida por HTTPS tiene prohibido abrir conexiones sin cifrar: el navegador las bloquea por contenido mixto.
  • El subprotocolo es mqtt. Casi todas las librerías lo envían solas; si tu cliente permite configurarlo, ése es el valor. También se acepta mqttv3.1 para clientes antiguos.

El certificado del servidor es público (emitido por una CA reconocida), así que no hace falta instalar ningún certificado ni desactivar la verificación TLS.

Ejemplo: navegador (MQTT.js)

<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
<script>
  const client = mqtt.connect("wss://node02.myqtthub.com/mqtt", {
    clientId: "miDispositivoId",
    username: "miUsuario",
    password: "miContraseña",
    protocolVersion: 4,   // MQTT 3.1.1
    clean: true,
    keepalive: 30
  });

  client.on("connect", () => {
    console.log("Conectado");
    client.subscribe("casa/salon/temperatura");
    client.publish("casa/salon/estado", "online");
  });

  client.on("message", (topic, payload) => {
    console.log(topic, payload.toString());
  });

  client.on("error", (err) => console.error("Error:", err));
</script>

Ejemplo: Python (paho-mqtt)

import paho.mqtt.client as mqtt

client = mqtt.Client(client_id="miDispositivoId", transport="websockets")
client.username_pw_set("miUsuario", "miContraseña")
client.tls_set()                       # certificado público: sin parámetros
client.ws_set_options(path="/mqtt")

client.connect("node02.myqtthub.com", 443, keepalive=30)
client.loop_forever()

Ojo a dos puntos que suelen despistar: el puerto es el 443 (no el 8883) y la ruta se configura aparte con ws_set_options, no forma parte del host.

Ejemplo: Node.js

const mqtt = require("mqtt");

const client = mqtt.connect("wss://node02.myqtthub.com/mqtt", {
  clientId: "miDispositivoId",
  username: "miUsuario",
  password: "miContraseña",
  keepalive: 30
});

client.on("connect", () => client.subscribe("casa/#"));
client.on("message", (topic, payload) =>
  console.log(topic, payload.toString()));

Clientes gráficos

En MQTTX, MQTT Explorer o similares, la configuración equivalente es:

Protocol / Schema : wss
Host              : node02.myqtthub.com
Port              : 443
Path              : /mqtt
Username / Password : los de tu dispositivo
Client ID         : el de tu dispositivo

Comprobar que el servicio responde

Sin ningún cliente MQTT, puedes verificar el canal con openssl:

printf 'GET /mqtt HTTP/1.1\r\nHost: node02.myqtthub.com\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Protocol: mqtt\r\n\r\n' \
  | openssl s_client -connect node02.myqtthub.com:443 -servername node02.myqtthub.com -quiet 2>/dev/null \
  | head -6

La respuesta debe ser:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: mqtt

Ese 101 confirma que el canal WebSocket se establece y que el subprotocolo mqtt se negocia correctamente. A partir de ahí, cualquier fallo será de credenciales o de configuración del cliente, no de conectividad.

Recomendaciones y problemas frecuentes

Configura un keepalive de 30 a 60 segundos. Una conexión WebSocket que se queda muda demasiado tiempo puede ser cerrada por los equipos intermedios. El PINGREQ de MQTT es lo que la mantiene viva; con 30 segundos vas sobrado y el consumo es mínimo.

Usa un Client ID único por dispositivo. Si dos clientes se conectan con el mismo Client ID, el segundo desplaza al primero. Es la causa número uno de “se me desconecta solo cada pocos segundos”.

Los mensajes viajan en tramas binarias. No es algo que tengas que configurar, pero conviene saberlo: la librería se encarga de reensamblar los paquetes MQTT, y las fronteras de las tramas WebSocket no coinciden necesariamente con las de los mensajes MQTT.

En el panel verás tu IP real. Las conexiones por WebSocket aparecen en la lista de conexiones con el protocolo mqtt-ws y con la dirección pública desde la que se conectan, igual que las del 1883 o el 8883.

Si usas un proxy propio delante, recuerda que WebSocket necesita que reenvíe las cabeceras Upgrade y Connection. En Apache eso significa mod_proxy_wstunnel; en nginx, proxy_set_header Upgrade y proxy_set_header Connection "upgrade".

Otros nodos

Este artículo describe el servicio de node02.myqtthub.com. Si tu hub está en otro nodo, el endpoint de WebSocket puede ser distinto. Escríbenos y te confirmamos el que corresponde a tu instalación.

¿Dudas o algo que no funciona como esperas? Responde en este hilo o escribe a support@myqtthub.com.


Soporte de WebSockets
WebSockets Support?
MyQttHub ES -- Empieza por aquí