WTH - Is there no easy way to return unavailable from a template

Simplest example, imagine is have sensor.temperature and I want to create a template that returns the temperature doubled (dumb, but simple example).

In the UI I have not found the recommended way to do that. I can do:

{% if has_state('sensor.temperature') %}
    {{ states('sensor.temperature') * 2 }}
{% else %}
    ??
{% endif %}

What to put in the else clause? No else clause? None? Something else?

In YAML, the availability template can be used. However I must repeat the state logic in availability, so it not great to have to repeat logic (not DRY).

It would be great that a template sensor’s state is unavailable if the state returned is None.

yes to both, if that’s not the case, I can probably add it. I’m pretty sure this is how it behaves now.

This returns unknown if the source is unavailable or unknown:

{% set ent = 'sensor.temperature'%}
{% if has_value(ent) %}
    {{ states(ent)|float(0) * 2 }}
{% else %}
{{ none }}
{% endif %}
1 Like

Perhaps this is just a documentation issue then - I spent at least two hours searching for answers in the docs, forums, and Reddit. I did not see a definitive answer. This thread was the closest I could find: How to handle unknown or unavailable states in template entities or automations - but it danced around a lot of aspects of this problem.

But that said, on restart of HA I was seeing exceptions when using none or leaving out the else clause. One example from my logs:

s6-rc: info: service legacy-services: stopping
2024-12-06 17:43:11.439 ERROR (MainThread) [homeassistant.helpers.event] Error while dispatching event for climate.ecobee to <Job track state_changed event {'climate.ecobee', 'sensor.ecobee_temperature_t6xz'} HassJobType.Callback <bound method TrackTemplateResultInfo._refresh of <TrackTemplateResultInfo {Template<template=({% if has_value('sensor.ecobee_temperature_t6xz')
   and has_value('climate.ecobee') %}
  {% set upstairs =
       states('sensor.ecobee_temperature_t6xz') | float %}
  {% set current = state_attr('climate.ecobee',
      'current_temperature') | float %}
  {{ '%0.1f' | format(current*2 - upstairs) }}
{% else %}
  none
{% endif %}) renders=8>: <RenderInfo Template<template=({% if has_value('sensor.ecobee_temperature_t6xz')
   and has_value('climate.ecobee') %}
  {% set upstairs =
       states('sensor.ecobee_temperature_t6xz') | float %}
  {% set current = state_attr('climate.ecobee',
      'current_temperature') | float %}
  {{ '%0.1f' | format(current*2 - upstairs) }}
{% else %}
  none
{% endif %}) renders=8> all_states=False all_states_lifecycle=False domains=frozenset() domains_lifecycle=frozenset() entities=frozenset({'sensor.ecobee_temperature_t6xz'}) rate_limit=None has_time=False exception=None is_static=False>}>>>
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 677, in state
    numerical_value = float(value)  # type:ignore[arg-type]
ValueError: could not convert string to float: 'none'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/event.py", line 356, in _async_dispatch_entity_id_event
    hass.async_run_hass_job(job, event)
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 949, in async_run_hass_job
    hassjob.target(*args)
    ~~~~~~~~~~~~~~^^^^^^^
  File "/usr/src/homeassistant/homeassistant/helpers/event.py", line 1314, in _refresh
    self.hass.async_run_hass_job(self._job, event, updates)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/core.py", line 949, in async_run_hass_job
    hassjob.target(*args)
    ~~~~~~~~~~~~~~^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/template/template_entity.py", line 463, in _handle_results
    self.async_write_ha_state()
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1023, in async_write_ha_state
    self._async_write_ha_state()
    ~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1148, in _async_write_ha_state
    self.__async_calculate_state()
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1085, in __async_calculate_state
    state = self._stringify_state(available)
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 1029, in _stringify_state
    if (state := self.state) is None:
                 ^^^^^^^^^^
  File "/usr/src/homeassistant/homeassistant/components/sensor/__init__.py", line 679, in state
    raise ValueError(
    ...<5 lines>...
    ) from err
ValueError: Sensor sensor.ecobee_main_floor_temperature has device class 'temperature', state class 'measurement' unit '°C' and suggested precision 'None' thus indicating it has a numeric value; however, it has the non-numeric value: 'none' (<class 'str'>)

Is this a trigger-based template sensor? If so, this is a known issue:

Those templates return none which is the test, does it error when you return None, the object?

I have tried both none and None. Does not seem to be a difference. I prefer using None. The errors have stopped at the moment. I’m not sure why as I did not change anything.

However, back to the WTH… It seems a template returning None for the state is the correct way and seems to work best. If it is the HA sanctioned way to do this, then a note in the template docs would be the solution to this WTH.

There may also be some undocumented behaviour or a bug around whether setting state class of the sensor causes this. As I play with this some more I will amend this WTH or create a bug if warranted.

None is the correct one. none is the test, and it should only be used in a test, i.e. x is not none

Well, you can’t set the value to None if it’s a numeric sensor state_class entity. That’s likely a feature request. I can look into adding it. IMO it should behave the way you describe, however I could see getting pushback from the dev team if I change the behavior.

1 Like

The docs explicitly say you can.

If the sensor is numeric, i.e. it has a state_class or a unit_of_measurement , the state template must render to a number or to none .

It’s just that None will result in unknown only for state-based template sensors. Something is broken with trigger-based template sensors and None results in an error.

1 Like