ESPHome and MQTT Event Bus

Good day to all,

I am new here and have perhaps too general a question. I have read through the documentation accordingly, but have not quite figured out how I could proceed.

I actually don’t want to use Home Assistant either, but I think this is where the expertise on ESPHome is greatest. Instead of api, I will use mqtt accordingly. And ESPHome can be installed without Home Assistant (Docker or Python).

But now to my actual question: How do I realize a MQTT Event Bus with ESPHome?

As example I use a D1 Mini with WiFi module. The following is clear:

  name: ${name}
  platform: ESP8266
  board: d1_mini

  ssid: !secret wifi_ssid 
  password: !secret wifi_password

Then as already mentioned is clear that I do not use api, because I will not have a direct connection to Home Assistant.

The next point will be to use MQTT.

  broker: !ip_to_broker
  port: 1883
  username: !secret broker username
  password: !secret broker password
  client_id: ${name}
  discovery: true
    topic: ${name}/mqtt_status
    payload: online
    topic: ${name}/mqtt_status
    payload: offline

I think you could also leave out a little bit because of the default values. But this should work so far.

Now I’ll come up with an example of how I envision the whole thing:

State: A state is something that my device spits out to me. For a temperature sensor, for example, it would be the temperature in degrees Celsius. A state can also be a boolean value like ON or OFF, e.g. if a device is switched on (not my D1 Mini, but a device I want to make smart) or if a functionality is switched on. A state can also be if one of several modes is selected. Let’s assume there are 3 speeds, then the used mode should be published values. In this example we just imagine Slow, Normal and Fast.

This generally leads to, for example, the following topics:

${name}/temperature/state # a degree Celsius value
${name}/power/state # ON or OFF
${name}/random_functionality/state # ON or OFF
${name}/speed/state # Slow, Normal, Fast
${name}/rgb/red/state # the red value of RGB
${name}/rgb/green/state # the green value of RGB
${name}/rgb/blue/state # the blue value of RGB

I hope people understand what I mean by that.


A command is something I want to send to my device. For example, I send the value ON to a topic to turn on a device. Or a value OFF to switch off a functionality. Or one of the possible modes to change the mode.

This generally leads to, for example, the following topics:

${name}/power/command # ON or OFF
${name}/random_functionality/command # ON or OFF
${name}/speed/command # Slow, Normal, Fast
${name}/rgb/red/command # the red value of RGB
${name}/rgb/green/command # the green value of RGB
${name}/rgb/blue/command # the blue value of RGB

I have now taken out the temperature again here because I meant a temperature sensor as an example. You can’t change the temperature on this one. With a device where perhaps an operating temperature is meant, it would be conceivable that there would also be a command topic with which one changes this temperature.

I also made the assumption that you can change RGB values via Topics. This may be true for lamps, LEDs or projectors.

What you might have to consider in these examples is how you might want to process the data. So just using the example of RGB, you could say that related data is sent over one topic and not over several individually. Then you don’t send three color values but a tuple of color values.


A device publishes its states when the status changes. A temperature sensor changes the status of the measured temperature constantly without external intervention. Some devices also change their status automatically after a certain time. For example, a room air cleaner that automatically changes from Fast to Normal after a certain time because it recognizes that it does not have to run at full speed. This mode can also be changed manually. And then there are devices where there are really only status changes when a user has changed something. In my opinion, you have to divide this into the following three categories:

  1. Device changes status by itself
  2. Device changes status automatically or manually
  3. Device changes status manually only

We will pay more attention to the manual changing of a status. In the future, a status change can and should also be made via an MQTT command topic. It can also be triggered by a remote control of the device (also Android apps or web apps, etc.) or by a button on the device, etc.

One point not yet fully mentioned is that states and commands do not necessarily have to have the same kind of values. I can’t think of a good example of this. I’m honestly at a loss at this point. But let’s take again the example with the modes Slow, Normal and Fast. It would be conceivable that I have three speeds as states, such as 0, 1 or 2. Or 0, 10 or 20, but still fixed values that cannot be set individually. So I send Command accordingly but Slow to set to 0 or Normal to set to 1 or 2 to set to Fast. And we can imagine this scenario the other way around as well. As States I would have only Slow, Normal and Fast and set them via my Command Topic with 0, 1 or 2.

Back to ESPHome. So now let’s leave the theory and come back to the practice a little…

From the documentation:

topic_prefix (Optional, string): The prefix used for all MQTT messages. Should not contain trailing slash. Defaults to <APP_NAME>.

It would be a value that I would not have to put. But does this mean that automatically if I compile my code correctly my “states” will be published? So that to my code above I would only need to add the sensor functionality, but the MQTT configuration already done is sufficient?

Or do I need something like on_value? So that it is clear, if a value changes, then it should be published. I wouldn’t be me if I didn’t have an example for this:

  - platform: esp8266_pwm
    id: red
    pin: D1
      - mqtt.publish:
          topic: "${name}/rgb/red/state"
          payload: !lambda |-
          return to_string(id(red).state);
  - platform: esp8266_pwm
    id: green
    pin: D5
      - mqtt.publish:
          topic: "${name}/rgb/green/state"
          payload: !lambda |-
          return to_string(id(green).state);
  - platform: esp8266_pwm
    id: blue
    pin: D6
      - mqtt.publish:
          topic: "${name}/rgb/blue/state"
          payload: !lambda |-
          return to_string(id(blue).state);

I hope you understand this pseudo code and the reasoning behind it.

Now of course the question arises, if I had something like modes, how I could still publish which of those has been chosen.

Now let’s move from publishing to subscribing. The states are published and the commands are subscribed. I didn’t mention this explicitly until now, but if you follow me, you’ve already noticed this anyway.

I also quote from the documentary:

on_message (Optional, Automation): An action to be performed when a message on a specific MQTT topic is received. See on_message Trigger).

As I understand it I use on_message to subscribe. Published could seemingly be automatic only subscribing is optional. So if I want to enable something like Commands, I would have to use on_message.

Can I use then to perform my function? So I take a value and then for my function change this value. Because of me I have a RGB color value change. How could I realize this?

And then of course another question. How do I actually receive what I have subscribed to on my topic with on_message? I ask this for two reasons:

  1. I may want to preprocess data. (For example formatting or transforming.)
  2. When setting different modes, I might want to perform a different function for a different mode.

I quote again from the documentation:

With this configuration option you can write complex automations whenever an MQTT message on a specific topic is received. To use the message content, use a lambda template, the message payload is available under the name x inside that lambda.

The given code example is following:

  # ...
    topic: my/custom/topic
    qos: 0
      - switch.turn_on: some_switch

How do I get the value from my topic and how do I pass this to my function? For example, would switch.turn_on be the function and some_switch what should be subscribed? I mean normally I would expect some unknown value. Here, after the subscription, a function is simply called without going into the received value, right? So the main thing is that the topic is subscribed, then I have to execute a function. So I don’t set any parameters for the function.

I quote again from the documentary:

payload (Optional, string): Optionally set a payload to match. Only if exactly the payload you specify with this option is received, the automation will be executed.

So, for example, could I resolve that with the different modes?

  # ...
    - topic: ${name}/speed/command
      qos: 0
      payload: "Slow"
        - # a good question how to run a different function
    - topic: ${name}/speed/command
      qos: 0
      payload: "Normal"
        - # a good question how to run a different function
    - topic: ${name}/speed/command
      qos: 0
      payload: "Fast"
        - # a good question how to run a different function

So that I use the topic several times and then use payload to check what is being subscribed to.

Times still additionally asked to discovery. Here, too, I quote briefly from the documentation:

discovery (Optional, boolean): If Home Assistant automatic discovery should be enabled. Defaults to true.

Does this really only refer to Home Assistant? Other smart home systems often also have automatic discovery. I mean, allowing this to be true certainly doesn’t provide a disadvantage, because then the device would end up being more universally applicable. For Home Assistant, this can then also be integrated via MQTT instead of directly via the API. But just other smart home systems could integrate the device via MQTT or you use programs that access this device directly via MQTT, etc. Can also be a robot in the end, which communicates via e.g. a Paho MQTT client with the created device.

Thank you in advance. I think it is quite a general and understandable concept. After all, it is also usually used in the smart home sector.

Kind regards,

Not sure what you are really asking. If you enable mqtt on esphome, states are published to mqtt and commands are accepted on mqtt, you don’t have to manually publish or subscribe. You can pub and sub custom stuff, if you have a need/wish to.

As far as discovery is concerned, it refers specifically to home assistant mqtt discovery, as documented here MQTT Discovery - Home Assistant You are of course free to implement that on another system, just as you are free to implement the api. Another home automation system already has.