Home Assistant Templates: Master Jinja2 for Smarter Automations

Templates are the secret weapon of every advanced Home Assistant user. They let you create dynamic sensors, write smarter automations, send personalized notifications, and build dashboards that actually react to your home. Here's everything you need to go from copy-pasting YAML to writing your own templates with confidence.

Check Your Setup 30 Automation Ideas

What Are Templates?

Templates use a language called Jinja2 to create dynamic values. Instead of hardcoding "turn on the lights at 7 PM," you can write logic that adapts to sunrise, who's home, or whether it's a workday.

Your first template

Every template lives inside double curly braces. Here's one that shows the current temperature:

{{ states('sensor.living_room_temperature') }} °C

This pulls the live value of your temperature sensor. If it reads 21.5, the output is "21.5 °C".

Three types of template syntax

{{ ... }} for outputting values

Use this to print a value. Most common in sensors and notifications.

{% ... %} for logic (if/for/set)

Use this for conditionals and loops. Nothing gets printed, it just controls flow.

{# ... #} for comments

Use this to leave notes for yourself. Comments are stripped from the output.

Key functions you'll use constantly

states('entity_id') Returns the main state of an entity (like "on", "21.5", or "home")
state_attr('id', 'attr') Returns a specific attribute (brightness, battery, friendly_name)
is_state('id', 'value') Returns true or false. Great for conditions.
now() Current date and time. Use .hour, .weekday(), .strftime() for parts.
as_timestamp() Converts a datetime to a Unix timestamp for math.

The Template Editor: Your Best Friend

Before putting templates in your config, always test them in the Developer Tools template editor. It shows results in real time and catches errors before they break anything.

How to open it

  1. Click Developer Tools in the sidebar (the wrench icon)
  2. Click the Template tab at the top
  3. Clear the example code and start typing
  4. The right panel updates instantly with your output

Try these in the editor

Count all lights that are on:

{{ states.light | selectattr('state', 'eq', 'on') | list | count }}

Show a greeting based on time of day:

{% if now().hour < 12 %}Good morning{% elif now().hour < 18 %}Good afternoon{% else %}Good evening{% endif %}

List all open doors:

{% for entity in states.binary_sensor if 'door' in entity.entity_id and entity.state == 'on' %} - {{ entity.name }} {% endfor %}

Template Sensors: Create Your Own Data

Template sensors let you combine data from multiple entities into one clean value. They update automatically whenever the source entities change.

1. Count open windows

Add this to your configuration.yaml:

template: - sensor: - name: "Open Windows" state: > {{ states.binary_sensor | selectattr('attributes.device_class', 'eq', 'window') | selectattr('state', 'eq', 'on') | list | count }} icon: mdi:window-open unit_of_measurement: "windows"

2. Total daily energy cost

Multiply your energy usage by the current rate:

template: - sensor: - name: "Daily Energy Cost" state: > {{ (states('sensor.daily_energy') | float(0) * states('input_number.electricity_rate') | float(0.25)) | round(2) }} unit_of_measurement: "€" device_class: monetary icon: mdi:currency-eur

3. Time since last motion

Shows how many minutes ago motion was last detected:

template: - sensor: - name: "Last Motion Minutes Ago" state: > {{ ((now() - states.binary_sensor.living_room_motion .last_changed).total_seconds() / 60) | round(0) }} unit_of_measurement: "min" icon: mdi:motion-sensor

4. People at home

Lists everyone currently home:

template: - sensor: - name: "People Home" state: > {{ states.person | selectattr('state', 'eq', 'home') | map(attribute='name') | join(', ') }} icon: mdi:account-group

5. Average temperature across rooms

template: - sensor: - name: "Average Temperature" state: > {% set temps = [ states('sensor.living_room_temperature') | float(0), states('sensor.bedroom_temperature') | float(0), states('sensor.kitchen_temperature') | float(0) ] %} {{ (temps | sum / temps | count) | round(1) }} unit_of_measurement: "°C" device_class: temperature

Templates in Automations

Templates make your automations smarter. Use them in conditions, triggers, and actions to create logic that adapts instead of following rigid rules.

Template conditions

Only run the automation on weekdays when someone is home:

condition: - condition: template value_template: > {{ now().weekday() < 5 and states('group.family') == 'home' }}

Dynamic brightness based on time

Lights get dimmer as the evening progresses:

action: - service: light.turn_on target: entity_id: light.living_room data: brightness_pct: > {% if now().hour < 18 %}100 {% elif now().hour < 20 %}70 {% elif now().hour < 22 %}40 {% else %}20 {% endif %}

Template triggers

Trigger when more than 3 windows are open (uses your template sensor):

trigger: - platform: template value_template: > {{ states('sensor.open_windows') | int(0) > 3 }}

Choose actions based on who's home

Different scenes for different people:

action: - choose: - conditions: - condition: template value_template: > {{ is_state('person.alice', 'home') and is_state('person.bob', 'not_home') }} sequence: - service: scene.turn_on target: entity_id: scene.alice_mode - conditions: - condition: template value_template: > {{ is_state('person.bob', 'home') }} sequence: - service: scene.turn_on target: entity_id: scene.bob_mode

Smarter Notifications with Templates

Stop getting "Motion detected" notifications with zero context. Templates let you include exactly the information that matters.

Rich context notification

action: - service: notify.mobile_app data: title: "Home Status" message: > {{ states.light | selectattr('state', 'eq', 'on') | list | count }} lights on. {{ states('sensor.open_windows') }} windows open. Inside: {{ states('sensor.average_temperature') }}°C. {% if is_state('binary_sensor.washing_machine', 'on') %} Washing machine is still running. {% endif %}

Low battery alert with device name

action: - service: notify.mobile_app data: title: "🔋 Low Battery Warning" message: > {% for state in states.sensor if 'battery' in state.entity_id and state.state | int(100) < 20 and state.state not in ['unavailable', 'unknown'] %} {{ state.name }}: {{ state.state }}% {% endfor %}

Door left open for too long

action: - service: notify.mobile_app data: title: "🚪 Door Alert" message: > {{ trigger.to_state.name }} has been open for {{ ((now() - trigger.to_state.last_changed) .total_seconds() / 60) | round(0) }} minutes.

Templates on Your Dashboard

Custom dashboard cards with dynamic content turn a static panel into a live overview of your home.

Markdown card: Home summary

The built-in Markdown card supports full Jinja2:

type: markdown content: > ## {% if now().hour < 12 %}Good Morning ☀️{% elif now().hour < 18 %}Good Afternoon 🌤️{% else %}Good Evening 🌙{% endif %} **Lights on:** {{ states.light | selectattr('state','eq','on') | list | count }} **Temperature:** {{ states('sensor.living_room_temperature') }}°C **People home:** {{ states.person | selectattr('state','eq','home') | map(attribute='name') | join(', ') | default('Nobody') }} {% if states('sensor.open_windows') | int > 0 %} **⚠️ {{ states('sensor.open_windows') }} window(s) open** {% endif %}

Mushroom Template Card

Install Mushroom from HACS for the cleanest template cards:

type: custom:mushroom-template-card primary: "Energy today" secondary: > {{ states('sensor.daily_energy') | round(1) }} kWh (€{{ states('sensor.daily_energy_cost') }}) icon: mdi:flash icon_color: > {% if states('sensor.daily_energy') | float > 10 %}red {% elif states('sensor.daily_energy') | float > 5 %}orange {% else %}green{% endif %}

Conditional card visibility

Show cards only when relevant:

type: conditional conditions: - condition: template value: > {{ states('sensor.open_windows') | int > 0 }} card: type: custom:mushroom-template-card primary: "Close your windows!" secondary: "{{ states('sensor.open_windows') }} still open" icon: mdi:window-open-variant icon_color: red

Jinja2 Cheat Sheet

Bookmark this section. These are the filters, tests, and patterns you'll reach for over and over.

Essential filters

| float(0) Convert to number, default 0 if unavailable
| int(0) Convert to integer
| round(1) Round to 1 decimal place
| default('fallback') Fallback value if result is empty or undefined
| timestamp_custom Format a timestamp: ('%H:%M', true)
| regex_search('pattern') Test if string matches a regex pattern
| selectattr('key', 'eq', 'val') Filter a list of objects by attribute
| map(attribute='name') Extract one field from each item in a list

Date and time patterns

{{ now().strftime('%A') }} Day name (Monday, Tuesday...)
{{ now().weekday() }} 0 = Monday, 6 = Sunday
{{ (as_timestamp(now()) - as_timestamp(states.sensor.x.last_changed)) | int }} Seconds since last state change
{{ state_attr('sun.sun', 'next_rising') }} Next sunrise time

Common gotchas

⚠️

Always use float(0) or int(0) with defaults

Without a default, an unavailable sensor will crash your template.

⚠️

states() returns strings, not numbers

Always convert with | float or | int before doing math.

⚠️

Check for 'unavailable' and 'unknown'

Entities can be in these states during restarts. Filter them out in loops.

⚠️

Whitespace matters in YAML multi-line templates

Use > for folded text (joins lines) or | for literal blocks (keeps newlines). Add a minus sign (>- or |-) to strip trailing newlines.

Frequently Asked Questions

What are Home Assistant templates?

Templates use the Jinja2 language to create dynamic values. Instead of hardcoding a number or text, you write a small expression that calculates the value on the fly. For example, a template sensor can show how many lights are on, or a notification template can include the current temperature. Templates work in automations, scripts, sensors, Lovelace cards, and almost anywhere you see a text field in YAML.

Where can I test Home Assistant templates?

Go to Developer Tools in the sidebar, then click the Template tab. You get a live editor where you can write Jinja2 code and see the result immediately. It shows all available states and attributes, making it the fastest way to experiment.

What is the difference between states() and state_attr()?

The states function returns the main state of an entity as a string. The state_attr function returns a specific attribute, like brightness, battery level, or friendly_name. Use states for the primary value and state_attr when you need extra details.

Can I use templates in Lovelace dashboards?

Yes. Custom cards like Mushroom Template Card, custom:button-card, and the built-in Markdown card all support Jinja2 templates. You can show dynamic text, change icons based on state, and build cards that adapt to your home in real time.

Why does my template show "unavailable"?

Templates return "unavailable" when an entity they reference does not exist or is itself unavailable. Always add a default filter or wrap your template in an if/else check. For example, states('sensor.something') | default(0) ensures you get 0 instead of an error.

How do I create a template sensor?

Add a template sensor in your configuration.yaml under the template: key. Define a name, a state template, and optionally a unit and device class. After saving, restart Home Assistant or reload template entities from Developer Tools. Check the examples above for five ready-to-use sensors.

Ready to Build Your Smart Home?

Templates let you get the most out of Home Assistant. If you're migrating from Google Home, Alexa, or another platform, our free scan checks your current devices and shows you what's possible.

Free Smart Home Scan 30 Automation Ideas