Trouble with MQTT Binary (Motion) Sensor

Trying to setup a binary sensor to represent motion based on a MQTT payload. I’m sure it’s something I’m missing, but here’s my sensor definition in configuration.yaml

mqtt:
  binary_sensor:
    - name: driveway_mus_motion
      unique_id: driveway_mus_motion
      device_class: motion
      state_topic: "zoneminder/1"
      value_template: "{{ 'ON' if value_json.eventtype == 'event_start' else 'OFF'}}"
      off_delay: 120
      enabled_by_default: false

Here’s my raw jason:

{
  "name": "Driveway (MUS):(32687) Linked",
  "detection": [],
  "eventtype": "event_start",
  "hookvalue": "1",
  "eventid": "32687",
  "monitor": "1",
  "state": "alarm"
}

So, what happens right now is that the trigger for ON seems to work, but when the state is Unlown, it shows as ON in the icon. So, what I’m looking for is, if the topic doesn’t exist, or the payload doesn’t match either because “eventtype” doesn’t exist or is a different value, that the sensor is in an OFF state. The “off_delay” only seems to work when the sensor was set into the ON state. The “enabled_by_default” seems to do nothing.

      value_template: >
        {{ iif(value_json.eventtype is defined and value_json.eventtype == 'event_start', 'ON', 'OFF') }}

As far as I know, there’s no test for that. Perhaps you can use expire_after which will cause the sensor to report unavailable if no payload is received within a specified time period.

Is there a way to, on HASS startup, to set the sensors into a known state? I could, say after a 30 second delay, set these sensors to “off” then let things stabilize on their own.

On startup, MQTT sensors get their state from their topic.

  • If the topic contains a retained message (meaning the last payload that was published to the topic was stored on the broker) then it immediately becomes the sensor’s value.

  • If it wasn’t published as a retained message then the sensor’s state will be unknown until the next payload is published to the topic.

The device that’s publishing to zoneminder/1 is responsible for determining if the payload is published as a retained message or not.

There’s the off_delay option but it doesn’t just apply to startup and is meant for use with devices that only publish their on state, not their off state.


Did you implement what I have already suggested and what was the result?

So the iif you suggested does about the same. When things first start, we’re in an Unknown state.
I did set the off_delay, but that only seems to start the countdown when the sensor first goes ON, so doesn’t help in the unknown state.
I did look at the retention flag, but that doesn’t seem to help. My MQTT broker is not in HASS, so a restart of HASS doesn’t clear the queue and the topics are still there.
So do I add a second layer of binary_sensor that isn’t tied to MQTT directly, but will read the state of my MQTT binary_sensor then set the state? That seems convoluted to me. Or, is there a way to set the icon to something custom based on state? The biggest issues is when it’s UNKNOWN, it’s the same as the DETECTED and until I set the payload in MQTT to ON, then let it timeout to OFF, things are in a weird state.
I guess, at HASS startup I could just send a dummy payload into MQTT to set the initial state of things, although I was hoping that I could directly set the state of the binary sensor.

payload_off string
(optional, default: OFF)

The string that represents the off state. It will be compared to the message in the state_topic (see value_template for details)

payload_on string
(optional, default: ON)

The string that represents the on state. It will be compared to the message in the state_topic (see >value_template for details)

payload_on: “event_start”
payload_off: (I am not sure what you have for this is just blank atm or does it have a state?)

You could try setting the payloads.

Also mqtt retained.
Messages sent without the retained flag, will not be visible upon a new connection to the broker. The retained flag will make them visible upon a new connection.

You can test that with mqtt explorer.
Send the message. disconnect and reconnect mqtt explorer and see if the message is still visible.

Even with the retain flag, the sensor wasn’t picking up the state, maybe a bug or something. What I did do, instead of using the off_delay, I created a automation that triggers when the sensor goes to ON for 90 seconds, or homeassistant starts, that calls the mqtt.publish to set the appropriate topic to “event_end” so that I start in a known state and have a good transition from ON to OFF. I think of it as my pulldown resistor.
It seems to work so far, not elegant by any means and adds to my automations, but it’s not horrible.
I looked at the payload_on property, but wasn’t sure how that would see it with a large json string.
I am interested in your iif code you published, I can’t find a good reference to that.

@123 Taras is the guru there. I just copy stuff. the docs are > templating Immediate if

Is this what actually gets publish on Off states?

{
  "name": "Driveway (MUS):(32687) Linked",
  "detection": [],
  "eventtype": "event_end",    <<  is this  the payload that gets published by the motion sensor
  "hookvalue": "1",
  "eventid": "32687",
  "monitor": "1",
  "state": "alarm"
}

that would make

payload_off: "event_end"

the payloads just convert the string to the on and off that a binary sensors requires I believe.

Because the payload isn’t being published as a retained message.

That’s exactly how the documentation explains its behavior (and why I said it doesn’t apply at startup).

I don’t know what “queue” you mean and the broker’s location is irrelevant. Home Assistant acts as an MQTT client so on startup it logs into the broker (wherever it’s hosted) and subscribes to all required topics (i.e. the topics of all MQTT-based entities, MQTT triggers, etc). At the moment it subscribes, it receives any payloads that were published as a retained message (i.e. it receives payloads stored on the broker).

Then you did something wrong somewhere. Where did you set the “retain flag”? It must be set on the device that publishes to zoneminder/1 and then confirmed by checking the topic with another client (like MQTT Explorer).

This isn’t useful for this application because the received payload is a JSON dictionary plus, apparently, the desired key in the dictionary doesn’t always exist.

If you’re forcing it to off on startup, what if it’s state was actually on just before Home Assistant restarted? Your automation just forced it into the wrong state.

1 Like

The entire JSON is the payload unfortunately.

Entire json is fine.
That’s what the value template and key:value do to refine the entire json to that key and then use it’s value.

key >>>  "eventtype": "event_start"   <<< value
value_template: >
        {{ iif(value_json.eventtype is defined and value_json.eventtype == 'event_start', 'ON', 'OFF') }}

What is the “Off” state json published though?? or isn’t there any or it always ‘event_start’?
It never publishes an off state…

This won’t fit your use case because of the json… tasmota pir example It does a good job of defining the other parts though.

Anyway I am just getting in the way now.

The template I posted above checks if the desired key exists (eventtype) and its associated value is event_start. If true it reports ON otherwise it reports OFF. In other words, if the value is anything other than event_start it reports OFF.

The sensor’s state will be unknown at startup if the topic doesn’t have a retained message.

1 Like

So I was bored and decided to play around with this.

If you manually publish a retained msg to your broker without the event_start, the binary sensor will start as clear in lovelace on mqtt reload or HA restarts.
You could also update your automation so that if the state was unknown or unavailable for > 5secs repuplish the manual message. Although the retained msg shouldn’t be deleted unless your broker failed…

mqtt:
  binary_sensor:
    - name: driveway_mus_motion
      unique_id: driveway_mus_motion
      device_class: motion
      state_topic: "zoneminder/1"
      value_template: >
          {{ iif(value_json.eventtype is defined and value_json.eventtype == 'event_start', 'ON', 'OFF') }}
      off_delay: 20

Capture

Retained msg --- starts as clear. Leave this as retained on your broker

{
  "name": "Driveway (MUS):(32687) Linked",
  "detection": [],
  
  "hookvalue": "1",
  "eventid": "32687",
  "monitor": "1",
  "state": "alarm"
}

Capture

retained msg --  starts as detected 

{
  "name": "Driveway (MUS):(32687) Linked",
  "detection": [],
  "eventtype": "event_start",
  "hookvalue": "1",
  "eventid": "32687",
  "monitor": "1",
  "state": "alarm"
}

Does this ever change btw?

 "detection": [],

Your suggestion forces the binary_sensor’s state to off on startup. jlw52761 stated that he has already created an automation that does this. It’s not a good solution because if the binary_sensor was on before restarting Home Assistant, it will be forced to off on startup (and no longer report the device’s true state).

The solution is to ensure the device publishing to zoneminder/1 does so as a retained message. If there’s no ability to do that then the alternative is to create a ‘middleman’ automation that subscribes to zoneminder/1, publishes whatever it receives as a retained message to a new topic, like zm/1, and then set the MQTT Sensor’s state_topic to zm/1. It’s a trivially simple automation that ensures the sensor immediately acquires a correct value on startup.

True.

Although if there was actually motion when HA restarted, then the retained message would be ignored in favour of the real message received after HA subscribed to the topic.

It wouldn’t be “ignored”. The sensor always uses the latest value published to its state_topic.

Yes… And if there is motion, it would be event_start and the state would be detected.

You’re stating the obvious so I fail to see why you had claimed a value would be “ignored”.

Each new payload published to a topic replaces the previous one. The subscriber to the topic (the MQTT Sensor) doesn’t “ignore” anything, it simply receives the latest published payload.

You are missing the point.
This has removed his unknown state, so fixes his original concern of the card showing On on unknown state.

If the state was motion when HA stops it should have started whatever automation was trying to triggered, before it died.

If HA crashed mid automation it was never going to act…

The state now briefly starts as unknown, then immediately flicks to clear.
HA is now subscribed.

If there is motion, there will be a new message with event_start, which will immediately update the state from clear to detected, which has updated the any triggers to start an automation or whatever.

With all due respect, you don’t appear to understand how Home Assistant uses MQTT with an MQTT Binary Sensor. If configured correctly, there’s no need for an automation to force the entity’s state to a default value.

For reference, I have several MQTT Binary Sensors (and other MQTT-based entities like lights, switches, sensors, locks, thermostat, etc) that always report the correct state on startup (over three years of operation). None require automations to set their state on startup.