MQTT Home Assistant Discovery

In previous notes we have explored how to integrate an IoT device (ESP8266) with an MQTT broker. The next step on this journey is to actually make such a device controllable from Home Assistant via the MQTT connection.

The work in this note will be based on the Home Assistant MQTT integration documentation.

Rough Plan Of Action

There are three ways that devices can be “added” to the MQTT integration

Only the first option would be relatively “automatic” or “plug and play”, in the sense that one could point the device at the MQTT broker and (presumably) have it automatically “appear” in Home Assistant. The latter two options it appears would require either manually setting the configuration YAML in Home Assistant or manually entering some stuff in the UI. Additionally the “discovery” approach is taken by the Tasmota integration which is what I’m used to and I find works pretty well.

Hence we’ll try and set up a device here by MQTT discovery.

From the linked documentation page, these are the rough steps.

Step 1 - we’ll need to send discovery messages on a specific discovery topic

Step 2 - work out the right format for the discovery message

Step 3 - we’ll need to do that at the right time

There appear to be two options to send the discovery messages at the right time, which are following “birth” and “will” messages from Home Assistant, or publishing those discovery messages with the “retained” flag. Because we have explored subscribing to topics already in the previous notes and because there seem to be more disadvantages to the latter approach, in this note we’ll take the former approach.

Hence

Step 3a - we’ll need to send a discovery message when the device connects to the MQTT broker

Step 3b - we’ll need to send a discovery message when Home Assistant sends a “birth” message (announces that it’s online)

Sending Discovery Messages On The Right Topic

The discovery topic format is documented here https://www.home-assistant.io/integrations/mqtt/#discovery-topic as <discovery_prefix>/<component>/[<node_id>/]<object_id>/config.

<discovery_prefix> is a configuration item in the MQTT integration in Home Assistant, which defaults to homeassistant. I have not changed this in my Home Assistant, hence that’s the right value to use.

For <component> we’ll use device since we’ll be using the “newer” device discovery rather than component discovery.

Per the documentation, since we will assign our devices a unique_id, we can omit the <node_id> level.

Per the documentation, since we will assign our devices a unique_id, the <object_id> will be set to that unique_id.

So for the case where the unique_id is e.g. e1e080f341364ceeb6038a050ed7dd60 the discovery topic would be homeassistant/device/e1e080f341364ceeb6038a050ed7dd60/config.

NEXT: code to connect to and publish to discovery topic

Find The Right Format For Discovery Messages

This is the major unknown in this note, everything else is frankly pretty easy to figure out with the code given in previous notes.

Unfortunately, the documentation is not (at least in my opinion) particularly well organised, so here’s what I’m able to piece together.

The discovery payload is, unsurprisingly, a JSON.

For device discovery, the JSON has the following top level keys

device and origin, maps**, are required.

command_topic, string, should be given for a device which accepts commands, such as a switch or a light.

state_topic, string, should be given for a device which can publish states to Home Assistant such as a switch (on/off) or a sensor.

qos, integer, optional, I assume it sets the quality of service for messages sent to the device? This is apparently not documented on the page.

encoding, string, optional, appears to tell Home Assistant the string encoding expected in messages from and to the device, which defaults to UTF-8. UTF-8 “covers” the entire range of ASCII encoding, outside of which our device will not step, so we can ignore this key completed.

components is a map, with a key per “component” in the device, each with an map value. A component is an independent “part” in a device - for example a single switch might just have one switch component, a temperature and humidity sensor might have two components i.e. two sensors with different units of measurement,

* where abbreviated keys are supported, I’ll give full_key / abbreviated_key

** JSON objects, but I’ll call them maps because that comes more naturally to me

device

To find the full documentation for the device map I had to dive into the YAML configuration documentation for the specific MQTT integrations, for example buttons or switches.

I’m pretty sure the device entry is the same for all of the different integrations, but I don’t feel like comparing all 20 or however many there are…

Everything in this map is apparently optional, which is a bit surprising considering the device key is required in the device discovery payload?

So, I’m just going to start with whatever is suggested in the example discovery payloads, under the assumption that nothing here (except probably the ids) is that important for our non-commercial device anyway. These fields are

For identifiers we’ll just use the unique id for the device, which we’ll take as a UUID. We’ll use that as serial_number too.

For name we worked in previous notes on a switch, so let’s call it “Test Switch”.

For sw_version and hw_version I’m sure a real project would follow some well defined versioning scheme such as semver. For simple learning projects like this, I prefer a simpler approach, so we’ll just use an integer number, setting these both to (string) “1”.

Assuming UUID c1d9bca9ddfc4803be31d7920d57f91e then would give us a device map

{
    "hw_version": "1",
    "identifiers": "c1d9bca9ddfc4803be31d7920d57f91e",
    "name": "Test Switch",
    "serial_number": "c1d9bca9ddfc4803be31d7920d57f91e",
    "sw_version": "1"
 }

origin

The purpose of this field it seems is only to add context to the logs generated by Home Assistant relating to updates to the device, but it’s required for the device discovery payload, so add it we must. There are three keys

Only name is required so that’s all we’ll give, and we’ll make it match the device name, Test Switch.

Hence our origin payload will be super simple

{
    "name": "Test Switch"
}

command_topic and state_topic

These fields tell Home Assistant where it should publish commands to be consumed by the device and on which topic the device will publish updates about its state.

Luckily we have chosen a switch example to work on, which means we will need to set both.

Obviously these need to be unique so multiple devices don’t interfere with one another.

We could go super simple here, something like

However I would generally go with something a bit more structured and that provides a bit more context - remember in the previous note we saw the Tasmota topics like stat/tasmota_DEVICE_SHORT_ID/RESULT and cmnd/tasmota_DEVICE_SHORT_ID/Power1.

We might want to include the application name or the manufacturer name (if we had one) or the model name, but since we only have a device name for now, let’s use that to “namespace” our topics.

TODO: components

Send A Discovery Message When The Device Connects

TODO

Send A Discovery Message When Home Assistant Sends Online Message

TODO