How to make HA actively check availability?

Hello everyone,
I wanted HA to notify me when a device is no longer available. So in theory the state would change from e.g. “OK” to “unknown”.
However, I have found that my sensors’ state does not change if the device is no longer available. It remains in the last known state.

My sensor:

- platform: mqtt
  state_topic: stat/EQ3/001A2208B97D
  name: "eQ-3 Battery LR"
  value_template: >
        {{ value_json.battery }}
  icon: hass:battery

My automation

- id: '1634910544401'
  alias: eQ-3 Battery LOW (Living Room)
  description: ''
  trigger:
  - platform: state
    entity_id: 
      - sensor.eq_3_battery_lr
    from: 'GOOD'
    to: 'LOW'
  - platform: state
    entity_id: 
      - sensor.eq_3_battery_lr
    from: 'GOOD'
    to: 'unknown'
    for:
      hours: 0
      minutes: 5
      seconds: 0
      milliseconds: 0
  - platform: state
    entity_id: 
      - sensor.eq_3_battery_lr
    from: 'LOW'
    to: 'unknown'
    for:
      hours: 0
      minutes: 5
      seconds: 0
      milliseconds: 0
  condition: []
  action:
  - service: notify.mobile_app_sm_g975f
    data:
      message: eQ-3 Battery LOW (Living Room)
      title: eQ-3 Battery LOW (Living Room)
  - service: notify.discord
    data:
      message: eQ-3 Battery LOW (Living Room)
      target: [!secret discord_target]
  - service: telegram_bot.send_message
    data:
      message: eQ-3 Battery LOW (Living Room)     
  mode: parallel
  max: 10

The reason for this is, that sometimes the device jumps from GOOD to dead. So the battery just dies without the state first being low.
But once this happens, there is no new data and HA retains the value.

Is there a way to make HA check the state?

The device is integrated via an ESP32 device running Tasmota. So
Thermostat → bluetooth → ESP32 dev board (Tasmota) → wifi (MQTT) → Home Assistant.

You don’t need to make Home Assistant check the device’s state. Your device is using MQTT via Tasmota so what you need to use in the sensor’s configuration is availability_topic.

Thank you for that, @123 .
But does there have to be a topic, that signals availability or does this check if a topic is sending anything and then decides whether the device is available or not?

Because I added the same topic as for the state (because essentially if this state_topic sends data, then the device is available)

  availability_topic: stat/EQ3/001A2208B97D

but then the sensor is then always unavailable.

As far as I know, the device does not send its availaibility status as “available/unavailable”.

16:11:27.703 MQT: stat/EQ3/001A2208B97D = {"cmd":"poll","result":"ok","MAC":"001A2208B97D","tas":"tasmota-D2EE70-3696","RSSI":-74,"stattime":1635084687,"temp":4.5,"posn":0,"mode":"manual","hassmode":"off","boost":"inactive","dst":"set","window":"closed","state":"unlocked","battery":"GOOD"}

EDIT:
One thing that I just found is the BLE topic of the ESP32 itself.
It lists the available BLE devices. But I am not sure how I would check this for the device in question because it would need to be a “if string contains” kind of lookup.
tele/tasmota_D2EE70/BLE = {"Time":"2021-10-24T16:52:04","BLEDevices":{"total":2,"001A2208CFD3":{"i":0,"r":-73},"001A2208B97D":{"i":1,"r":-83}}}

tele/device_name/LWT should be publishing Online and Offline messages.

If in doubt, Google (and then Download) MQTT Explorer and you can easily see everything that is happening on all MQTT topics.

You can’t just use the topic that is publishing the actual data, because Home assistant is looking for a specific payload, which you can specify with payload_available: and payload_not_available: and since the topic that is publishing the data does not match either of those payloads, then Home Assistant cannot determine if it is online or offline.

But I think that this only works for Tasmota devices and not a Tasmota hub.
The devices themselves are not Tasmota (setup desrcibed in first post).

So I think only the Tasmota ESP32 board will send its availability, will it not? The BLE devices that send their battery states to the Tasmota ESP32 board (hub) don’t publish availability. And the ESP32 does not publish availability for the different devices connected to it via BLE.

I made a mistake because I misread your first post and assumed the devices were flashed with Tasmota. I now understand the devices communicate via Bluetooth through an ESP32 flashed with Tasmota which communicates with Home Assistant via MQTT.

The ESP32 publishes the sensor’s value as a retained message to the MQTT broker. That means the value is stored by the broker and made available to Home Assistant whenever it connects to the broker. This value changes only when the device transmits a new value. If the device ceases to transmit new data, the broker’s stored value remains unchanged.

If you use the expire_after option in your MQTT Sensor configuration, it will automatically report unavailable if it detects the value hasn’t been updated within a specified interval. For example, if you specify 600 seconds, it means the sensor should receive a new value within 10 minutes. If it doesn’t, the sensor’s state value is set to unavailable.

1 Like

Does that work even if the new value is the same as the old value? Or do you have to use force_update so Home Assistant acknowledges that it has received a value, even if it hasn’t changed?

Good question; I haven’t experimented with that scenario so I don’t know the answer.

Had a quick look at Github.

def _update_state(msg):
            payload = msg.payload
            # auto-expire enabled?
            expire_after = self._config.get(CONF_EXPIRE_AFTER)
            if expire_after is not None and expire_after > 0:
                # When expire_after is set, and we receive a message, assume device is not expired since it has to be to receive the message
                self._expired = False

                # Reset old trigger
                if self._expiration_trigger:
                    self._expiration_trigger()
                    self._expiration_trigger = None
# Set new trigger
                expiration_at = dt_util.utcnow() + timedelta(seconds=expire_after)

                self._expiration_trigger = async_track_point_in_utc_time(
                    self.hass, self._value_is_expired, expiration_at
                )

Looks like just receiving a message will reset the timer, before it even attempts to decide if the message is valid.

The expire_after option works perfectly. The ESP32 checks every 5 minutes for thermostat data. So I set the expire to 12 minutes, which means there will be two attempts at getting fresh data before the device is set unavailable.

Glad to hear it solved the original problem (and without any need for an automation).

Please consider marking my post above with the Solution tag. It will automatically place a check-mark next to the topic’s title which signals to other users that this topic has been resolved. It will also place a link below your first post that leads to the solution post. All of this helps users find answers to similar questions. For more information, refer to guideline 21 in the FAQ.

Sorry, I usually do mark the solution.

Thank you for your help! :slight_smile:

1 Like