El gateway zwave-js-ui MQTT publica cada valor Z-Wave, desde sensores de puerta hasta niveles de regulación, como mensajes MQTT que cualquier panel, script o herramienta de automatización puede aprovechar. En esta guía ejecutarás Z-Wave JS UI en Docker, configurarás sus ajustes de MQTT y de gateway, escribirás valores de vuelta con topics /set y reenviarás los datos a un broker en la nube con TLS.
Qué hace el gateway MQTT de Z-Wave JS UI
Z-Wave JS UI (antes zwavejs2mqtt) envuelve el driver Z-Wave JS en una interfaz web para incluir dispositivos, reparar la red y editar parámetros de configuración. Expone la red de dos maneras: un servidor WebSocket, que es el que usa la integración Z-Wave JS de Home Assistant, y un gateway MQTT, que publica valores en un broker y acepta escrituras desde él.
La parte MQTT es la que te interesa cuando los consumidores no son Home Assistant: flujos de Node-RED, Telegraf alimentando una base de datos de series temporales, un backend propio o un panel remoto. Cada uno de ellos simplemente se suscribe a topics en el broker. Si el papel del broker es nuevo para ti, lee primero qué hace un broker MQTT.
Paso 1: ejecutar Z-Wave JS UI
Docker es la forma más habitual de ejecutarlo. Localiza la ruta estable de tu stick Z-Wave con ls -l /dev/serial/by-id/ e inicia el contenedor:
docker run -d --name zwave-js-ui --restart unless-stopped \
-p 8091:8091 -p 3000:3000 \
--device=/dev/serial/by-id/usb-Silicon_Labs_CP2102N_USB_to_UART_Bridge-if00-port0:/dev/zwave \
-v zwave-config:/usr/src/app/store \
zwavejs/zwave-js-ui:latest
Sustituye la ruta del dispositivo por la tuya. Abre http://<host>:8091, ve a Settings y luego a Z-Wave, establece el puerto serie en /dev/zwave, genera las claves de seguridad y guarda. Incluye uno o dos dispositivos antes de continuar, para que haya algo que publicar.
Paso 2: entender la estructura de topics
Los valores se publican siguiendo este patrón:
<prefix>/<location>/<node name>/<command class>/<endpoint>/<property>
Para un regulador llamado desk_lamp en la ubicación office, con el prefijo zwave, el nivel actual está en zwave/office/desk_lamp/38/0/currentValue, donde 38 es la command class Multilevel Switch. Para cambiarlo, publica en el mismo topic añadiendo /set, normalmente sobre targetValue:
| Propósito | Topic | Payload |
|---|---|---|
| Actualización de valor | zwave/office/desk_lamp/38/0/currentValue |
{"time":1760600000000,"value":60} |
| Escribir un valor | zwave/office/desk_lamp/38/0/targetValue/set |
{"value":100} |
| Estado del nodo | zwave/office/desk_lamp/status |
true / false o JSON |
| Estado del gateway | zwave/_CLIENTS/ZWAVE_GATEWAY-<name>/status |
true / false |
| Llamada a la API | zwave/_CLIENTS/ZWAVE_GATEWAY-<name>/api/<api>/set |
{"args":[...]} |
El topic de estado del gateway es especialmente útil: indica a los consumidores remotos si el propio Z-Wave JS UI está conectado, con independencia de cualquier dispositivo.
Paso 3: probar el gateway zwave-js-ui MQTT en el servidor MQTT público gratuito
Antes de montar nada permanente, comprueba que el gateway funciona con el servidor MQTT público gratuito en broker.connectmq.com. Acepta conexiones anónimas con cualquier client ID único. Aquí importan dos detalles:
- Z-Wave JS UI construye su client ID como
ZWAVE_GATEWAY-<Name>, así que el campo Name debe ser único. Usa un sufijo aleatorio. - El área pública permite un máximo de ocho niveles de topic. Un prefijo largo más ubicación, nombre de nodo, command class, endpoint, propiedad y
/setlo supera con facilidad, así que usa un prefijo corto y desactiva las ubicaciones en los topics.
En Settings y luego MQTT, introduce:
| Campo | Valor |
|---|---|
| Name | zw-h2k8tp |
| Host url | mqtts://broker.connectmq.com |
| Port | 8883 |
| Reconnect period | 5000 |
| Prefix | connectmq/demo/h2k8tp |
| QoS | 1 |
| Retain | activado |
| Clean | activado |
| Auth | desactivado |
| Allow self signed certs | desactivado |
Después, en Settings y luego Gateway, elige:
- Type: ValueId topics.
- Payload type: JSON Time-Value.
- Use nodes name instead of numeric nodeIDs: activado.
- Ignore location: activado.
Guarda y suscríbete desde un terminal:
mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-i watch-h2k8tp -t 'connectmq/demo/h2k8tp/#' -v
Verás el estado del gateway y luego los valores de cada nodo. Acciona la lámpara:
mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
-i send-h2k8tp -t 'connectmq/demo/h2k8tp/desk_lamp/38/0/targetValue/set' \
-m '{"value":40}'
Unos instantes después, currentValue se actualiza a 40. Recuerda que el área pública es visible para todo el mundo; úsala solo para pruebas inofensivas, nunca para cerraduras, alarmas o puertas de garaje.
Paso 4: configuración de producción con un puente local
Los brokers privados emiten las credenciales junto con un client ID fijo. ConnectMQ vincula el client ID al usuario y la contraseña emitidos, y Z-Wave JS UI siempre antepone ZWAVE_GATEWAY- a su client ID. En la práctica, eso significa que Z-Wave JS UI no puede presentar exactamente el ID emitido.
La solución limpia es un pequeño puente Mosquitto junto a Z-Wave JS UI. Z-Wave JS UI se conecta al Mosquitto local sin TLS, y Mosquitto reenvía los topics zwave/# al broker en la nube usando tu client ID, usuario y contraseña emitidos sobre TLS. Como ventaja añadida, las automatizaciones locales siguen funcionando durante un corte de internet.
docker-compose.yml:
services:
mosquitto:
image: eclipse-mosquitto:2
restart: unless-stopped
volumes:
- ./mosquitto.conf:/mosquitto/config/mosquitto.conf:ro
- /etc/ssl/certs:/etc/ssl/certs:ro
zwave-js-ui:
image: zwavejs/zwave-js-ui:latest
restart: unless-stopped
ports:
- "8091:8091"
- "3000:3000"
devices:
- /dev/serial/by-id/usb-Silicon_Labs_CP2102N_USB_to_UART_Bridge-if00-port0:/dev/zwave
volumes:
- zwave-config:/usr/src/app/store
depends_on:
- mosquitto
volumes:
zwave-config:
mosquitto.conf:
listener 1883
allow_anonymous true
connection connectmq
address broker.connectmq.com:8883
remote_clientid YOUR_CLIENT_ID
remote_username YOUR_USERNAME
remote_password YOUR_PASSWORD
bridge_capath /etc/ssl/certs
bridge_protocol_version mqttv311
try_private false
cleansession true
topic zwave/# both 1
El listener local solo es accesible dentro de la red de Compose, porque el puerto 1883 no se publica en el host. En Z-Wave JS UI, cambia los ajustes de MQTT a Host url mqtt://mosquitto, Port 1883, Prefix zwave, Auth desactivado. Puedes volver a desactivar Ignore location, ya que los brokers privados no están sujetos al límite público de ocho niveles.
try_private false es importante: desactiva un handshake de puente específico de Mosquitto que otros brokers no entienden. topic zwave/# both 1 reenvía en ambas direcciones, de modo que los mensajes /set procedentes de la nube llegan a Z-Wave JS UI.
Consumir datos Z-Wave en remoto
Ahora cualquier cliente MQTT con sus propias credenciales puede leer la red desde cualquier lugar. Un consumidor mínimo en Python (paho-mqtt 2.x) que registra los sensores de puerta y el estado del gateway:
import json
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe("zwave/_CLIENTS/+/status", qos=1)
client.subscribe("zwave/+/48/0/+", qos=1) # command class Binary Sensor
def on_message(client, userdata, msg):
try:
data = json.loads(msg.payload)
value = data["value"] if isinstance(data, dict) else data
except ValueError:
value = msg.payload.decode()
print(msg.topic, "->", value)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID")
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set()
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 8883, keepalive=60)
client.loop_forever()
Usa un conjunto de credenciales independiente para este consumidor; no puede compartir el client ID del puente.
Lista de comprobación para resolver problemas
- El estado del gateway se queda en
false: revisa el esquema de la host url (mqtt://frente amqtts://) y la correspondencia de puertos: 1883 sin TLS, 8883 con TLS. - Las escrituras no hacen nada: publica en
targetValue/set, no encurrentValue, y envía JSON con un campovalue. - Algunos topics nunca aparecen en el broker público: superan los ocho niveles. Acorta el prefijo o ignora la ubicación.
- El puente se conecta y luego se cae: otro cliente está usando el mismo client ID emitido.
- Los valores llegan como objetos JSON enormes: el tipo de payload está en "Entire ValueId Object"; cámbialo a JSON Time-Value o Just value.
La documentación oficial de Z-Wave JS UI recoge todos los nombres de la API y las opciones del gateway.
Guías relacionadas de hogar inteligente
Z-Wave rara vez vive solo. La guía de Zigbee2MQTT con broker en la nube aplica el mismo patrón remoto a Zigbee, y la guía de rtl_433 con MQTT añade sensores baratos de 433 MHz. Una estructura de topics MQTT para el hogar inteligente coherente mantiene todo ordenado, y la guía de automatización IoT muestra cómo encajan las piezas.
Conecta tu red Z-Wave a internet con ConnectMQ
Un broker MQTT gestionado da a tu puente un endpoint estable y protegido con TLS sin tener que mantener un servidor en internet. ConnectMQ ofrece MQTT 3.1.1 y 5.0, un explorador de topics en vivo para revisar los topics Z-Wave y reglas de alerta por umbral para valores como la temperatura o el nivel de batería. Crea gratis un broker Serverless en app.connectmq.com, sin tarjeta de crédito.
Preguntas frecuentes
¿Qué client ID usa Z-Wave JS UI para MQTT?
Usa ZWAVE_GATEWAY- seguido del Name definido en los ajustes de MQTT. Haz que el nombre sea único para que dos gateways nunca compartan client ID.
¿Cómo cambio un valor Z-Wave mediante MQTT?
Publica un JSON como {"value":100} en el topic del valor añadiendo /set, normalmente .../38/0/targetValue/set. El nuevo valor aparece en el topic currentValue.
¿Necesito el gateway MQTT si uso Home Assistant?
No necesariamente. La integración Z-Wave JS de Home Assistant usa el servidor WebSocket; el gateway MQTT es para otros consumidores como Node-RED, bases de datos o paneles remotos.
¿Por qué usar un puente Mosquitto en lugar de conectarse directamente?
Porque Z-Wave JS UI antepone un prefijo a su client ID, no puede usar un client ID emitido que el broker vincula a las credenciales. El puente presenta el ID exacto y además mantiene el tráfico local funcionando sin conexión.



