Automação IoT

Home Assistant MQTT Discovery: Crie Entidades Automaticamente para Dispositivos Próprios

Publique payloads de configuração de discovery para que seus próprios sensores e interruptores apareçam no Home Assistant como um dispositivo completo, com disponibilidade, IDs únicos e remoção limpa, usando um simulador de dispositivo em Python.

Dispositivo sensor personalizado aparecendo automaticamente em um dashboard de casa inteligente por meio do home assistant mqtt discovery
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

O MQTT discovery do Home Assistant permite que um dispositivo se descreva para que o Home Assistant crie suas entidades automaticamente, sem nenhum YAML do lado do Home Assistant. Neste tutorial você vai aprender o formato do tópico de discovery, escrever payloads de configuração para sensores e um interruptor, agrupá-los em um único dispositivo, lidar com disponibilidade e reinicializações do Home Assistant e remover entidades de forma limpa, tudo com um simulador de dispositivo em Python conectado a um broker ConnectMQ.

Como o MQTT Discovery Funciona

Quando a integração MQTT inicia, ela assina tópicos sob um prefixo de discovery, que por padrão é homeassistant. Um dispositivo publica uma mensagem JSON retida por entidade em um tópico de configuração:

<discovery_prefix>/<component>/[<node_id>/]<object_id>/config

homeassistant/sensor/hvac-node-1/temperature/config
homeassistant/switch/hvac-node-1/relay/config
  • component é a plataforma da entidade: sensor, binary_sensor, switch, light, button, number, select, climate e outras.
  • node_id é opcional e apenas agrupa tópicos; ele não cria o dispositivo.
  • object_id identifica a entidade dentro do nó.

O payload de configuração diz ao Home Assistant onde ler o estado, para onde enviar comandos, como interpretar os valores e a qual dispositivo a entidade pertence. Como a mensagem é retida, o broker a reenvia sempre que o Home Assistant se reconecta, e assim as entidades reaparecem após uma reinicialização.

O discovery é apenas metadado. Os dados reais continuam trafegando nos seus próprios tópicos de estado e de comando, que você projeta como em qualquer integração MQTT do Home Assistant.

Pré-requisitos

  • Home Assistant com a integração MQTT configurada e o discovery habilitado (ele vem ativado por padrão).
  • Um broker ConnectMQ privado: crie um no portal e anote o usuário, a senha e o client ID gerados. O Home Assistant e o simulador precisam, cada um, de suas próprias credenciais.
  • Python 3.10+ com pip install "paho-mqtt>=2.0".

Você também pode experimentar no servidor MQTT público (gratuito), mas duas coisas o tornam inconveniente para discovery. Primeiro, os tópicos de configuração retidos sob o prefixo compartilhado homeassistant ficam visíveis para todas as instâncias do Home Assistant conectadas ali, então defina um prefixo de discovery personalizado nas opções da integração (por exemplo cmqx7d2). Segundo, o broker público permite 10 assinaturas por cliente, e o Home Assistant precisa de várias para o discovery mais uma por entidade. Um broker privado evita os dois problemas.

Um Payload de Discovery, Campo a Campo

Esta é a configuração de um sensor de temperatura:

{
  "name": "Supply Air Temperature",
  "unique_id": "hvacnode1_supply_temp",
  "object_id": "hvac_node_1_supply_temp",
  "state_topic": "home/hvac-node-1/state",
  "value_template": "{{ value_json.supply_c }}",
  "unit_of_measurement": "°C",
  "device_class": "temperature",
  "state_class": "measurement",
  "availability_topic": "home/hvac-node-1/availability",
  "device": {
    "identifiers": ["hvacnode1"],
    "name": "HVAC Node 1",
    "manufacturer": "DIY",
    "model": "ESP32 duct sensor",
    "sw_version": "1.3.0"
  }
}
Campo Por que importa
unique_id Obrigatório para o registro de entidades: renomear, áreas, desativar. Deve ser estável para sempre.
device.identifiers Agrupa todas as entidades com o mesmo identificador em um único card de dispositivo.
state_topic + value_template Várias entidades podem ler campos diferentes de uma mesma mensagem de estado JSON.
availability_topic As entidades ficam indisponíveis quando o dispositivo publica offline (normalmente via last will).
device_class, state_class Ícones, unidades e estatísticas de longo prazo corretos.
object_id Influencia o ID de entidade gerado.

Payloads longos podem usar as abreviações documentadas, por exemplo stat_t para state_topic, uniq_id para unique_id e dev para device. Elas são úteis em microcontroladores com buffers pequenos; em um PC, os nomes completos são mais fáceis de ler.

Um Dispositivo Python Completo com Discovery

O simulador abaixo se comporta como um dispositivo real: anuncia três entidades, publica o estado em JSON a cada dez segundos, obedece a comandos do interruptor, define um last will para a disponibilidade e republica sua configuração quando o Home Assistant volta a ficar online.

import json
import random
import time

import paho.mqtt.client as mqtt

BROKER, PORT = "broker.connectmq.com", 8883
USERNAME, PASSWORD = "YOUR_USERNAME", "YOUR_PASSWORD"
CLIENT_ID = "YOUR_CLIENT_ID"

DISCOVERY_PREFIX = "homeassistant"
NODE = "hvac-node-1"
BASE = f"home/{NODE}"
STATE_T = f"{BASE}/state"
AVAIL_T = f"{BASE}/availability"
RELAY_CMD_T = f"{BASE}/relay/set"
RELAY_STATE_T = f"{BASE}/relay/state"

DEVICE = {
    "identifiers": ["hvacnode1"],
    "name": "HVAC Node 1",
    "manufacturer": "DIY",
    "model": "ESP32 duct sensor",
    "sw_version": "1.3.0",
}

ENTITIES = [
    ("sensor", "supply_temp", {
        "name": "Supply Air Temperature",
        "state_topic": STATE_T,
        "value_template": "{{ value_json.supply_c }}",
        "unit_of_measurement": "°C",
        "device_class": "temperature",
        "state_class": "measurement",
    }),
    ("sensor", "filter_dp", {
        "name": "Filter Pressure Drop",
        "state_topic": STATE_T,
        "value_template": "{{ value_json.filter_dp_pa }}",
        "unit_of_measurement": "Pa",
        "device_class": "pressure",
        "state_class": "measurement",
    }),
    ("switch", "relay", {
        "name": "Fan Relay",
        "command_topic": RELAY_CMD_T,
        "state_topic": RELAY_STATE_T,
        "payload_on": "ON",
        "payload_off": "OFF",
    }),
]

relay_on = False


def publish_discovery(client):
    for component, object_id, cfg in ENTITIES:
        payload = {
            **cfg,
            "unique_id": f"hvacnode1_{object_id}",
            "availability_topic": AVAIL_T,
            "device": DEVICE,
        }
        topic = f"{DISCOVERY_PREFIX}/{component}/{NODE}/{object_id}/config"
        client.publish(topic, json.dumps(payload), qos=1, retain=True)
    client.publish(AVAIL_T, "online", qos=1, retain=True)
    client.publish(RELAY_STATE_T, "ON" if relay_on else "OFF", qos=1, retain=True)


def on_connect(client, userdata, flags, reason_code, properties):
    print("connected:", reason_code)
    client.subscribe(RELAY_CMD_T, qos=1)
    client.subscribe("homeassistant/status", qos=1)   # mensagem de nascimento do Home Assistant
    publish_discovery(client)


def on_message(client, userdata, msg):
    global relay_on
    if msg.topic == "homeassistant/status" and msg.payload == b"online":
        time.sleep(random.uniform(0.5, 2.0))          # distribui a carga após reinícios do HA
        publish_discovery(client)
    elif msg.topic == RELAY_CMD_T:
        relay_on = msg.payload == b"ON"
        client.publish(RELAY_STATE_T, "ON" if relay_on else "OFF", qos=1, retain=True)


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.username_pw_set(USERNAME, PASSWORD)
client.tls_set()
client.will_set(AVAIL_T, "offline", qos=1, retain=True)
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, PORT, keepalive=30)
client.loop_start()

while True:
    state = {"supply_c": round(random.uniform(12.5, 14.5), 1),
             "filter_dp_pa": random.randint(150, 190)}
    client.publish(STATE_T, json.dumps(state), qos=0)
    time.sleep(10)

Execute o script e abra Settings > Devices & services > MQTT. Aparece um dispositivo chamado HVAC Node 1 com dois sensores e um interruptor. Pare o script com Ctrl+C e, dentro da janela de keep-alive, o broker publica o last will e as entidades ficam indisponíveis.

O tratamento da mensagem de nascimento (birth message) é importante. O Home Assistant publica online em homeassistant/status quando inicia. As configurações retidas normalmente tornam a republicação desnecessária, mas um dispositivo que republica ao receber o birth também se recupera caso as mensagens retidas tenham sido apagadas.

Discovery por Dispositivo

Versões recentes do Home Assistant também aceitam uma única mensagem de configuração por dispositivo em <prefix>/device/<object_id>/config, listando todas as entidades sob a chave components (abreviada cmps), cada uma com uma platform (p). Ela também exige um bloco origin (o) que nomeia o software que a publica:

{
  "dev": {"ids": ["hvacnode1"], "name": "HVAC Node 1", "mf": "DIY", "mdl": "ESP32 duct sensor"},
  "o": {"name": "hvac-node-firmware", "sw": "1.3.0"},
  "avty_t": "home/hvac-node-1/availability",
  "stat_t": "home/hvac-node-1/state",
  "cmps": {
    "supply_temp": {"p": "sensor", "dev_cla": "temperature", "unit_of_meas": "°C",
                    "val_tpl": "{{ value_json.supply_c }}", "uniq_id": "hvacnode1_supply_temp"},
    "filter_dp":   {"p": "sensor", "dev_cla": "pressure", "unit_of_meas": "Pa",
                    "val_tpl": "{{ value_json.filter_dp_pa }}", "uniq_id": "hvacnode1_filter_dp"}
  }
}

Uma mensagem retida em vez de muitas é atraente para dispositivos com dezenas de entidades. Use um único estilo por dispositivo; não anuncie os mesmos IDs únicos pelos dois caminhos.

Removendo e Alterando Entidades

Para excluir uma entidade, publique um payload vazio e retido no tópico de configuração dela:

mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
  -u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_CLIENT_ID -r -n \
  -t "homeassistant/sensor/hvac-node-1/filter_dp/config"

-n envia uma mensagem de comprimento zero e -r a torna retida, o que também apaga a configuração armazenada no broker. Para alterar uma entidade, publique a nova configuração no mesmo tópico com o mesmo unique_id. Alterar o unique_id cria uma entidade nova e deixa a antiga órfã.

Checklist de Solução de Problemas

  1. Nada aparece. Confirme se o prefixo de discovery nas opções da integração é o mesmo que o seu dispositivo usa e se o discovery está habilitado.
  2. As entidades aparecem, mas indisponíveis. O tópico de disponibilidade não tem uma mensagem online retida, ou o payload não é exatamente online.
  3. "Unique ID already exists" no log. Duas configurações compartilham o mesmo unique_id. Torne-os globalmente únicos, de preferência derivados de um endereço MAC.
  4. Dispositivos duplicados após uma atualização de firmware. O valor de device.identifiers mudou. Mantenha-o estável.
  5. Entidades fantasmas. Configurações retidas antigas continuam no broker. Use o explorador de tópicos da ConnectMQ para encontrá-las sob o prefixo de discovery e apague-as com mensagens retidas vazias.
  6. Configuração rejeitada silenciosamente. Valide seu JSON; uma vírgula sobrando em um payload escrito à mão é a culpada mais comum, e o Home Assistant registra o erro na integração MQTT.

Discovery a partir de um ESP32

Em um microcontrolador a lógica é idêntica: monte cada payload de configuração, publique-o como retido após cada conexão bem-sucedida e assine o tópico de nascimento. Três detalhes diferem do Python. Primeiro, o buffer de pacotes padrão do PubSubClient é pequeno, então chame mqtt.setBufferSize(1024) ou mais antes de conectar; caso contrário, payloads de discovery longos são descartados silenciosamente. Segundo, derive unique_id e device.identifiers do endereço MAC do chip para que cada placa receba valores estáveis e únicos sem configuração manual. Terceiro, publique a disponibilidade pelo last will em connect() para que o Home Assistant saiba de uma queda de energia sem que o dispositivo precise fazer nada.

Chaves abreviadas ajudam em dispositivos pequenos, e montar os payloads com ArduinoJson evita erros de aspas em strings escritas à mão. Teste os payloads do seu firmware assinando homeassistant/# com qualquer cliente MQTT e verificando se cada configuração é um JSON válido antes de procurar as entidades no Home Assistant.

Onde o Discovery se Encaixa

Firmwares como Tasmota, ESPHome em modo MQTT e Zigbee2MQTT já publicam payloads de discovery, e é por isso que seus dispositivos aparecem instantaneamente. Para o seu próprio firmware, o exemplo em Python acima se traduz diretamente para C++ com PubSubClient ou AsyncMqttClient; basta aumentar o tamanho do buffer do cliente, porque os payloads de configuração facilmente excedem o padrão. Quando os dispositivos ficam fora da sua rede doméstica, coloque todos em um único broker MQTT na nuvem, como descrito em como usar um broker MQTT externo com o Home Assistant. O guia de ESPHome MQTT e nosso guia de automação com IoT mostram mais dispositivos que dependem do discovery.

Crie Dispositivos Detectáveis na ConnectMQ

Crie um broker no plano Serverless (Free) em app.connectmq.com, sem cartão de crédito, e gere credenciais para o Home Assistant e para cada dispositivo. Com um broker MQTT gerenciado da ConnectMQ, as configurações de discovery retidas ficam em um broker que você nunca precisa atualizar, e o explorador de tópicos em tempo real mostra exatamente o que cada dispositivo anuncia.

Perguntas frequentes

As mensagens de discovery precisam ser retidas?

Deveriam. Configurações retidas permitem que o Home Assistant reconstrua as entidades após uma reinicialização sem que o dispositivo republique; republicar ao receber a mensagem de nascimento é um reforço útil.

Qual é a diferença entre node_id e o dispositivo?

node_id é apenas um nível de tópico para organização. O card do dispositivo é criado a partir do bloco device, e as entidades que compartilham os mesmos identifiers são agrupadas.

Como removo uma entidade descoberta?

Publique uma mensagem retida de comprimento zero no tópico de configuração dela. O Home Assistant exclui a entidade e o broker esquece a configuração retida.

Posso mudar o prefixo de discovery?

Sim, nas opções da integração MQTT. Todos os dispositivos precisam então publicar suas configurações sob o novo prefixo.

Artigos relacionados

Guia de Configuração do Zigbee2MQTT: do Coordenador ao Painel

Instale o Zigbee2MQTT com Docker, configure o coordenador e a conexão MQTT, pareie e renomeie dispositivos, controle-os via MQTT e veja seus estados em um painel, testando primeiro no servidor MQTT público (gratuito).

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.