Set and read state of boolean helper with mosquitto-clients

Hello list,

I created a helper (toggle) in HAOS (latest). The helper is called “test1”. When I read all messages using:

mosquitto_sub -h host -t '#'

I do not see anything drop by concerning “test1”. I added:

mqtt:
  binary_sensor:
   - name: "test1"
      state_topic: "homeassistant/binary_sensor/test1"
      device_class: "running"
      unique_id: "binary_sensor.test1_202601020940"

but this does not change anything, I must have missed something crucial somewhere. Anyone a hint?

Richard

An mqtt binary_sensor in HA reads the topic.

To publish from HA, use the mqtt.publish action

Well, it’s quite difficult to understand the docs if you’re not 100% familiar with the matter, like most open source docs BTW :wink:

But anyway, I found where I went wrong: I created a helper called test1 and I tried to make this helper read/writable through MQTT, but I should not do that, I threw away the helper and I created a new one in configuration.yaml:

mqtt:
  binary_sensor:
    - name: "test1"
      state_topic: "homeassistant/binary_sensor/test1"

That did the job :slight_smile:

Richard

Just another question: I am now able to read and write this boolean with mosquitto_[sp]ub, but it is impossible to toggle the boolean from within the HA web interface, I get a “history” page instead. Is it possible to toggle this boolean from the HA web interface?

R.

You defined a binary sensor. In the HA world that means a read-only entity that shows you the on/off state of something.

If you want an entity that can be toggled, you need to define a switch instead

Yep, that did the trick! I was already mucking about with the developer tools with which I was able to change the state of the entity. But the switch works and reports its state through mqtt. Thnx a lot!

[addendum]
Apparently the HA-switch sends out the mqtt message, but the other way round I am not able to switch on and off the switch using mosquitto_pub.

mqtt:                                              
  switch:                                        
    - name: "test1"                              
      command_topic: "homeassistant/switch/test1"
      unique_id: "test1_202601020940"
mosquitto_pub -h ha -t "homeassistant/switch/test1" -m "ON"

Am I doing something wrong somewhere?

I still have to go a long way with HA I fear…

Richard

You’ll need to define a state topic (in addition to the command topic). Without one, the switch works in “optimistic mode” and only changes state when commanded by HA. When you define a state topic, the switch’s state will be updated when commanded by HA and then also updated if that state topic changes.

Thnx, I already found this:

mqtt:                                 
  switch:                                          
    - name: "test0"                         
      state_topic: "home/switch/test0"      
      command_topic: "home/switch/test0/set"   
      unique_id: "test1_202601021900"

But now I stumble upon a possible bug:

When starting HA, the status of the switch is “Unknown”, even with “retain: true” and I’m not able to switch it on and off from HA.
However, I can switch it on and off using mosquitto_pub. Once that is done I can switch it on and off in HA.

Another weird thing:

When using mosquitto_pub, everything works as expected in both directions.

When using HA, I can toggle the switch (colour changes) and mqtt is reporting the new state. But the “On” and “Off” text and the message “X minutes ago” only changes when toggled by mosquitto_pub.

[addendum]

It does not seem to be stable either. Sometimes I need to toggle with the HA interface to make the mosquitto_pub work again. And vice versa.

Richard

I’d guess that the retain option only applies to the command and not the state. I don’t think HA will publish anything to the state topic; that should be performed by whatever is monitoring the actual switch’s physical state.

It might be helpful if you explain what you’re actually trying to do. What is the switch, and how does it communicate its state to MQTT?

Edit: if you’re just trying to create a virtual switch that can be controlled either by HA or via MQTT, then when you want to change the state reflected by HA you’d need to publish the new state to MQTT, and you can do that with a retain flag so that the switch’s state is known by HA after a restart. Probably what would make the most sense is to create a HA automation that will publish a new state whenever a command is published to the MQTT command topic. That automation essentially simulates what a real switch connected via MQTT would do.

I have a small program on an old RPi 3B+ with two physical buttons on two GPIO ports. That works. One is a pulse button and the other one an on/off switch.

I’m just eager to know if I can have copies of these buttons in HA like if they were in parallel with the physical ones :slight_smile:

For the moment I’m just playing with the on/off version. I can of course install a small webserver with php on the RPi and create a link in HA, but that’s a gateway of last resort.

R.

I had a chance to test this out, and it will work as I previously described:

To clarify, this is how an MQTT switch works:

  • HA will publish ON (or OFF) to the command topic when HA is commanding the switch ON (or OFF). For example, when the switch is toggled from the UI or when the switch is changed via an automation or script.
  • HA will not record a state change of the switch until the new state is published to the MQTT state topic. The publishing of the state is done by the switch , not by HA
  • When the switch is changed from the UI, the UI will show the switch changing position (and/or color or however the UI shows the new state) immediately even though an updated state hasn’t (yet) been published to the MQTT state topic. The UI has to behave this way otherwise the user experience would be terrible. You’d try to toggle the switch in the UI and nothing would happen. You wouldn’t know if the UI received the input (screen press or mouse click). And then some time later (whenever the MQTT state topic is updated) it would finally change visually. So, essentially, you’d have no indication that you attempted to toggle the switch, and you’d probably attempt to toggle it multiple times before it changed, and then it would start changing back and forth. So, the UI visually shows the switch changing states, even though HA has only issued the command but hasn’t yet seen a state change. If you refresh the browser you’ll find the switch visualization will revert back to its original position.

If you are just testing out a virtual switch and aren’t actually switching anything, publishing something to the command topic is pointless. HA doesn’t look at the command topic, and you don’t have a real switch (or RPi) to look at it and take action. So you’re publishing a command to a topic with no subscribers. If you just want to change whether HA shows the switch as ON or OFF you need to publish to the state topic.

To summarize:

  • A real switch that works over MQTT will take action when it sees a command published to the command topic, and it will also publish its new state to the state topic whenever its state changes.
  • If you are just playing around and don’t have a real switch, you need to (either yourself with mosquitto_pub or with an HA automation) publish a new state to the state topic in order for HA to register a state change.

Ok, thnx for your clear explanation! So the entity “test0” I see is just a read only device from the HA interface perspective. Thinking about this, it brings me to another point: instead of coupling the physical and the virtual switch like I tried before, I need to send an MQTT message to the RPi (ON or OFF) using a different MQTT subscription which emulates a button press. The RPi sends back its state to the MQTT switch in HA.
That way I’m sure that the physical switch is in the right position. If there is e.g. a network problem I have the possibility to notice it.

So, I need a helper that sends MQTT messages. In automations, there is an option to publish an MQTT message, but I don’t see how to send messages to another host, I think I need to call a shell script that uses mosquitto_pub, right?

Thnx for your time BTW!

Richard

The state is read-only, yes. That’s not unique to MQTT switches, that’s how every switch (Zigbee, WiFi, RPi, etc) works. The best HA can do is to ask any switch to turn on or off. If the switch is broken or is not responding, HA isn’t going to override the state with a new (incorrect) state.

No, that’s not necessary. That’s the purpose of the command topic. You can of course do as you suggest, but you’re just creating a unique workaround to a problem that has already been solved cleanly and is supported natively.

The MQTT protocol is equipped to handle unresponsive devices or clients that have disconnected unexpectedly. There is a “last will” message that can be set up by the client, and when the client unexpectedly disconnects, the broker will publish that message. That can be used in this case to make the switch appear “unavailable” in HA. So you’d set up the switch (your RPi) to connect to your broker with a last will message, and then you’d set an an availability topic in your HA MQTT switch configuration. When the RPi connects to the broker it would set the last will message and would then publish available to the availability topic. If the RPi unexpectedly disconnects, the broker will publish the Will Message, which would be set up to be unavailable published to the availability topic.

However, all this is not totally necessary. With the way you have it configured today, you can just look at the last_changed property of the switch to see if it responded to your command. Many dashboard cards can display that along with the switch, and will display the time in an easy-to-read relative time format. So when you toggle the switch and the RPi responds appropriately, the card will show something like “One Second Ago”. If it hasn’t responded it should say something like “Two Hours Ago”.

Even when not on a dashboard, just viewing the switch entity will show you this:

This is a zwave switch and it responds essentially instantly for me, so I see this as soon as I command it on:

If it wasn’t responding, it would have switched to ON but would still show “49 minutes ago”. And when you close and re-open the entity dialog (or just refresh it), it would revert back to the OFF state.

Again, keep in mind this behavior isn’t unique to what you are doing with your RPi and MQTT. This is how every switch in HA behaves.

Just a message to show I’m still busy with it, I try to understand how things work, but I think I still miss some crucial things somewhere. But I’m quite busy with other things at the moment, tomorrow there will be snow over here and I wlll have a closer look at it :slight_smile:

There is one thing I cannot get a finger behind, on https://www.home-assistant.io/integrations/switch.mqtt/ it says

We can simulate the switch being turned on by publishing the ON command message:

mosquitto_pub -h 127.0.0.1 -t home/bedroom/switch1/set -m "ON"

Finally, we can simulate the switch reporting back the changed state to Home Assistant:

mosquitto_pub -h 127.0.0.1 -t home/bedroom/switch1 -m "ON

The first does not do anything, the second does. What’s happening here? This is the config of my test0 switch:

mqtt:                                              
  switch:                                     
    - name: "test0"                           
      state_topic: "home/switch/test0"        
      command_topic: "home/switch/test0/set"  
      unique_id: "test1_202601021900"         
      availability:                           
        - topic: "home/switch/test0/available"
      retain: true

Thnx for your explanations and time!

R.

I think this is confusing for you because you don’t have a switch.

When the docs say

We can simulate the switch being turned on by publishing the ON command message:

They really mean:

We can simulate what would happen if you turned on the switch using Home Assistant by publishing the ON command message:

And that is why publishing that message does nothing: because you don’t have a physical switch. If you actually had a real switch, then publishing that command to MQTT would make the switch turn on. In the real world. Like, you would hear a click. And Home Assistant wouldn’t be involved whatsoever.

Pfff, the forest is hidden by a tree as they say in France :slight_smile: I fear I still don’t get the clue.

Virtual MQTT switch in HA ← network → the real switch on a RPi

If I toggle the real switch, it sends the ON or OFF message to the MQTT switch in HA, so the virtual switch will be in sync.

The other way round, I send an MQTT message to the virtual MQTT switch in HA (localhost), the real switch then toggles as well because it listens to a subscription.

But I think you do not agree with this solution :slight_smile:

Well, I need to send a mosquitto_pub message, but I have lost quite some time running shell scripts by an automation. Everything seems to be ok, but the scripts aren’t executed, even a simple

touch /tmp/test1

does not work. I restarted HA as noted in the docs. In configuration.yaml:

shell_command:
  test_on: touch /tmp/test1

In automations.yaml:

- id: '1767519223311'       
  alias: 11 - test0 state ON
  description: ''         
  triggers:               
  - trigger: state                               
    entity_id:            
    - input_button.h_test0       
    from:                        
    to:                          
  conditions: []                 
  actions:                       
  - action: shell_command.test_on
    metadata: {}               
    data: {}  
  mode: single

But no way. When I run the shell scripts in a terminal there is no problem.

R.

Below I’ve added bold underlined text to those statements:

If I toggle the real switch, it sends the ON or OFF status message to the MQTT switch in HA, so the virtual switch will be in sync.

The other way round, I send an MQTT command message from the virtual MQTT switch in HA (localhost), the real switch then toggles as well because it listens to a subscription. And then the real switch sends a status message to MQTT so that HA updates the status of its virtual switch, so that they remain in sync.

Maybe it is also helpful to clarify that with MQTT, you don’t get to choose who to send a message to. You merely post a message to a topic. Whoever (or whatever) is subscribed to that topic will be informed that the message was posted.

So when you send a MQTT message, you can either send it to the command topic or you can send it to the status topic. There is no ability to send a message “to the switch” or “to HA”. That’s not how it works.

With that in mind, the more correct explanation is:

If I toggle the real switch, it sends the ON or OFF status message to the MQTT status topic. Since HA is subscribed to that topic, it receives the message and updates the position of the virtual switch so it stays in sync.

The other way round, I send an MQTT command message to the MQTT command topic. The real switch then toggles as well because it listens to a subscription on the command topic. And then the real switch sends a status message to the MQTT status topic with its new state. Since HA is subscribed to the status topic, it is alerted of the new state and then HA updates the status of its virtual switch, so that they remain in sync.

I played a bit with a real Zigbee MQTT switch which reports its state each minute. I can see now what you tried to explain.

When I send ON to the state topic, I see the HA-button switch to ON, but the switch itself stays OFF and reports OFF each minute, which in turn makes the HA-button turn OFF again.

And indeed: When I send ON to the command_topic the switch switches ON, the switch immediately reports that its state is ON which turns ON the HA-switch.

When I send ON to the command_topic of the virtual switch, nothing happens. When I reread your previous comments, it is much clearer now. The virtual switch is not a switch, it is only capable to show a state. I should have started with a real switch, that would have been much simpler.

So, if I start an automation by clicking the virtual switch that sends ON to the RPi (which does not work yet, but that’s another issue) the RPi must send its new state to MQTT which toggles the virtual switch because it is subscribed to these messages.

I think I finally got the clue :slight_smile:

1 Like