Creating devices and sub-devices with MQTT discovery

I have just started to play with HA because I want to automate some sensors and switches driven by a collection of micro-controllers on an RS485 network.

I want to have one or more RS485 master node use MQTT discovery to define the set of RS485 slave nodes on the network, and the switches sensors on each node. Reading through the MQTT Discovery documentation it seems like I should be able to create a hierarchy something like this:

rs485-master device:
  - rs485-slave sub-device
      - sensor
      - sensor
      - switch
  - rs485-slave sub-device

But for the life of me I can’t figure out have to do it. The developer documentation talks about devices and sub-devices that entities are a part of, as does the MQTT discovery documentation.

What am I missing? How do I define devices and sub-devices via MQTT?

1 Like

Where in Home Assistant’s documentation did you see the concept of sub-devices presented?

MQTT Discovery allows you to create entities belonging to a device.

The description of via_device:

Identifier of a device that routes messages between this device and Home Assistant. Examples of such devices are hubs, or parent devices of a sub-device. This is used to show device topology in Home Assistant.

Edit: Which also mentions another complete mystery. Where can I see the device topology in Home Assistant?

Here’s what MQTT Discovery supports for a device:

Supported abbreviations for device registry configuration:

‘cns’: ‘connections’,
‘ids’: ‘identifiers’,
‘name’: ‘name’,
‘mf’: ‘manufacturer’,
‘mdl’: ‘model’,
‘sw’: ‘sw_version’,
‘sa’: ‘suggested_area’,

It’s important to remember that the Developer documentation is intended for use by developers of integrations (written in python). However, not all of the concepts presented are accessible to other tools within Home Assistant (like MQTT Discovery, Jinja2, scripts, etc).

Do you mean that if I want to define my own device type for a master node on an RS485 network, and a sub-device type for a slave node on an RS485 network then I am going to have to create my own Integration?

If MQTT Discovery cannot be used to create the hierarchy you want then you will need to explore other options.

FWIW, it would be interesting to examine an existing integration that implements the device/sub-devices structure you want, but I can’t think of one. Not saying it doesn’t exist but there are a lot of integrations and I am not familiar with all of them.

I did have a quick scan through the core source code for home assistant and it looked like the device section of the config for MQTT Discovery was used to create new devices in the registry.

And that mixin is used in the MqttEntity class. The discovery_update method, calls device_info_discovery_update in the mixin which looks at the device part of the config and calls device_registry.async_get_or_create(**device_info). I have not spent enough time to fully trace through the code, but that was enough to make me think that devices should be created when they are described in the message from MQTT config topic.

1 Like

Just for fun, you could experiment with MQTT Discovery and supply it with the via_device option. Maybe it works and the documentation is not up to date.

That is what I have been trying :-).

Bed time. Will try a few more variations tomorrow after work.

OK - fiddling around again. I turned on debug logging in configuration.yaml:

  default: info
    homeassistant.components.mqtt: debug

I can see sensors and switches being created, but when I try to delete my entities only the sensors get deleted when I publish an empty config.

The creation looks like (I removed the device config for now):

2021-05-20 08:07:54 DEBUG (MainThread) [homeassistant.components.mqtt] Received message on homeassistant/switch/pi0-node0-valve0/config: b'{"name": "Valve 1", "state_topic": "homeassistant/switch/pi0-node0-valve0/state", "command_topic": "homeassistant/switch/pi0-node0-valve0/command", "availability": [{"topic": "homeassistant/switch/pi0-node0-valve0/available", "payload_not_available": "OFFLINE", "payload_available": "ONLINE"}], "unique_id": "pi0-node0-valve0", "icon": "mdi:water"}'
2021-05-20 08:07:54 DEBUG (MainThread) [homeassistant.components.mqtt.discovery] Process discovery payload {'name': 'Valve 1', 'state_topic': 'homeassistant/switch/pi0-node0-valve0/state', 'command_topic': 'homeassistant/switch/pi0-node0-valve0/command', 'availability': [{'topic': 'homeassistant/switch/pi0-node0-valve0/available', 'payload_not_available': 'OFFLINE', 'payload_available': 'ONLINE'}], 'unique_id': 'pi0-node0-valve0', 'icon': 'mdi:water', 'platform': 'mqtt'}
2021-05-20 08:07:54 INFO (MainThread) [homeassistant.components.mqtt.discovery] Found new component: switch pi0-node0-valve0
2021-05-20 08:07:54 INFO (SyncWorker_3) [homeassistant.loader] Loaded switch from homeassistant.components.switch
2021-05-20 08:07:54 INFO (MainThread) [homeassistant.setup] Setting up switch
2021-05-20 08:07:54 INFO (MainThread) [homeassistant.setup] Setup of domain switch took 0.0 seconds

Then when I send the empty messages to delete the entities I see this:

2021-05-20 08:08:12 DEBUG (MainThread) [homeassistant.components.mqtt] Received message on homeassistant/sensor/pi0-node0-valve0/config: b''
2021-05-20 08:08:12 DEBUG (MainThread) [homeassistant.components.mqtt.discovery] Process discovery payload {}
2021-05-20 08:08:12 DEBUG (MainThread) [homeassistant.components.mqtt] Received message on homeassistant/sensor/pi0-node0-flow0/config: b''
2021-05-20 08:08:12 DEBUG (MainThread) [homeassistant.components.mqtt.discovery] Process discovery payload {}
2021-05-20 08:08:12 INFO (MainThread) [homeassistant.components.mqtt.discovery] Component has already been discovered: sensor pi0-node0-flow0, sending update
2021-05-20 08:08:12 INFO (MainThread) [homeassistant.components.mqtt.mixins] Got update for entity with hash: ('sensor', 'pi0-node0-flow0') '{}'
2021-05-20 08:08:12 INFO (MainThread) [homeassistant.components.mqtt.mixins] Removing component: sensor.flow_1
2021-05-20 08:08:13 DEBUG (MainThread) [homeassistant.components.mqtt.discovery] Pending discovery for ('sensor', 'pi0-node0-flow0'): deque([])

Notice the distinct lack of activity for the valve (which is a switch). I can manually delete the entities in the user interface, and then sometimes I also need to restart the core before they disappear.

Why does this seem half baked?

Ahhh… I am so dumb, for real…

I have the wrong entity type for the topic used to delete the switch.

OK - I think I have more or less solved the problem well enough to move on to other things.

By giving all of the entities a common device config they are all grouped together under the Devices tab. I am not sure what I was doing wrong yesterday, but this works well enough:

{"name": "Valve 1",
 "state_topic": "homeassistant/switch/pi0-node0-valve0/state",
 "device": {"model": "Slave V1",
            "identifiers": "pi0-node0",
            "via_device": "pi0",
            "name": "Garden Bed 1",
            "manufacturer": "DICS"},
 "command_topic": "homeassistant/switch/pi0-node0-valve0/command",
 "availability": [{"topic": "homeassistant/switch/pi0-node0-valve0/available",
                   "payload_not_available": "OFFLINE",
                   "payload_available": "ONLINE"}],
 "unique_id": "pi0-node0-valve0",
 "icon": "mdi:water"}

So long as I make sure all of the entities on the same slave node have the same device config then the grouping works.


FWIW, that information is found throughout the forum (device with entities); here’s one example (see point #3):

What is not found is what you requested, namely devices with sub-devices (with entities). I don’t know if the Frontend is even capable of rendering that kind of hierarchy.

Obviously my google-fu is weak :-).

Once you know what to look for things become easier. I am very much a complete n00b.