Skip to main content
The State Machine is Home Assistant’s central storage system for all entity states. It maintains a complete picture of your home automation system’s current state and efficiently tracks changes over time.

StateMachine Overview

The StateMachine class provides thread-safe access to entity states:
homeassistant/core.py
The StateMachine maintains two references to state storage: _states (the States container) and _states_data (direct dict access) for performance optimization.

State Object Structure

Each entity’s state is represented by a State object:
homeassistant/core.py

State Components

entity_id

Unique identifier in format domain.object_id

state

String representing the current state value

attributes

Dictionary of additional state metadata

timestamps

Three timestamps tracking different types of changes

Setting States

Basic State Setting

Advanced State Setting

homeassistant/core.py

Parameters

  • entity_id: Entity identifier (automatically lowercased)
  • new_state: New state value (converted to string)
  • attributes: Optional dictionary of attributes
  • force_update: Force last_changed update even if state unchanged
  • context: Context tracking the change origin
  • timestamp: Override the timestamp (for replay scenarios)
1

Entity ID Normalized

The entity_id is converted to lowercase for consistency.
2

State Validated

The state string length is validated (max 255 characters).
3

Old State Retrieved

The existing state is retrieved to compare changes.
4

State Object Created

A new State object is created with the updated values.
5

Event Fired

Either EVENT_STATE_CHANGED or EVENT_STATE_REPORTED is fired.

State Change Detection

The state machine intelligently detects different types of state changes:
homeassistant/core.py

Event Types

EVENT_STATE_REPORTED was introduced to allow tracking of entity updates even when the state value doesn’t change. This is useful for detecting that a device is still communicating.

Reading States

Getting a Single State

Checking State Value

Getting All States

Getting Entity IDs

Removing States

Remove an entity from the state machine:
Removing a state fires a STATE_CHANGED event with new_state=None. This signals to listeners that the entity no longer exists.

State Reservations

Reserve an entity_id before creating it to prevent race conditions:
Reservations prevent multiple components from trying to create the same entity_id simultaneously, which could cause data corruption or unexpected behavior.

States Container

The States class provides efficient domain-based indexing:
homeassistant/core.py
The domain index enables O(1) lookups when retrieving all entities of a specific domain, making operations like hass.states.async_all("light") very fast even with thousands of entities.

State Attributes

Attributes provide additional context about an entity’s state:

Attribute Best Practices

  • Use standard attribute names defined in homeassistant.const
  • Keep attribute values JSON-serializable
  • Don’t store large data structures in attributes
  • Use ReadOnlyDict to prevent accidental modification

Timestamp Semantics

The State object maintains three timestamps:

last_changed

Updated when the state value changes:

last_updated

Updated when the state value or attributes change:

last_reported

Updated every time async_set is called, even if nothing changed:
Use last_reported to detect if a device is still communicating, even when its state hasn’t changed. This is particularly useful for detecting unavailable devices.

State Serialization

States can be serialized for storage or API responses:

Compressed State Format

homeassistant/core.py

Performance Optimizations

The state machine includes several optimizations:
Direct dict access: Internal code uses _states_data to bypass container overhead
Cached properties: Expensive computations are cached with @cached_property
Domain indexing: O(1) lookups for domain-filtered queries
Timestamp caching: Timestamp conversions are cached on State objects

Best Practices

  1. Use lowercase entity_ids: The state machine automatically lowercases, but it’s faster if you do it yourself
  2. Preserve contexts: Pass contexts through automation chains for proper tracking
  3. Validate before setting: Check entity_id format before calling async_set
  4. Use async methods: Always prefer async_set over set when in the event loop
  5. Handle None states: When listening to state changes, old_state or new_state may be None