Not quite understanding the benefits of MQTT Discovery for custom devices

I’ve been spending more hours than I care to admit working on a custom mqtt device (an R2D2 sphero toy). It’s been going well so far, but I’m confused on something.

I setup a handful of sensors through mqtt discovery with the /config topic and corresponding payload. I end up with an mqtt device page that shows all my sensors. This is nice and expected behavior.

Device Page

MQTT Discovery holoprojector config payload
homeassistant/sensor/r2d2/holoprojector/config

 {
    "availability_topic": "homeassistant/sensor/r2d2/availability",
    "icon": "mdi:led-on",
    "unique_id": "d1c1af96a0e956c89f1625533620be82",
    "device": {
        "identifiers": "r2d2",
        "manufacturer": "Sphero",
        "model": "R201",
        "name": "R2D2",
        "sw_version": "2022.09.29"
    },
    "name": "R2D2 Holoprojector LED",
    "expire_after": 5,
    "state_topic": "homeassistant/sensor/r2d2/holoprojector/state",
    "platform": "mqtt"
}

Now, what I am confused about is when I want to make a control to set the state of one of his lights, legs, or dome, I have to setup custom mqtt devices in my configuration.yaml file. So, what I’m left with in my python library is something like the following. Let’s take his holoprojector led for example (simple on/off and 0-255 no rgb)

  • 1 topic to report the state (on/off)
  • 1 topic to report the value (0-255)
  • 1 topic to receive the state from the UI (on/off)
  • 1 topic to receive the value from the UI (0-255)

That’s 4 topics for just a simple led. First question, is this correct?

Second question, is in my configuration.yaml file I have the following custom light entry for him:

- name: "R2D2 Holoprojector"
    unique_id: "r2d2_df12b4032fe411e4800bcd1fd09bffdc"
    state_topic: "homeassistant/switch/r2d2/holoprojector/state"
    command_topic: "homeassistant/switch/r2d2/holoprojector/switch"
    brightness_state_topic: "homeassistant/switch/r2d2/holoprojector/brightness"
    brightness_command_topic: "homeassistant/switch/r2d2/holoprojector/brightness/set"
    on_command_type: "brightness"
    optimistic: false
    retain: false
    brightness_scale: 255
    payload_on: "ON"
    payload_off: "OFF"

Is this not achievable with just the mqtt discovery or do I need both the configuration.yaml entry and the discovery topic?

Just wanted to double-check if anyone had any thoughts on this.

You don’t need the configuration.yaml entry if you created a discovery topic for it.Auto-discovered mqtt topic load faster, and can create devices, manual mqtt entries can’t create devices.

Thanks for the input, but if I don’t create it in the yaml the light doesn’t show up in the entities. Is there a special way to format the light config topic that I’m missing?

You just need to pack everything you wrote in the manual entry into the discovery message.

1 Like

I will give that a try, thank you. Quick question for you though, what’s the purpose of the availability_topic and what is it expecting? Currently I’m giving it a literal “online” string value.

I don’t use it on most of my mqtt topics, unless it are energy measuring devices. It is to check if the device is online or not, and for energy devices to prevent dips in the energy dashboard.

Ah. So it’s not necessarily needed and it’s expecting “online/offline” payloads?

You don’t actually need one topic for each of these if you don’t want. Take a look at how zigbee2mqtt does it for example. Instead of one topic for the state and each of the attributes, just pass JSON with everything to one topic. So if you send JSON like this to homeassistant/switch/r2d2/holoprojector:

{
  "state": "on",
  "value": 128,
}

then you can use this as the discovery info:

{
    "availability_topic": "homeassistant/sensor/r2d2/availability",
    "icon": "mdi:led-on",
    "unique_id": "d1c1af96a0e956c89f1625533620be82",
    "device": {
        "identifiers": "r2d2",
        "manufacturer": "Sphero",
        "model": "R201",
        "name": "R2D2",
        "sw_version": "2022.09.29"
    },
    "name": "R2D2 Holoprojector LED",
    "expire_after": 5,
    "state_topic": "homeassistant/sensor/r2d2/holoprojector",
    "value_template": "{{ value_json.state }}",
    "platform": "mqtt"
}

Repeat for value and any other attributes you want to set.

You can do the same thing for commands if you wish. Instead of having one topic per command use the same topic for all commands and use the corresponding *_template option in discovery to have HA craft a different message per command so you can differentiate.

Both approaches work, just depends which option you prefer.

1 Like

If you don’t set availability or availability_topic the entity is simply assumed to be always available. So yes, its optional.

By default. You can change these to anything you want by setting payload_available and payload_not_available. You can also use availability_template (or availability.value_template if using the newer option) to tell HA how to process the payload before comparing it to payload_available and payload_not_available.

1 Like

Thank you! I noticed in your state_topic you dropped the last part of the path “/state” from the topic but included it in the value_template. If I’m sending an int value in the json wouldn’t the value_template need to be "{{ value_json.value }}" ? So, like this:

{
    "state": "on",
    "value": 128
}
...
    "state_topic": "homeassistant/sensor/r2d2/holoprojector/state",
    "value_template": "{{ value_json.value }}"
...

These two changes weren’t really related? I assumed if you were passing all the state information to one topic then you would drop /state from the path. But that’s not required, totally up to you what topic you want to use.

I included it in value_template because when value_template is executed if the payload is json it is parsed into a python dictionary that can be accessed by using value_json. And then you can access the state field of that dictionary by doing value_json.state. This is all related to the payload though, it has nothing to do with the topic.

Correct. Although I kind of forgot this was a light so value is brightness, its not an attribute. So I think what you’d actually want is this:

...
    "state_topic": "homeassistant/sensor/r2d2/holoprojector", # or add /state on the end, whatever you want
    "brightness_state_topic": "homeassistant/sensor/r2d2/holoprojector", # or add /state on the end, whatever you want
    "state_value_template": "{{ value_json.state }}",
    "brightness_value_template": "{{ value_json.value }}",
...

There we go! That cleared it up. I get the path is arbitrary, but in the example nothing was looking at .state
and .value. Thanks!

1 Like

Yea my bad. I was thinking generic mqtt entity with attributes and wasn’t really thinking about a light. Similar patterns apply but different options in that case.

1 Like

@CentralCommand, when I tried it this way, it registers as a sensor and not a light and it’s unavailable. Where did I go wrong?

homeassistant/r2d2/holoprojector/config
{
    "availability_topic": "homeassistant/r2d2/availability",
    "icon": "mdi:led-on",
    "unique_id": "2f2da0794781efb83a983518340e0e6b",
    "device": {
        "identifiers": "r2d2",
        "manufacturer": "Sphero",
        "model": "R201",
        "name": "R2D2",
        "sw_version": "2022.09.29"
    },
    "name": "R2D2 Holoprojector LED",
    "expire_after": 5,
    "state_topic": "homeassistant/r2d2/holoprojector/state",
    "command_topic": "homeassistant/r2d2/holoprojector/switch",
    "brightness_state_topic": "homeassistant/r2d2/holoprojector/brightness",
    "brightness_command_topic": "homeassistant/r2d2/holoprojector/brightness/set",
    "on_command_type": "brightness",
    "optimistic": false,
    "retain": true,
    "brightness_scale": 255,
    "payload_on": "ON",
    "payload_off": "OFF",
    "platform": "mqtt"
}

Oh wait. Your topics are strange.

So from here discovery topics look like this:

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

discovery_prefix is almost always homeassistant but it can be changed. component is the type of thing you’re making. That seems to be missing from your discovery topic as r2d2 isn’t a type of component. So you should change it to this:

homeassistant/light/r2d2/holoprojector/config

Also if this is an addon or custom component you should be prepared to handle discovery_prefix being something other then homeassistant. If it’s just for your own use that doesn’t matter.

All your other topics (state_topic, command_topic, etc.) should not start with homeasssistant (i.e. the discovery prefix). I mean they can but that’s likely to cause more harm then good. Since HA will be looking at each message to see if it should be discovering a new entity and may accidently make entities.

I would recommend carving off another topic space for the actual state of things. Like maybe have all topics around the state and command of your devices start with r2d2. r2d2/holoprojector/state, r2d2/holoprojector/switch, etc.

so, if I’m understanding you correctly, my config topics should not include “homeassistant/”? So basically this?

{
    "availability_topic": "r2d2/availability",
    ...
    "state_topic": "light/r2d2/holoprojector/state",
    "command_topic": "light/r2d2/holoprojector/switch",
    "brightness_state_topic": "light/r2d2/holoprojector/brightness",
    "brightness_command_topic": "light/r2d2/holoprojector/brightness/set",
    ...
}

I’m only asking because I didn’t remove the homeassistant bit yet, but I did update my topics to include the component again (don’t know why I originally took that out) and now it seems I’m 1 step closer to getting it, but just not quite there yet.

I now see two entities (1 light, 1 sensor) both for the holoprojector led, but it’s still “unavailable”.

That looks fine. You don’t have to prefix all those topics with light for reference but are more then welcome to if you want to. For topics for my devices I personally use this pattern:

<service name (ex. zigbee2mqtt, amr2mqtt, blueiris, etc.)>/<device_name>[/<aspects of device (ex. set, motion/person, motion/animal, etc.)>]

But that’s just me, use whatever pattern works best for you.

The discovery topic has a strict format as I posted above. You didn’t share what you’re using now but hopefully its something like this?

homeassistant/light/r2d2/holoprojector/config

Okay. I must still be missing something. I’m just not getting anything other that “unavailable” from this thing and when I adjust the brightness, it doesn’t send mqtt commands. I confirmed this by opening a console window and subscribed to the brightness_command_topic using mosquitto_sub.exe

So you’re getting all the right entities but they are unavailable? Are you sending online to the availability topic? Also are setting retain to true when you send that message? Otherwise it will be unavailable every time HA restarts or reloads Mqtt entities until you send it again.