MQTT Cover and/or binary sensor don't check actual state on HA startup

It might be cold comfort but my Garage Door’s config is effectively identical to yours but I don’t get ‘Unknown’ after a restart.

I suspect the difference is that the device I use that actually operates the garage door publishes the state topic with retain=true. Effectively, it’s telling the MQTT broker (mosquitto) to store the topic’s value and report it to any subscriber that connects to it later. “Later” as when Home Assistant reboots and re-subscribes to all MQTT topics, such as the garage door’s state. If that topic’s value is not retained by the MQTT broker, Home Assistant receives no value from the broker and reports it’s unknown. It’ll become known the next time the garage door changes state.

Effectively, “retain” is a form of persistence on the MQTT broker. Without it, the only subscribers who know what’s changing are the ones connected at the time of the change. Subscribers who arrive later, get no “meeting notes” and don’t know the current state of any topic.

This might be my problem. I had to disable the ‘retain’ setting because my garage door opener is far enough away from my router that it occasionally disconnects. Because opening or closing the door is the same MQTT command, whenever TASMOTA reconnected, it would toggle the door opening. I’m sure you can appreciate that this is a non-starter.

I only really need it to retain the setting for the sensor, not the setting of the relay. Is there any way I can configure it to do that? Otherwise, I guess I might have to live with this issue.

Depends on how much of a kludge you want. You could write a bash listener, and republish the message straight after with the retain set.

device -> mqtt “cmnd/GarageDoor/POWER_temp” -> bash listener
bash publisher -> mqtt “cmnd/GarageDoor/POWER” -retain

If you are just wanting to keep the sensor state, what about storing it as a boolean or input_select?

Use MQTT to update this instead?

Storing as an input_boolean is a possibility. I’ll have to look into that.

I’m envisioning an automation to set the state of the input_boolean based on the states of the garage door that are actually reported. Then the state of the input_boolean will get persisted across restarts.

The part I’m not sure about is how to make the state of the garage door in HA accurately reflect the value of the input_boolean on HA startup without actually triggering the door to open or close.

You mean if the door state changes whilst HA is not running it could get out of sync?

Edit or now thinking about it, you mean when you detect it’s open, you now toggle the input_boolean. The input_boolean then treats the to “on” change as an indication of the switch being toggled, therefore it sends a command to open the door. And then it loops because that would close the door.

Mmmm could be interesting.

No, I mean that the cover’s state will be ‘unknown’ when HA restarts. I’ll want to set it to the appropriate ‘closed’ or ‘open’ based on the value of the input_boolean. I don’t want to call one of the cover services because that would actually open or close the door. I just want to set the state like you can in the ‘States’ developer tool in the UI.

Ideally, yes. A command topic is only relevant at the moment it’s issued. There’s no need to retain it for use by other subscribers at a later time (unless there’s a special use-case and a garage-door opener ain’t it).

In contrast, a state topic is often relevant to future subscribers (like Home Assistant after a reboot) and so should be retained. Having said that, there are exceptions but, in my experience, I haven’t run into them.

Which part of your system is publishing this state topic:

cmnd/GarageDoor/POWER2

Because that’s the only one that should be using retain=true. Unless I’ve misunderstood your system, I believe it’s the Sonoff switch. Home Assistant publishes the command topic and so the cover’s retain flag should be false.

If your mosquitto broker is currently retaining the value for the command topic (cmnd/GarageDoor/POWER2) you should purge it. To purge a retained topic value you must publish an empty string to it.

For reference, this is how I configured the Sonoff with Tasmota to control my garage door:

You’re right on all counts. I just don’t know how to make the switch state get retained when the relay state isn’t. Can I do this via configuration in Tasmota? I had to remove the “retain: true” line in the HA cover config because that was giving me issues previously. I’m not sure what that line does behind the scenes. Those problems were all when I was using the embedded MQTT broker, however.

I have no hands-on experience with replacement firmware, like Tasmota, ESPurna, ESPeasy, etc, only ‘book learning’ so take what I say next with a grain of salt.

I scanned the list of MQTT-specific Tasmota commands and it appears to provide fine-grained control of what it does and does not publish with the retain flag.

Specifically, there’s ButtonRetain, PowerRetain, and SensorRetain. I’m going to take a wild guess and say SensorRetain might represent the garage-door sensor you hooked up. That would be the parameter I’d set retain=true and the other two to retain=false (but I could be wrong).

Again, before tweaking anything, be sure to purge the darn command topic so the broker is no longer holding on to a value. Otherwise, this “pre-condition” might goof up all your experiments to make this work the way you want.

I’ve fixed my problem by adding a small program that hits the web API to retrieve the existing state information for my garage door object and then changes the state to the appropriate value based on the input_boolean that is storing the current state of the garage door. I then set up an automation that runs 15 seconds after HA boots to run this shell_command.

Seems like a lot of running around to get a simple task accomplished, but now it’s done :slight_smile:

Could show us your code

If it helps I’ve seen issues like this with espurna firmware which is fixed by a “state topic” which is a value which the device publishes to and HA listens to and then updates the GUI accordingly. On some devices there’s a refresh interval you can set.

Would be interesting to listen to all mqtt traffic from your device and see what it’s publishing

I’m sure that this could be accomplished more simply in python or some other scripting language, but I’m just more familiar with C#. I stuck it in a shell_command and use it like this:

shell_command:
  set_garagedoor_state: /home/hass/config/bin/DeviceStateChanger.exe localhost:8123 cover.garagedoor state {% if is_state('input_boolean.garagedoor_state', 'off') -%} closed {%- else -%} open {%- endif %}

Here’s the automation that uses it:

automation:
  - id: SetVariablesOnStartup
    alias: Home Assistant Startup
    initial_state: 'ON'
    trigger:
      - platform: homeassistant
        event: start
    action:
      - delay: '00:00:15'
      - service: shell_command.set_garagedoor_state

Here’s the code that I wrote for the utility:

namespace DeviceStateChanger
{
    using System;
    using System.IO;
    using System.Net;
    using System.Web.Script.Serialization;

    class Program
    {
        static void Main(string[] args)
        {
            // expected arguments:
            // 0: serverName:port
            // 1: device name
            // 2: parameter
            // 3: value
            dynamic objectInfo = null;
            var homeAssistantAuthKey = new Properties.Settings()["HomeAssistantAuthKey"];
            var webserviceUri = new Uri($"http://{args[0]}/api/states/{args[1]}");
            var serializer = new JavaScriptSerializer();

            // Call into HA to retrieve the current state of the device
            {
                var request = WebRequest.CreateHttp(webserviceUri);
                request.Method = "GET";
                request.ContentType = "application/json";
                request.Headers.Add("Authorization", $"Bearer {homeAssistantAuthKey}");

                using (var response = request.GetResponse())
                {
                    using (var responseReader = new StreamReader(response.GetResponseStream()))
                    {
                        objectInfo = serializer.DeserializeObject(responseReader.ReadToEnd());
                    }
                }
            }

            // Set new state
            Console.WriteLine($"{args[1]} existing state = {objectInfo[args[2]]}");
            objectInfo[args[2]] = args[3];
            Console.WriteLine($"{args[1]} updated state = {objectInfo[args[2]]}");
            Console.WriteLine();

            // Tell HA about the updated state
            {
                var request = WebRequest.CreateHttp(webserviceUri);
                request.Method = "POST";
                request.ContentType = "application/json";
                request.Headers.Add("Authorization", $"Bearer {homeAssistantAuthKey}");
                using (var requestWriter = new StreamWriter(request.GetRequestStream()))
                {
                    var jsonString = serializer.Serialize(objectInfo);
                    requestWriter.Write(jsonString);
                    requestWriter.Flush();
                }

                using (var response = request.GetResponse())
                {
                    using (var responseReader = new StreamReader(response.GetResponseStream()))
                    {
                        Console.WriteLine(responseReader.ReadToEnd());
                        Console.WriteLine();
                    }
                }
            }
        }
    }
}

Did you try my suggestion? I watched the video you posted and I’m now more certain that it would work.

GPIO14 is listed as Sensor. Tasmota’s default setting for SensorRetain is off (same as for ButtonRetain and PowerRetain).

Run “SensorRetain 1” in the console to enable it. That’ll make the broker retain the Sensor’s value and subscriber’s will receive it upon connection (as opposed to receiving nothing).

For good measure, confirm PowerRetain is disabled.

I did try that, but to no avail. So far, my clunky solution has been the only thing that’s worked for me.

That’s odd … but I won’t press the issue. If what you have now works, great!

Wanted to come back here and detail exactly what was the cause of my issue, because now I finally understand it :slight_smile:

The problem was originally caused by my use of the “retain: true” flag in my cover entity. After learning a bit more about what the MQTT retain flag does, I realized that MQTT was just doing its job. If my garage Sonoff ever dropped off the wifi, when it came back on, it would look for any retained MQTT commands that were available for it. Because the ‘open’ and ‘close’ MQTT commands were the same, it would effectively toggle the state no matter what when it re-joined the network.

To ultimately fix the issue, I set the retain flag on the sonoff instead of the cover entity in Home Assistant. I set both the PowerRetain and SwitchRetain options on the sonoff. Some people above suggested this option, and I was convinced that I couldn’t use retain. It was only because open and close were the same in that cover entity that the retain flag was screwing me. Settiing the retain flag for the particular MQTT commands was fine.

The binary_sensor wasn’t picking up its state on HomeAssistant restart because I didn’t have the state MQTT command retained. This was fixed by setting the SwitchRetain flag on the sonoff.

Because of this, my garage door no longer suddenly opens in the middle of the night, and I don’t need the crazy solution I came up with above. I almost certainly didn’t need to install mosquitto, but I have it now, so that’s cool.

Live and learn. Hopefully someone else can benefit from my troubles.

1 Like

25 days ago I wrote:

You later replied you tried my suggestion yet it didn’t work. That made absolutely no sense to me, but I didn’t press the issue because you had already moved to another solution.

So what happened in the intervening 20+ days that ultimately made it work?

What “made it work” was some good old fashioned learning :slight_smile: I had made assumptions that were ultimately proven wrong. You were 100% correct from the beginning. I didn’t really understand ‘MQTT retain’.

When I said I had tried using ‘retain’ it was the home assistant “retain: true” option on the cover entity. Like I said in my mea culpa post, that completely breaks down because it doesn’t distinguish between PowerRetain and SwitchRetain, and the ‘open’ and ‘close’ commands are the same.

I have the same issue of “unknown” starus after restart. I’m a newbies in HASS, co could you please describe in layman’s terms what exactly you did, to solve this issue. Did you change sometthing in Tasmota console or in HASS?