Three facts that cause most template bugs
- Every state is text.
"21.5"is a string until you convert it. - Missing entity →
"unknown". A typo in an entity ID doesn't raise an error;states()returnsunknown. - Offline device →
"unavailable".unknownmeans "exists, value not known right now".unavailablemeans "can't be reached" (device offline, integration failed to load).
So {{ states('sensor.outdoor_temp') | float + 5 }} fails exactly when the sensor goes offline, often at night, in an automation nobody is watching.
Patterns
{# Convert with a fallback: 0 is used when the state is unavailable/unknown #}
{{ states('sensor.outdoor_temp') | float(0) + 5 }}
{# Better when 0 would be a misleading value: skip the calculation #}
{% if has_value('sensor.outdoor_temp') %}
{{ (states('sensor.outdoor_temp') | float * 1.8 + 32) | round(1) }}
{% else %}
unavailable
{% endif %}
{# Attributes: use state_attr(), compare with is_state() / is_state_attr() #}
{{ state_attr('climate.living_room', 'current_temperature') }}
{{ is_state('binary_sensor.front_door', 'on') }}
For template sensors
- Pick the fallback deliberately.
float(0)makes a dead temperature sensor report 0 °C, which can trigger heating automations. Prefer an availability condition (has_value(...)) so the template sensor itself becomes unavailable. - Test in Developer tools → Template with the source entity switched off or renamed.
- Use
states('...')rather than attribute access onstates.domain.entity, so missing entities give youunknowninstead of an error.