Fundamentos de MQTT

User properties de MQTT 5: añade metadatos sin tocar el payload

Las user properties de MQTT 5 son cabeceras clave/valor que puedes adjuntar a un mensaje sin cambiar su payload. Aprende cómo funcionan, para qué sirven y cómo enviarlas y leerlas en Python, Node.js y la línea de comandos.

Sobre de mensaje con etiquetas clave/valor adjuntas, ilustrando las propiedades de usuario MQTT en MQTT 5
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

Las propiedades de usuario MQTT (user properties) son pares de cadenas clave/valor que adjuntas a un mensaje MQTT 5, de forma muy parecida a las cabeceras HTTP. Te permiten enviar metadatos como un trace ID, una versión de esquema o la unidad de una medida sin cambiar el formato de payload que tus consumidores ya interpretan. En este artículo aprenderás cómo se comportan las user properties, dónde ayudan de verdad y cómo publicarlas y leerlas en Python, Node.js y la línea de comandos.

Qué son las propiedades de usuario MQTT

MQTT 3.1.1 no tenía sitio para los metadatos. Todo lo que fuera más allá del topic y del payload había que meterlo en el propio payload o codificarlo en el nombre del topic. MQTT 5 introdujo propiedades en la mayoría de los paquetes, y la User Property es la que queda abierta para las aplicaciones.

Datos clave sobre las user properties:

  • Cada propiedad es un par de cadenas UTF-8: un nombre y un valor.
  • Un mensaje puede llevar cualquier número de ellas, y el mismo nombre puede aparecer más de una vez.
  • El orden se conserva. El broker las reenvía en el orden en que se enviaron.
  • En los paquetes PUBLISH, el broker las pasa a los suscriptores sin modificarlas.
  • Cuentan para el tamaño del paquete y, por tanto, para cualquier límite de tamaño de mensaje.
  • También pueden aparecer en CONNECT, SUBSCRIBE, DISCONNECT y otros paquetes, aunque PUBLISH es donde más las usan las aplicaciones.

Como el broker no las interpreta, las user properties son únicamente un contrato entre tus publicadores y tus suscriptores. Son una de las varias funciones de MQTT 5 que hacen el protocolo más amigable para sistemas grandes.

Casos de uso habituales de las propiedades de usuario MQTT

Caso de uso Propiedad de ejemplo Por qué no en el payload
Trazabilidad distribuida traceparent=00-4bf9...-01 La trazabilidad es transversal; los esquemas de payload no deberían cambiar por ella
Versionado de esquemas schema=telemetry.v3 Los consumidores eligen un parser antes de decodificar
Metadatos del contenido unit=celsius, encoding=gzip Describe cómo leer el payload
Identificación del origen source=gateway-12, fw=2.4.1 Útil para depurar sin tocar los datos
Pistas de enrutamiento tenant=plant-a Permite al middleware filtrar sin parsear
Marcadores de prueba synthetic=true Permite a los consumidores descartar el tráfico de pruebas

El hilo común: información sobre el mensaje, no la medida en sí. Si un dashboard necesita un valor para dibujar un gráfico, ese valor va en el payload. Si un valor le dice al software cómo tratar el mensaje, una user property encaja bien.

Para payloads binarios como Protobuf, las user properties resultan especialmente prácticas, porque puedes añadir metadatos sin cambiar el archivo .proto. Consulta los formatos de payload MQTT para esa comparación.

Enviar user properties desde la línea de comandos

Los clientes de Mosquitto admiten user properties cuando seleccionas MQTT 5. Usaremos el servidor MQTT público gratuito en broker.connectmq.com con un prefijo de topic único; es apto para pruebas, no para datos de producción.

Suscríbete primero. El especificador de formato %P imprime las user properties:

mosquitto_sub -V mqttv5 -h broker.connectmq.com -p 1883 -i up-sub-w2c5 \
  -t 'connectmq/demo/w2c5/#' -F '%t %p | props: %P'

Luego publica con dos propiedades:

mosquitto_pub -V mqttv5 -h broker.connectmq.com -p 1883 -i up-pub-w2c5 \
  -t connectmq/demo/w2c5/line1/temp -m '21.7' \
  -D publish user-property unit celsius \
  -D publish user-property schema temp.v1

El suscriptor imprime el topic, el payload y unit:celsius schema:temp.v1. Publica el mismo comando con -V mqttv311 y el suscriptor seguirá recibiendo el payload, pero sin propiedades, porque MQTT 3.1.1 no puede transportarlas.

Publicar y leer user properties en Python

En paho-mqtt 2.x, las user properties son una lista de tuplas en un objeto Properties. Una lista y no un diccionario, porque los nombres pueden repetirse:

import time
import uuid
import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes

BROKER = "broker.connectmq.com"
TOPIC = "connectmq/demo/w2c5/line1/pressure"

def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(TOPIC, qos=1)

def on_subscribe(client, userdata, mid, reason_code_list, properties):
    props = Properties(PacketTypes.PUBLISH)
    props.UserProperty = [
        ("trace-id", uuid.uuid4().hex),
        ("unit", "bar"),
        ("source", "gateway-12"),
    ]
    client.publish(TOPIC, "2.31", qos=1, properties=props)

def on_message(client, userdata, msg):
    user_props = dict(getattr(msg.properties, "UserProperty", []))
    print(msg.topic, msg.payload.decode(), user_props)

client = mqtt.Client(
    mqtt.CallbackAPIVersion.VERSION2,
    client_id=f"up-py-{uuid.uuid4().hex[:8]}",
    protocol=mqtt.MQTTv5,
)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_message = on_message
client.connect(BROKER, 1883, keepalive=30)
client.loop_start()
time.sleep(3)
client.loop_stop()
client.disconnect()

Convertirlas en un diccionario es cómodo, pero solo si sabes que tus nombres son únicos. Si permites nombres repetidos, conserva la lista.

User properties en Node.js

MQTT.js v5 expone las user properties como un objeto simple en properties.userProperties. Un valor puede ser una cadena o un array de cadenas en el caso de nombres repetidos:

const mqtt = require("mqtt");

const client = mqtt.connect("mqtts://broker.connectmq.com:8883", {
  clientId: "up-js-" + Math.random().toString(16).slice(2, 10),
  protocolVersion: 5,
});
const topic = "connectmq/demo/w2c5/line1/flow";

client.on("connect", () => {
  client.subscribe(topic, { qos: 1 }, () => {
    client.publish(topic, "12.4", {
      qos: 1,
      properties: {
        userProperties: { unit: "m3/h", tag: ["calibrated", "line1"] },
      },
    });
  });
});

client.on("message", (t, payload, packet) => {
  console.log(t, payload.toString(), packet.properties?.userProperties);
  client.end();
});

User properties frente a niveles de topic y campos del payload

Hay tres lugares donde poner un dato en un mensaje MQTT, y cada uno tiene un coste distinto:

Ubicación Adecuada para Visible para Coste
Nivel del topic Enrutamiento y filtrado de suscripciones (instalación, línea, dispositivo) El broker, todos los suscriptores, los comodines Forma parte de cada cadena de topic; cambiarla rompe suscripciones
User property Instrucciones de tratamiento, trazabilidad, versión de esquema Solo los suscriptores; el broker la ignora Bytes en cada mensaje; se pierde en saltos MQTT 3.1.1
Campo del payload Datos de negocio que los consumidores almacenan o muestran Los suscriptores tras decodificar Añadirlo requiere cambiar el esquema

Una regla práctica útil: si un suscriptor necesita filtrar por ello, usa el topic. Si un suscriptor necesita decidir cómo procesar el mensaje antes de decodificarlo, usa una user property. Si el suscriptor lo almacena o lo muestra, ponlo en el payload.

Por ejemplo, un valor unit podría ir tanto en una propiedad como en el payload. Si todos los consumidores guardan la unidad junto al valor, ponla en el payload para que sobreviva al escribirse en una base de datos. Si la unidad es fija por topic y solo la comprueba una capa de validación, una propiedad es más limpia. Ten en cuenta que las suscripciones con comodines solo filtran por niveles de topic: un suscriptor no puede pedir al broker "mensajes en los que tenant sea plant-a" basándose en una user property.

Pautas de diseño

  1. Define un vocabulario reducido. Poneos de acuerdo entre equipos en un puñado de nombres y documentadlos. Las propiedades improvisadas se convierten rápidamente en ruido.
  2. Mantenlas cortas. Las propiedades viajan con cada mensaje. Diez cabeceras largas en una lectura de sensor de 20 bytes pueden multiplicar su tamaño.
  3. No pongas secretos en ellas. Son tan visibles como el payload para cualquiera que pueda suscribirse.
  4. No dependas de ellas para datos críticos si algunos consumidores siguen usando MQTT 3.1.1. Esos consumidores las perderán sin avisar.
  5. Usa formatos estándar cuando existan, como traceparent de W3C para la trazabilidad, para que las herramientas puedan entenderlas.
  6. Prefiere content type para el tipo de payload. MQTT 5 tiene una propiedad Content Type dedicada y un Payload Format Indicator; úsalos en lugar de una user property content-type personalizada.

Resolución de problemas con las user properties

Faltan las propiedades en el suscriptor. El suscriptor o el publicador se conectó con MQTT 3.1.1. Ambas conexiones deben ser MQTT 5.

Los mensajes se rechazan por ser demasiado grandes. Las propiedades cuentan para el tamaño del paquete. En un plan o broker con límite de tamaño, recórtalas. Nuestro artículo sobre el límite de tamaño de mensaje en MQTT explica cómo se aplica el límite.

Los valores aparecen como arrays inesperadamente. En MQTT.js, un nombre repetido se convierte en un array. Gestiona ambas formas o evita repetir nombres.

Los mensajes reenviados o republicados pierden las propiedades. Cualquier componente que lea y vuelva a publicar un mensaje debe copiar las propiedades explícitamente; muchos scripts sencillos no lo hacen.

User properties en ConnectMQ

ConnectMQ reenvía sin cambios las user properties de MQTT 5 entre publicadores y suscriptores, como cualquier broker conforme al estándar. Recuerda que cuentan para el tamaño del mensaje: 256 KB en el plan Serverless (Free), 1 MB en el plan Serverless (Paid) y 64 KB en el servidor MQTT público gratuito. Para ver tus metadatos en la práctica, suscríbete con el comando de Mosquitto anterior o con tu propio cliente contra tu broker, usando las credenciales del portal. Si todavía estás eligiendo infraestructura, nuestra visión general de un broker MQTT gestionado explica lo que obtienes, y el tutorial de MQTT cubre los fundamentos.

Empieza con ConnectMQ

Regístrate en app.connectmq.com y crea un broker en el plan Serverless gratuito, sin tarjeta de crédito. Conéctate con MQTT 5, añade un trace ID a tus mensajes y síguelos desde el dispositivo hasta el dashboard en tu propio broker MQTT en la nube.

Preguntas frecuentes

¿Pueden repetirse los nombres de las user properties?

Sí. MQTT 5 permite el mismo nombre más de una vez y el broker conserva el orden. Guárdalas como lista si dependes de ello.

¿Modifica el broker las user properties?

En los paquetes PUBLISH, el broker las reenvía sin cambios a los suscriptores. No las interpreta ni las filtra.

¿Están disponibles las user properties en MQTT 3.1.1?

No. Son una función de MQTT 5. Un suscriptor 3.1.1 recibe el payload sin ninguna propiedad.

¿Cuentan las user properties para el tamaño del mensaje?

Sí. Forman parte del paquete, así que cuentan para el tamaño máximo de paquete del broker.

Artículos relacionados

¿Quién inventó MQTT? La historia, de los oleoductos al IoT

MQTT lo inventaron en 1999 Andy Stanford-Clark, de IBM, y Arlen Nipper, de Arcom, para monitorizar oleoductos vía satélite. Sigue su camino hacia el open source, OASIS, ISO y los brokers MQTT gestionados en la nube de hoy.

8 min de lectura

Por qué tu cliente MQTT se desconecta constantemente (y cómo solucionarlo)

Los bucles de reconexión son uno de los problemas más habituales de MQTT. Conoce las cinco causas típicas, desde los client ID duplicados hasta los timeouts de keep alive y los paquetes demasiado grandes, y sigue un flujo de diagnóstico que localiza la tuya.

9 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.