Working with states
Home Assistant keeps track of everything in your home as a collection of entitiesAn 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]. Each entity has a state (its current value) and often a few attributes (extra details about it). When you write a template, you are almost always reading state or attributes from one or more entities.
This page explains how to get at that information inside a template.
First, go look at your states
Before you write a single line of template, spend five minutes at Settings > Tools > States. This is where Home Assistant shows you every entity it knows about, its current state, and all of its attributes.
For example, you might see something like this for your outdoor thermometer:
Entity: sensor.outdoor_temperature
State: 22.5
Attributes:
unit_of_measurement: °C
device_class: temperature
friendly_name: Outdoor temperature
This one entity has:
- An entity ID (
sensor.outdoor_temperature). This is the name you use to look it up. - A state (
22.5). That is the entity’s main value. - Several attributes (unit of measurement, device class, friendly name). These are extra pieces of information that go along with the state.
When you write {{ states('sensor.outdoor_temperature') }}, Home Assistant looks up that exact entity ID and gives you back its state. It is that direct.
Keep the Settings > Tools > States page open in a separate browser tab while you write templates. You can search for entities, see exactly what state and attributes they have, and make sure you are spelling entity IDs correctly. It is the single most useful debugging habit you can build.
Reading a state
The states function gives you the current state of an entity. You pass it the entity ID as text.
The kitchen light is {{ states('light.kitchen') }}.
The kitchen light is on.
Every state is text
Here is something that catches everyone at least once. Home Assistant stores every entity state as text. Even when a sensor looks like it’s giving you a number, states() hands it back as a piece of text. So states('sensor.outdoor_temperature') returns the text '22.5', not the number 22.5.
Why does that matter? Because you can’t do math with text, and comparing text to a number gives surprising results. For example, '6' < '10' is False (text is sorted alphabetically, so '6' comes after '1'). If you try to do math directly, you will get an error or the wrong answer.
{{ states('sensor.outdoor_temperature') | float(0) + 5 }}
27.5
The | float(0) part converts the text to a number. The 0 is a fallback: if the conversion fails (maybe the sensor is offline), the template uses 0 instead of crashing.
Rule of thumb: whenever you do math or number comparisons on a sensor state, add | float(0) or | int(0) first. It is not optional, it is how templates work.
States have a 255 character limit
The text stored in an entity’s state can be at most 255 characters long. Home Assistant enforces this limit so the state can fit in the database and dashboards. If your template sensor needs to produce something longer (say, a list of names, a formatted table, or a long paragraph), store it in an attribute instead. Attributes don’t have the same limit.
When an entity is missing or unavailable
Home Assistant has two special state values for when things go wrong:
-
unknownmeans the entity exists but Home Assistant does not know its value right now. -
unavailablemeans the entity cannot be reached at all. Maybe a device is offline or an integration failed to load.
And if you ask for an entity that does not exist at all, you get the text unknown back as well.
Templates that depend on live values should handle these cases gracefully. Adding a number fallback (| float(0)) fixes most math problems. For decisions, use has_value (covered below).
Reading an attribute
Attributes carry extra details about an entity. A light has attributes for brightness and color. A weather entity has attributes for forecast data. A media player has attributes for the current track.
To read one, use state_attr:
The kitchen light is at {{ state_attr('light.kitchen', 'brightness') }}.
The kitchen light is at 192.
Like with states, if the entity does not exist or the attribute is not set, you get nothing back (none). For math, add a fallback:
{{ state_attr('light.kitchen', 'brightness') | int(0) }}
192
You can find an entity’s attribute names by looking at Settings > Tools > States.
Reading the state object
states only gives you the state, as text. To read more about an entity, use its state object: states. followed by the entity ID, such as states.sensor.outdoor_temperature.
The state object has the following properties:
-
state: The state, as text. -
state_with_unit: The state followed by its unit, such as22.5 °C. For sensors, the value is rounded the way Home Assistant shows it. Only available in templates. -
attributes: The attributes, such asattributes.brightness. -
name: The name of the entity. -
entity_id,domain, andobject_id: The entity ID, and its two parts. Forsensor.outdoor_temperature, the domain issensorand the object ID isoutdoor_temperature. -
last_changed,last_updated, andlast_reported: When the state last changed, when the state or attributes last changed, and when the entity last reported its state. All three are in UTC. -
context: The context of the state, which tells you what caused the change.
It is {{ states.sensor.outdoor_temperature.state_with_unit }} outside.
It is 22.5 °C outside.
If the entity doesn’t exist, the state object is none. Reading one of its properties gives an empty result, but reading further, such as .attributes.unit_of_measurement, causes an error. Check for none first, for example, {% if states.sensor.outdoor_temperature is not none %}. To read only the state or an attribute, states() and state_attr() are safer. For all details, refer to State object.
Checking a state
You can compare a state with ==, but there is a dedicated function that is cleaner and handles missing entities without surprises: is_state.
{{ is_state('light.kitchen', 'on') }}
True
This reads naturally: “is the state of light.kitchen equal to on?”. The answer is True or False.
There is a matching function for attributes, is_state_attr:
{{ is_state_attr('media_player.living_room', 'source', 'Spotify') }}
True
And has_value checks whether an entity has a usable state at all (not unknown or unavailable):
{% if has_value('sensor.outdoor_temperature') %}
It is {{ states('sensor.outdoor_temperature') }}°C outside.
{% else %}
The outdoor sensor is unavailable.
{% endif %}
It is 22.5°C outside.
Use has_value whenever you want to fall back to a friendly message instead of showing “unavailable” on a dashboard or in a notification.
Getting a list of entities
states.domain gives you every entity in that domainEach integration in Home Assistant has a unique identifier: The domain. It is often shown as the first part (before the dot) of entity IDs. (the first part of an entity ID, like light. or sensor.). This is how you count, filter, and iterate over groups of entities.
There are {{ states.light | count }} lights in total.
There are 12 lights in total.
Combine it with selectattr to filter the list down to what you care about. selectattr reads as “select entities where this attribute equals this value”:
Lights that are on:
{% for light in states.light | selectattr('state', 'eq', 'on') %}
- {{ light.name }}
{% endfor %}
Lights that are on:
- Kitchen
- Hallway
- Desk
How often templates update
Templates that update automatically, such as in a template entity or a Markdown card, render again when an entity they use changes. To keep this light, Home Assistant limits how often templates that use many entities render again:
- A template that goes through all states, such as
states | selectattr('state', 'eq', 'unavailable') | list | count, renders again at most once per minute. A template that only counts all entities, such asstates | count, isn’t limited. It renders again only when an entity is added or removed. - A template that goes through all entities of a domain, such as
states.light, renders again at most once per second. - A change to an entity that the template names directly, such as in
states('sensor.outdoor_temperature'), always makes the template render again right away.
For details, and how to avoid the limit with a trigger, refer to Rate limiting updates.
Finding entities by area, device, label, or floor
Home Assistant comes with a family of functions for finding entities grouped by how you’ve organized them:
-
area_entitiesreturns every entity in an areaAn area in Home Assistant is a logical grouping of devices and entities that represents a room or space in your home, such as the living room, kitchen, or garage. [Learn more]. -
device_entitiesreturns every entity tied to a deviceA device is a model representing a physical or logical unit that contains entities.. -
label_entitiesreturns every entity carrying a given labelLabels 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]. -
floor_entitiesreturns every entity on a floorA floor in Home Assistant is a logical grouping of areas that are meant to match the physical floors in your home. Devices & entities are not assigned to floors but to areas. Floors can be used in automations and scripts as a target for actions. For example, to turn off all the lights on the downstairs floor when you go to bed. [Learn more]. -
integration_entitiesreturns every entity created by a given integrationIntegrations connect and integrate Home Assistant with your devices, services, and more. [Learn more].
Each has matching functions for going the other way (for example, area_devices lists the devices in an area). Browse the Areas, Devices, Floors, and Labels categories in the reference for the full set.
Here is how you’d list the bedroom lights that are on:
Bedroom lights on:
{% for entity in area_entities('bedroom') %}
{% if entity.startswith('light.') and is_state(entity, 'on') %}
- {{ state_attr(entity, 'friendly_name') }}
{% endif %}
{% endfor %}
Bedroom lights on:
- Bedroom ceiling
- Bedside lamp
The this variable (in template entities)
When you write a template that defines a template entity, this refers to the entity itself. That is useful when the entity needs to read its own state or attributes without hardcoding its entity ID. For example, this sensor keeps its last value while the outdoor sensor is unavailable:
template:
- sensor:
- name: "Outdoor temperature (last known)"
unit_of_measurement: "°C"
state: >
{% if has_value('sensor.outdoor_temperature') %}
{{ states('sensor.outdoor_temperature') }}
{% else %}
{{ this.state | float(none) }}
{% endif %}
22.5 (the last value, while the outdoor sensor is unavailable)
The sensor has a unit, so its state must be a number. Before it has had a value, this.state is unknown, so float(none) turns it into none instead.
A template that reads its own entity renders again when that entity changes. If the template changes the value every time, such as a counter that adds one to its own state, it keeps updating itself. Home Assistant detects this loop, stops it, and logs a “Template loop detected” warning. To count something, use a counter helper instead.
this only exists where Home Assistant knows which entity the template belongs to. That means template entities and some automation contexts, but not the Template editor available in Settings > Tools > Template.
The trigger variable (in automations)
When an automation runs, it receives a trigger variable with details about what caused it. The fields depend on the triggerA trigger is the part of an automation that makes the automation start when something specific happens, for example, when the sun sets, a door opens, or a button is pressed. [Learn more] type; the Automation trigger variables page lists them all.
triggers:
- trigger: state
entity_id: binary_sensor.front_door
to: "on"
actions:
- action: notify.send_message
target:
entity_id: notify.my_device
data:
message: >
{{ trigger.to_state.name }} was opened at
{{ as_local(trigger.to_state.last_changed).strftime('%H:%M') }}.
Front door was opened at 14:32.
last_changed is in UTC, so the example converts it to your local time with as_local before formatting it.
Next steps
- Ready-made examples that combine these tools live on the Common template patterns page.
- The full list of state and entity functions is in the template functions reference.
- When a template does not give you what you expected, see Debugging templates.