How to handle unknown or unavailable states in template entities or automations

* Template warning: 'int' got invalid input 'unknown' when rendering template ...
* Template warning: 'float' got invalid input 'unavailable' when rendering template ...
but no default was specified. Currently 'float' will return '0', however this template will fail to render in Home Assistant core 2022.1

I guess I should change something in my templates, but how? If the value is not available, it doesn’t make sense to calculate with this value. So it should probably set the template entity to unknown.

This also includes states for automations:

* Error in 'xyz' trigger: In 'numeric_state' condition: no entity specified

So I should add this to all my templates?

{{ ,  default = "unknown" }}
          {% if (states('sensor.wind_m_s') | float < 5) %}
            {{ (10 * 3.6 * states('sensor.wind_m_s') | float )| round(1),  default = "unknown" }}
          {% else %}
            {{ "unknown" }} //erratic value
          {% endif %}

What happens if the if statement fails?

What about conditions in automations?
* Error in 'xyz' trigger: In 'numeric_state' condition: no entity specified

I don’t see the benefit of doing this, could someone please explain?

If the value is not available the template will be unknown anyway, right?

The benefit is that, when you update to 2022.1 and beyond, your templates will still work.

No, you should do what is explained in the post linked above and the warning you received

If you want your templates to behave the same as it has in the past just add a default of 0 to your float() filters:

{% if (states('sensor.wind_m_s') | float(0) < 5) %}
  {{ (10 * 3.6 * states('sensor.wind_m_s') | float(0)) | round(1) }}
{% else %}
  {{ "unknown" }}
{% endif %}
1 Like

I didn’t even start before 2022.1 so for me it was always like that.

If a value is unknown it makes sense to say it is unknown. But it is already unknown, so why should I want it to be 0? So this is even redundant:
{{ , default = "unknown" }}

{% if (states('sensor.wind_m_s') | float(0) < 5) %}
The state is in that case not set, which makes it unknown, which again is correct.

Or if a template condition is having such an error it is false, which again is correct.

is the word ‘unknown’ greater than or less than 5?

When you convert the word ‘unknown’ to a number, what should that number be?

That’s what default is. It’s the value of the left side of the equation x < 5 when x fails to convert to a valid number.

The original plan was to error out templates in version 2022.1. They forgot about making that change. When they remember, your templates will start to fail.

But isn’t that what it is supposed to do? I can’t just assume states that I don’t know. In that case it will go unknown, right? Or am I missing something?

Perspective is likely the challenge here.

I have far more binary_sensor templates than any other domain. You cannot have true/false/unknown and be binary. “isn’t that what it is supposed to do?” I’d say no. A binary template should not be unknown.

If you have a string-based template sensor then “supposed” to could be any value you desire. If that is “unknown”, great!

But the vast majority of us like our binary sensors to be binary and our number templates to be a number not a string.

You’re missing something. The calculation will fail when the float can’t convert. And you’ll get an error. That’s the error you are seeing. Supplying a default will guard against it.

Edit: or supply a availability template that guards against it.

But if it is missing it should throw an error?

If I don’t have a relevant sensor value why would I calculate with a dummy value?

I think this is misplaced approach. More below…

For good reason; determinism. Aka, when an error occurs, you control the result.

Let’s use an example. If my “door unlock motion sensor” stops responding for any reason, I may choose to have a “fail-open” design and let people out. Others mights want a “fail-safe” design and lock people in. The key here isn’t choosing fail-open or fail-safe, but knowing which you have chosen.

Likewise if you have a heating or cooling circuit that relies upon a temperature sensor, do you want to turn on or off that cooling or heating circuit if the temperature sensor stops responding?

I prefer to keep my freezer food frozen even if the sensor breaks. Or I might prefer to turn the oven off in the same scenario to prevent burning food.

The key here is determinism and choice. Not the example itself. So picking apart any example misses the point.

Which leads us to the goal of monitoring sensors. I agree, that’s a good thing. But don’t do it using sensor values, use a monitoring automation or other system that reports unknown or unavailable sensors. Don’t force that on automation logic for heating/cooling/doors/whatever that isn’t designed to monitor and only designed to trigger something.

I hope this makes sense.

It does make sense.

But my use case/approach seems different.

I actually trigger on the error to ensure proper operation and also notification.

Also the default won‘t help if the the condition fails (e.g. in the if statement).

I have made wide use of the availability: template. That way, the sensor state is unavailable rather than HA throwing template warnings/errors into my logs, which usually occurs during startup as various components are initializing. This particular one though was throwing a template error at startup, sometimes two 5 seconds apart and was bugging me as I had an availability template for the MQTT sensor and even tried adding utcnow() != 'unknown' but it turned out I simply needed to default the as_timestamp() function…

  - trigger:
    - platform: time_pattern
      seconds: "/5"
      - name: "HASS Agent My PC Idle Time"
#        availability: '{{ utcnow() != "unknown" and states("sensor.lastactive") != "unknown" }}'
#        state: '{{ as_timestamp(utcnow()) - as_timestamp(states("sensor.lastactive"))|float(default=0) }}'
        state: '{{ as_timestamp(utcnow(),0) - as_timestamp(states("sensor.lastactive"),0) }}'
        unit_of_measurement: "Seconds"