Fundamentos de MQTT

User Properties do MQTT 5: Metadados Sem Mexer no Payload

As user properties do MQTT 5 são cabeçalhos chave/valor que você anexa a uma mensagem sem alterar o payload. Entenda como funcionam, para que servem e como enviá-las e lê-las em Python, Node.js e na linha de comando.

Envelope de mensagem com etiquetas chave/valor anexadas, ilustrando as propriedades de usuário MQTT no MQTT 5
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

As propriedades de usuário MQTT (user properties) são pares de strings chave/valor que você anexa a uma mensagem MQTT 5, de forma muito parecida com cabeçalhos HTTP. Elas permitem enviar metadados como um trace ID, uma versão de schema ou a unidade de uma medição sem alterar o formato de payload que seus consumidores já interpretam. Neste artigo você vai entender como as user properties se comportam, onde elas realmente ajudam e como publicá-las e lê-las em Python, Node.js e na linha de comando.

O que são as propriedades de usuário MQTT

O MQTT 3.1.1 não tinha lugar para metadados. Qualquer coisa além do topic e do payload precisava ser espremida dentro do próprio payload ou codificada no nome do topic. O MQTT 5 introduziu propriedades na maioria dos pacotes, e a User Property é a que ficou aberta para as aplicações.

Fatos importantes sobre as user properties:

  • Cada propriedade é um par de strings UTF-8: um nome e um valor.
  • Uma mensagem pode carregar qualquer quantidade delas, e o mesmo nome pode aparecer mais de uma vez.
  • A ordem é preservada. O broker as encaminha na ordem em que foram enviadas.
  • Em pacotes PUBLISH, o broker as repassa aos assinantes sem alterações.
  • Elas contam para o tamanho do pacote e, portanto, para qualquer limite de tamanho de mensagem.
  • Também podem aparecer em CONNECT, SUBSCRIBE, DISCONNECT e outros pacotes, embora o PUBLISH seja onde as aplicações mais as utilizam.

Como o broker não as interpreta, as user properties são puramente um contrato entre seus publicadores e assinantes. Elas são um dos vários recursos do MQTT 5 que tornam o protocolo mais amigável para sistemas maiores.

Casos de uso comuns das propriedades de usuário MQTT

Caso de uso Exemplo de propriedade Por que não no payload
Rastreamento distribuído traceparent=00-4bf9...-01 Rastreamento é transversal; os schemas de payload não deveriam mudar por causa dele
Versionamento de schema schema=telemetry.v3 Os consumidores escolhem um parser antes de decodificar
Metadados de conteúdo unit=celsius, encoding=gzip Descreve como ler o payload
Identificação da origem source=gateway-12, fw=2.4.1 Útil para depuração sem tocar nos dados
Dicas de roteamento tenant=plant-a Permite que um middleware filtre sem fazer parsing
Marcadores de teste synthetic=true Permite que os consumidores descartem tráfego de teste

O fio condutor: informação sobre a mensagem, não a medição em si. Se um dashboard precisa de um valor para desenhar um gráfico, ele pertence ao payload. Se um valor diz ao software como tratar a mensagem, uma user property é uma boa escolha.

Para payloads binários como Protobuf, as user properties são especialmente úteis, porque você pode adicionar metadados sem alterar o arquivo .proto. Veja formatos de payload MQTT para essa comparação.

Enviando user properties pela linha de comando

Os clients do Mosquitto suportam user properties quando você seleciona MQTT 5. Vamos usar o servidor MQTT público em broker.connectmq.com, destinado a testes, com um prefixo de topic único.

Assine primeiro. O especificador de formato %P imprime as 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'

Depois publique com duas propriedades:

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

O assinante imprime o topic, o payload e unit:celsius schema:temp.v1. Publique o mesmo comando com -V mqttv311 e o assinante ainda recebe o payload, mas sem propriedades, porque o MQTT 3.1.1 não consegue transportá-las.

Publicando e lendo user properties em Python

No paho-mqtt 2.x, as user properties são uma lista de tuplas em um objeto Properties. Uma lista, e não um dict, porque os nomes podem se repetir:

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()

Converter para dict é conveniente, mas só se você souber que seus nomes são únicos. Se permitir nomes repetidos, mantenha a lista.

User properties em Node.js

O MQTT.js v5 expõe as user properties como um objeto simples em properties.userProperties. Um valor pode ser uma string ou um array de strings no caso de nomes 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 vs níveis de topic vs campos do payload

Há três lugares para colocar uma informação em uma mensagem MQTT, e cada um tem um custo diferente:

Local Bom para Visível para Custo
Nível de topic Roteamento e filtragem de assinaturas (site, linha, dispositivo) Broker, todos os assinantes, wildcards Faz parte de toda string de topic; mudanças quebram assinaturas
User property Instruções de tratamento, rastreamento, versão de schema Apenas assinantes; o broker a ignora Bytes por mensagem; perdida em saltos MQTT 3.1.1
Campo do payload Dados de negócio que os consumidores armazenam ou exibem Assinantes, após decodificar Exige mudança de schema para adicionar

Uma regra prática útil: se um assinante precisa filtrar por algo, use o topic. Se um assinante precisa decidir como processar a mensagem antes de decodificá-la, use uma user property. Se o assinante armazena ou exibe a informação, coloque-a no payload.

Por exemplo, um valor unit poderia ir tanto em uma propriedade quanto no payload. Se todo consumidor armazena a unidade junto com o valor, coloque-a no payload para que ela sobreviva à gravação em um banco de dados. Se a unidade é fixa por topic e apenas uma camada de validação a verifica, uma propriedade é mais limpa. Note que assinaturas com wildcard só filtram por níveis de topic: um assinante não pode pedir ao broker "mensagens em que tenant seja plant-a" com base em uma user property.

Diretrizes de design

  1. Defina um vocabulário pequeno. Combine um punhado de nomes entre as equipes e documente-os. Propriedades ad hoc viram ruído rapidamente.
  2. Mantenha-as curtas. As propriedades viajam com cada mensagem. Dez cabeçalhos longos em uma leitura de sensor de 20 bytes podem multiplicar seu tamanho.
  3. Não coloque segredos nelas. Elas são tão visíveis quanto o payload para qualquer um que possa assinar o topic.
  4. Não dependa delas para dados críticos se alguns consumidores ainda usam MQTT 3.1.1. Esses consumidores vão perdê-las silenciosamente.
  5. Use formatos padronizados quando existirem, como o traceparent do W3C para rastreamento, para que as ferramentas consigam entendê-los.
  6. Prefira o content type para indicar o tipo do payload. O MQTT 5 tem uma propriedade Content Type dedicada e um Payload Format Indicator; use-os em vez de uma user property content-type personalizada.

Solução de problemas com user properties

As propriedades não chegam ao assinante. O assinante ou o publicador se conectou com MQTT 3.1.1. As duas conexões precisam ser MQTT 5.

Mensagens são rejeitadas por serem grandes demais. As propriedades contam para o tamanho do pacote. Em um plano ou broker com limite de tamanho, reduza-as. Nosso artigo sobre o limite de tamanho de mensagem MQTT explica como o limite é aplicado.

Valores aparecem como arrays inesperadamente. No MQTT.js, um nome repetido vira um array. Trate os dois formatos ou evite repetir nomes.

Mensagens em bridge ou republicadas perdem as propriedades. Qualquer componente que lê e republica uma mensagem precisa copiar as propriedades explicitamente; muitos scripts simples não fazem isso.

User properties no ConnectMQ

O ConnectMQ encaminha as user properties do MQTT 5 sem alterações entre publicadores e assinantes, como qualquer broker compatível com o padrão. Lembre-se de que elas contam para o tamanho da mensagem: 256 KB no plano Serverless gratuito, 1 MB no plano Serverless pago e 64 KB no servidor MQTT público. Para ver seus metadados na prática, assine com o comando do Mosquitto acima ou com seu próprio client contra o seu broker, usando as credenciais do portal. Se ainda está escolhendo a infraestrutura, nossa visão geral de um broker MQTT gerenciado explica o que você recebe, e o tutorial de MQTT cobre os fundamentos.

Comece a usar o ConnectMQ

Cadastre-se em app.connectmq.com e crie um broker no plano Serverless gratuito, sem cartão de crédito. Conecte-se com MQTT 5, adicione um trace ID às suas mensagens e acompanhe-as do dispositivo ao dashboard no seu próprio broker MQTT na nuvem.

Perguntas frequentes

Os nomes das user properties podem se repetir?

Sim. O MQTT 5 permite o mesmo nome mais de uma vez, e o broker preserva a ordem. Armazene-as como lista se você depende disso.

O broker altera as user properties?

Em pacotes PUBLISH, o broker as encaminha sem alterações aos assinantes. Ele não as interpreta nem as filtra.

As user properties estão disponíveis no MQTT 3.1.1?

Não. Elas são um recurso do MQTT 5. Um assinante 3.1.1 recebe o payload sem nenhuma propriedade.

As user properties contam para o tamanho da mensagem?

Sim. Elas fazem parte do pacote, então contam para o tamanho máximo de pacote do broker.

Artigos relacionados

Por que Seu Cliente MQTT Fica Desconectando (e Como Corrigir)

Loops de reconexão estão entre os problemas mais comuns do MQTT. Conheça as cinco causas habituais, de client IDs duplicados a timeouts de keep alive e pacotes grandes demais, e siga um fluxo de diagnóstico que identifica a sua.

9 min de leitura

Quem Inventou o MQTT? A História dos Oleodutos à IoT

O MQTT foi inventado em 1999 por Andy Stanford-Clark, da IBM, e Arlen Nipper, da Arcom, para monitorar oleodutos via satélite. Acompanhe sua trajetória até o open source, a OASIS, a ISO e os brokers MQTT gerenciados na nuvem de hoje.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.