Common template patterns

Templates are most useful when you can reach for an example that already does what you need. This page collects recipes for the situations that come up again and again: counting things, summarizing data, building nice-sounding sentences, and dealing with values that might be missing.

Each recipe explains what it does, shows you a working template, and links to the reference pages for the functions it uses. Copy the template you need, swap in your own entity IDs, and adjust the wording.

Counting entities

Counting is one of the most common things you do with templates. “How many lights are on?” “How many windows are open?” These templates follow the same shape every time: list the entities, filter them, count the result.

Tip

If all you need is a count on a dashboard, a Group helper can gather the entities and its state shows how many are active. No template needed.

Count how many lights are on:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{ states.light | selectattr('state', 'eq', 'on') | list | count }}
Result
3

Read the template left to right: take every light, keep only the ones whose state is on, turn that into a list, count the items in the list.

Count how many doors are open:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{
  states.binary_sensor
  | selectattr('attributes.device_class', 'eq', 'door')
  | selectattr('state', 'eq', 'on')
  | list | count
}}
Result
2

Here the filter is stricter. First keep only binary sensors whose device class is door, then only the ones that are on (binary sensors that represent doors report on when the door is open).

See selectattr, list, and count.

Finding the highest or lowest value

When you have several sensors of the same kind, you often want to pick out the extreme. The warmest room. The coldest fridge. The lowest battery. The heaviest power draw.

Tip

A Group helper can pick the minimum, maximum, or mean from a group of sensors and expose it as a regular sensor. No template needed if you only need the value.

The warmest room:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set temps = states.sensor
   | selectattr('attributes.device_class', 'eq', 'temperature')
   | list %}
{% set warmest = temps | max(attribute='state') %}
{{ warmest.name }}: {{ warmest.state }}°C
Result
Kitchen: 23.5°C

We gather all temperature sensors, then ask max to find the one with the highest state value. The result is the whole entity, so we can show both its name and its state.

The lowest battery:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set batteries = states.sensor
   | selectattr('attributes.device_class', 'eq', 'battery')
   | rejectattr('state', 'in', ['unknown', 'unavailable'])
   | list %}
{{ batteries | map(attribute='state') | map('float') | min | round(0) }}%
Result
18%

This one adds an important step: rejectattr removes sensors that are offline, so they don’t accidentally become “the lowest”. We then turn the states into numbers and ask min to find the smallest.

See also map.

Safe numbers from a sensor

This one deserves its own section because it comes up constantly. Sensors return their state as text, even when the content looks like a number. If you try to do math on that text directly, you get errors. The fix is always the same: convert with a fallback.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set temp = states('sensor.outdoor_temperature') | float(0) %}
{{ temp | round(1) }}°C
Result
22.5°C

Use float(0) for decimals and int(0) for whole numbers. The 0 inside the parentheses is the fallback value: if the sensor is offline or reports something that cannot be converted to a number, the template uses 0 instead of crashing.

Pick a fallback value that makes sense for your situation. For a temperature, 0 might be misleading. For a counter, 0 is fine. For a power draw, 0 is accurate. Think about what should happen when things go wrong.

Building a sentence from a list of names

When you’re sending a notification, writing “Kitchen, Hallway, Desk” looks robotic. “Kitchen, Hallway, and Desk are on.” reads much better. Here is a template that does that formatting with a proper Oxford comma:

All lights that are on, in one sentence:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set lights = states.light
   | selectattr('state', 'eq', 'on')
   | map(attribute='name') | list %}
{% if lights | count == 0 %}
  No lights are on.
{% elif lights | count == 1 %}
  {{ lights[0] }} is on.
{% elif lights | count == 2 %}
  {{ lights[0] }} and {{ lights[1] }} are on.
{% else %}
  {{ lights[:-1] | join(', ') }}, and {{ lights[-1] }} are on.
{% endif %}
Result
Kitchen, Hallway, and Desk are on.

The template handles three cases: nothing, exactly one thing, or more than one. The tricky part is lights[:-1] which means “all items except the last”, and lights[-1] which means “the last item”. That lets us put “and” before the final name.

See join and map.

Picking the right word: pluralization

“1 door is open” and “3 doors are open” both need to sound right. Templates handle this with a small inline if.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set count = states.binary_sensor
   | selectattr('attributes.device_class', 'eq', 'door')
   | selectattr('state', 'eq', 'on') | list | count %}
{{ count }} door{{ 's' if count != 1 }}
{{- ' is' if count == 1 else ' are' }} open.
Result
2 doors are open.

Two small tricks there: {{ 's' if count != 1 }} adds an s when the count is not 1 (so “doors” instead of “door”), and {{ 'is' if count == 1 else 'are' }} picks the right verb.

Time differences

Home Assistant records when each state last changed, and you can reach that timestamp from any state in a template. That opens up “how long ago” questions.

How long ago did the front door change?

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
The front door changed {{
  relative_time(states.binary_sensor.front_door.last_changed)
}} ago.
Result
The front door changed 15 minutes ago.

relative_time produces nice human-readable text like “15 minutes” or “2 hours”.

Has it been more than 10 minutes?

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{
  (now() - states.binary_sensor.front_door.last_changed)
  .total_seconds() > 600
}}
Result
True

now() gives you the current moment. Subtracting two moments gives you the duration between them. .total_seconds() turns that duration into a number of seconds, and 600 is ten minutes. This pattern is handy for conditions like “only notify me if the door has been open for more than 10 minutes”.

See now and relative_time.

Formatting timestamps

Humans read dates and times in all sorts of ways. Templates use strftime (the standard date-formatting tool) to turn a timestamp into whichever shape you want.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{ now().strftime('%A %B %-d at %H:%M') }}
Result
Saturday April 4 at 14:30

The mysterious characters (%A, %B, %H, %M) are format codes. Each one stands for a piece of the date or time. You can mix them freely with plain text.

Common codes:

  • %H:%M for 24-hour time (14:30).
  • %I:%M %p for 12-hour time with AM/PM (02:30 PM).
  • %A for the full weekday name (Saturday).
  • %B for the full month name (April).
  • %Y-%m-%d for ISO-style dates (2026-04-04).

The Python documentation has the full list of format codes if you need something unusual.

Summing values across sensors

When you have several sensors measuring the same thing, summing them gives you a household total. Total power draw, total water usage, total number of people home.

Tip

A Group helper with a sum type adds up its members and exposes the result as a sensor. For energy specifically, the Energy dashboard handles totals automatically.

Total power draw across all power sensors:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{ states.sensor
   | selectattr('attributes.device_class', 'eq', 'power')
   | rejectattr('state', 'in', ['unknown', 'unavailable'])
   | map(attribute='state') | map('float') | sum | round(1) }} W
Result
427.3 W

The steps: keep only power sensors, skip offline ones, pull out their states, convert to numbers, add them up, round the total. See sum.

Parsing JSON

REST sensors, MQTT topics, and command-line sensors often return their data as JSON. from_json turns JSON text into something you can read with dots and brackets.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set data = '{"temp": 22.5, "humidity": 60}' | from_json %}
Temperature: {{ data.temp }}°C
Humidity: {{ data.humidity }}%
Result
Temperature: 22.5°C
Humidity: 60%

In real use, you’d pass a variable (like value from an MQTT payload) instead of a hardcoded piece of text.

Handling missing values

Home Assistant entities can go missing, go offline, or report unknown. Templates that don’t handle these cases produce noisy output or outright errors. Add a safety net.

With default:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{ states('sensor.might_not_exist') | default('not available') }}
Result
not available

The default filter replaces a missing value with one you choose.

With has_value:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% if has_value('sensor.outdoor_temperature') %}
  {{ states('sensor.outdoor_temperature') }}°C
{% else %}
  Temperature is not available.
{% endif %}
Result
22.5°C

Use has_value when you want a completely different branch for missing data, not only a replacement word.

Finding entities by device class

The device class tells Home Assistant what kind of thing a sensor measures: temperature, humidity, battery, power, door, motion, and many others. Filtering by device class is the most reliable way to pick out “all the X sensors” without listing them by name.

Tip

On dashboards, a grid of Tile cards shows individual entities cleanly. Templates are the right tool when you need the result as text inside an automation or notification.

All temperature sensors in the house:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% for sensor in states.sensor
   | selectattr('attributes.device_class', 'eq', 'temperature')
   | rejectattr('state', 'in', ['unknown', 'unavailable']) %}
  {{ sensor.name }}: {{ sensor.state }}°C
{% endfor %}
Result
Living room: 22.5°C
Kitchen: 23.5°C
Bedroom: 20.1°C

All open doors and windows:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{
  states.binary_sensor
  | selectattr('attributes.device_class', 'in', ['door', 'window'])
  | selectattr('state', 'eq', 'on')
  | map(attribute='name') | join(', ')
}}
Result
Front door, Kitchen window

The pattern is always the same: take a list of entities, keep only those with the device class you care about, drop the offline ones, then do whatever you need with the remaining list. Swap temperature for humidity, battery, power, or any other device class to cover a different kind of sensor.

All temperature sensors on a specific floor:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set floor_sensors = floor_entities('first_floor') %}
{% for entity in floor_sensors %}
  {% if entity.startswith('sensor.')
     and is_state_attr(entity, 'device_class', 'temperature') %}
    {{ state_attr(entity, 'friendly_name') }}: {{ states(entity) }}°C
  {% endif %}
{% endfor %}
Result
Living room: 22.5°C
Kitchen: 23.5°C

This combines floor_entities with a device-class check. Use area_entities or label_entities in the same shape when you want to filter by area or label instead.

Aggregating entities by label

LabelsLabels in Home Assistant allow grouping elements irrespective of their physical location or type. Labels can be assigned to areas, devices, entities, automations, scenes, scripts, and helpers. Labels can be used in automations and scripts as a target for actions. Labels can also be used to filter data. [Learn more] let you group entities in ways that don’t match your area/floor structure. A classic use is collecting everything you want to control together, like all TRVs or all radiators in a “Heating Zone”.

Any radiator calling for heat (boiler demand signal):

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{
  label_entities('Heating Zone')
  | select('is_state_attr', 'hvac_action', 'heating')
  | list | count > 0
}}
Result
True

This template returns True whenever at least one climate entityAn entity represents a sensor, actor, or function in Home Assistant. Entities are used to monitor physical properties or to control other entities. An entity is usually part of a device or a service. [Learn more] with the Heating Zone label has its hvac_action attribute set to heating. Drop this into a template binary sensor with device_class: heat and you have a boiler demand signal. Add it as a template trigger and you can turn the boiler on exactly when heat is needed.

Which entity changed most recently

When you have a group of similar sensors (doors, motion, windows), you sometimes want to know which one was active last. Every state tracks a last_changed timestamp, so you can sort by it.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set doors = states.binary_sensor
   | selectattr('attributes.device_class', 'eq', 'door')
   | list %}
{% set latest = doors | max(attribute='last_changed') %}
{{ latest.name }} changed {{ relative_time(latest.last_changed) }} ago.
Result
Front door changed 3 minutes ago.

Hold-last-value (ignore intermittent dropouts)

A sensor that goes unknown or unavailable for a moment can wreck your automations. A trigger-based template sensor lets you freeze the value during dropouts so downstream templates see a stable number.

AutomationAutomations in Home Assistant allow you to automatically respond to things that happen in and around your home. [Learn more]
template:
  - triggers:
      - trigger: state
        entity_id: sensor.outdoor_temperature
        not_to:
          - unknown
          - unavailable
    sensor:
      - name: "Outdoor temperature (held)"
        unique_id: outdoor_temperature_held
        state: "{{ states('sensor.outdoor_temperature') }}"
        device_class: temperature
        state_class: measurement
        unit_of_measurement: "°C"
Result
22.5 (even when the original sensor briefly goes unavailable)

The trigger uses not_to so the sensor only updates when the source reports a real value. Between updates, the held sensor keeps whatever it had last. Pair this with a long-term alarm on the original sensor if you want to be notified about extended outages.

Latch: keep a condition on until another clears it

Sometimes a condition needs to “latch” on: once it becomes true, it stays true until a different condition clears it. Heating control with hysteresis is a common example. Turn the heater on when the temperature drops below 18°, keep it on until the temperature rises above 20°.

Tip

For heating specifically, the Generic thermostat integration has hysteresis built in. For a generic two-threshold switch, see the Threshold helper.

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{
  states('sensor.temperature') | float(20) < 18
  or (this.state == 'on'
      and states('sensor.temperature') | float(20) < 20)
}}
Result
True

Reading it aloud: “the heater is on if the temperature is below 18, OR if the heater is already on AND the temperature is still below 20”. Put this in a template binary sensor; the this.state reference reads the binary sensor’s own previous value, creating the latching behavior.

Loop over a dictionary

Dictionaries come from JSON responses, entity attributes, action responses, and many other places. Iterate through one with .items():

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set data = {"temperature": 22.5, "humidity": 54, "pressure": 1013} %}
{% for key, value in data.items() %}
  {{ key }}: {{ value }}
{% endfor %}
Result
temperature: 22.5
humidity: 54
pressure: 1013

To list all attributes of an entity, call .items() on its attributes:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% for name, value in states.sensor.outdoor_temperature.attributes.items() %}
  {{ name }}: {{ value }}
{% endfor %}
Result
unit_of_measurement: °C
device_class: temperature
friendly_name: Outdoor temperature

Data navigation cheat sheet

Templates read data using three tools: dots, brackets, and iteration. Here are the common shapes you will run into.

Attribute with a dot:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{{ states.sensor.outdoor_temperature.state }}
Result
22.5

Dictionary key with a bracket:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set data = {"temp": 22.5, "unit": "°C"} %}
{{ data['temp'] }}{{ data['unit'] }}
Result
22.5°C

List item by position (starting at 0):

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set sources = ["Spotify", "Bluetooth", "TV"] %}
First: {{ sources[0] }}
Last: {{ sources[-1] }}
Result
First: Spotify
Last: TV

Nested access:

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set payload = {"sensor": {"readings": [22.5, 23.0, 22.8]}} %}
First reading: {{ payload['sensor']['readings'][0] }}
Via dots: {{ payload.sensor.readings[0] }}
Result
First reading: 22.5
Via dots: 22.5

List of dicts (common in action responses):

TemplateA template is an automation definition that can include variables for the action or data from the trigger values. This allows automations to generate dynamic actions. [Learn more]
{% set events = [
  {"name": "Meeting", "start": "09:00"},
  {"name": "Lunch", "start": "12:00"}
] %}
{% for event in events %}
  {{ event.start }}: {{ event.name }}
{% endfor %}
Result
09:00: Meeting
12:00: Lunch

When you don’t know the shape of your data, pipe it through tojson in the template editor. That gives you a JSON view of exactly what you’re working with.

Next steps

Still stuck?

The Home Assistant community is quick to help: join Discord for real-time chat, post on the community forum with your template and expected result, or share on our subreddit. The forum has thousands of community templates for all kinds of situations.

Tip

AI assistants like ChatGPT or Claude can also explain or fix templates when you describe what you want in plain language.