Template to use existing value when new value is not present

I have an MQTT topic that sends data updates. Sometimes a field is not present, and sometimes it returns -1 if there’s no data available.

So what I’m trying to do is build a sensor so that non-present data will use the existing value.

I tried

binary_sensor:
  - platform: mqtt
    name: "Boiler on"
    state_topic: "thermostat"
    payload_on: 1
    payload_off: 0
    value_template: >
      {% if value_json.tstate is defined and value_json.tstate != -1 %}
        {{ value_json.tstate }}
      {% else %}
        {{ states('binary_sensor.boiler_on') }}
      {% endif %}

But on the cases where there’s no valid data then I get an error in the log:

2019-03-27 21:40:35 WARNING (MainThread) [homeassistant.components.mqtt.binary_sensor] No matching payload found for entity: Boiler on with state_topic: thermostat

How can I use the current state, or alternatively skip updating the state?

Here’s why:

A binary_sensor’s valid states are on and off. That means this:
states('binary_sensor.boiler_on')
will return either on or off, depending on its current state.

In your value_template you have:

      {% else %}
        {{ states('binary_sensor.boiler_on') }}
      {% endif %}

It means when else is executed, it will return either on or off, depending on the current state of binary_sensor.boiler_on.

The problem is that value_template has to produce something that matches one of these values:

    payload_on: 1
    payload_off: 0

Neither on or off will ever match 1 or 0 and that’s why you get the warning message No matching payload found for ...

Oh, I see!

So would a template like this work better (and delete the payload_on/off lines) ?

value_template: >
  {% if value_json.tstate is defined and value_json.tstate == 1 %}
    on
  {% elif value_json.tstate is defined and value_json.tstate == 0 %}
    off
  {% else %}
    {{ states('binary_sensor.boiler_on') }}
  {% endif %}

No. Your template still uses {{ states(binary_sensor.boiler_on') }} which will return on or off and never 1 or 0.

Try this:

    value_template: >
      {% if value_json.tstate is defined and value_json.tstate != -1 %}
        {{ value_json.tstate }}
      {% else %}
        {{ 1 if states('binary_sensor.boiler_on') == 'on' else 0 }}
      {% endif %}

Ah, OK, I can see what you’re doing here (forcing everything to be 0 or 1, and so matching a payload_on/off setting). I’ll give that a try. Thanks!

Out of curiousity, wouldn’t it be “cleaner” to force the good values to return the expected value for the default on/off ? So if I don’t have any payload_on or payload_off values, force the received values to be on/off ?

OK, so based on your suggestion this seems to work, and didn’t trigger a warning on bad data

  - platform: mqtt
    name: "Boiler on"
    state_topic: "thermostat"
    payload_on: 1
    payload_off: 0
    value_template: >
      {% if value_json.tstate is defined and value_json.tstate != -1 %}
        {{ value_json.tstate }}
      {% else %}
        {{ 1 if states('binary_sensor.boiler_on') == 'on' else 0 }}
      {% endif %}

I guess I don’t understand why

- platform: mqtt
  name: "Boiler on"
  state_topic: "thermostat"
  value_template: >
    {% if value_json.tstate is defined and value_json.tstate == 1 %}
      on
    {% elif value_json.tstate is defined and value_json.tstate == 0 %}
      off
    {% else %}
      {{ states('binary_sensor.boiler_on') }}
    {% endif %}

Caused errors. Wouldn’t this match the default values for on/off ?

No. The value_template must produce results that match payload_on and payload_off. If you read the documentation for MQTT Binary Sensor, the default values for payload_on and payload_off are: ON or OFF (uppercase, not lowercase).

Your value_template uses lowercase on and off so they will fail to match the default values for payload_on and payload_off.

In addition, states('binary_sensor.boiler_on') returns on or off so you’d need to use a filter to convert the states to uppercase.

      {{ states('binary_sensor.boiler_on') | upper }}

I hope this makes it all clearer now.

Oh, case sensitivity!

I never expected the current value of sensor (“on”) to not match the default valid input to a sensor (“ON”) . I wrote my template to match values in the states table. That was my mistake!

But, yes, this explains everything. Odd. Unexpected. But explainable :slight_smile:

Thanks!

You’re welcome!

Tag one of those posts as ‘solution’ so others can easily find it in the thread.