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 %}
2 Likes

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"
    sensor:
      - 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"
2 Likes

I wanted to post a summary of this old thread because it helped me fix a problem, but it took a long while to figure out how. Everyone seemed to be talking at crossed purposes. Hopefully this will help someone else get to a solution quicker.

The problem

Davinci’s original problem involved sensors that were supposed to return numeric values, but actually returned strings like "unknown" or "unavailable". These values then caused errors when used in template functions that expected inputs that could be converted into numeric values.

Digeridrew and Petro suggested adding default parameters into the functions that threw the errors, but this didn’t seem to make sense to Davinci: using a default value of the correct type makes the error go away, but then means that the template that uses those functions will produce a valid but incorrect answer. Defaulting to the string "unknown" just produces more errors when the template is expected to output a number.

Petro and Dbrunt also mentioned using availability: templates. If these templates evaluate to a value like false, the sensor will have the state "unavailable" and its icon will be greyed-out in the UI. You can use these to flag a template entity as unavailable when the values it depends on are unavailable or unknown. However, this doesn’t solve the whole problem either. Even when the template sensor is flagged as unavailable, it will still throw errors if "unknown" or "unavailable" values are passed into numeric functions in the template.

The Solution

To fix this issue robustly, you need to use both default values and availability: templates at the same time. In an ideal world, if the availability: template flagged the sensor as unavailable, then Home Assistant wouldn’t try to render the state: template, and you wouldn’t get errors. Unfortunately, it seems to still process the state: template, even though it will discard its output. This means you need to use defaults in any numeric function in the state: template that could potentially receive an unexpected string value like “unknown” or “unavailable”. Similarly, if you are expecting JSON inputs, the state: template needs to handle missing data elements without throwing errors, e.g. by checking that objects exist before trying to access their attributes.

You then need to set the availability: template to check for bad inputs to your template, so that the output of the state: template will be discarded and replaced by "unavailable", rather than a plausible but wrong value based on default inputs.

For me, something like this worked:

 template:
   sensor:
    - name: Test Sensor
      unit_of_measurement: "%"
      state_class: measurement
      availability: |-
        {{ states("sensor.unreliable_sensor") != "unavailable"
        and states("sensor.unreliable_sensor") != "unknown" }}
      state: |-
        {{ states("sensor.unreliable_sensor") |float(default = 100) / 100 }}

Remember that even once you have set this up properly, if your template sensor was supposed to output a numeric value rather than a string, you will still have to make sure that any automations or other templates that it is used in can also handle receiving "unavailable" as their input.

3 Likes