> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/home-assistant/core/llms.txt
> Use this file to discover all available pages before exploring further.

# State Management

> Understanding and managing entity state in Home Assistant Core

The state machine is the heart of Home Assistant. It tracks the current state of all entities and fires events when states change. Understanding state management is crucial for building reliable integrations.

## The State Machine

The `StateMachine` class manages all entity states in Home Assistant:

```python theme={null}
from homeassistant.core import HomeAssistant

def example(hass: HomeAssistant):
    # Access the state machine
    state_machine = hass.states
    
    # Get current state
    state = state_machine.get("light.living_room")
    
    # Set state
    state_machine.async_set(
        "sensor.temperature",
        "23.5",
        {"unit_of_measurement": "°C"}
    )
```

Reference: `homeassistant/core.py:2058`

## State Objects

### State Structure

The `State` object contains complete entity information:

```python theme={null}
from homeassistant.core import State

state = hass.states.get("light.living_room")

# Core properties
entity_id: str = state.entity_id          # "light.living_room"
domain: str = state.domain                # "light"
object_id: str = state.object_id          # "living_room"
state_value: str = state.state            # "on", "off", etc.

# Metadata
attributes: dict = state.attributes       # Extra data
context: Context = state.context          # Who/what caused change

# Timestamps
last_changed: datetime = state.last_changed    # When state changed
last_updated: datetime = state.last_updated    # When state/attrs updated
last_reported: datetime = state.last_reported  # When last written
```

Reference: `homeassistant/core.py:1718`

### State vs Attributes

* **State**: The primary status (on/off, open/closed, numeric value)
* **Attributes**: Additional context (brightness, color, temperature)

```python theme={null}
# Light state
state = "on"  # State is simple string
attributes = {
    "brightness": 255,
    "color_temp": 370,
    "friendly_name": "Living Room Light",
    "supported_features": 43
}
```

## Reading State

### Get Single State

```python theme={null}
from homeassistant.core import State

# Get state (returns None if not found)
state = hass.states.get("light.bedroom")

if state is None:
    _LOGGER.warning("Entity not found")
else:
    _LOGGER.info(f"Light is {state.state}")
    brightness = state.attributes.get("brightness")
```

Reference: `homeassistant/core.py:2142`

### Check State Value

```python theme={null}
# Quick check if entity has specific state
if hass.states.is_state("light.bedroom", "on"):
    _LOGGER.info("Bedroom light is on")
```

Reference: `homeassistant/core.py:2151`

### Get All States

```python theme={null}
# Get all states
all_states = hass.states.async_all()

# Filter by domain
all_lights = hass.states.async_all("light")
all_sensors = hass.states.async_all(["sensor", "binary_sensor"])

# Count entities
light_count = hass.states.async_entity_ids_count("light")
```

Reference: `homeassistant/core.py:2124`

### Get Entity IDs

```python theme={null}
# Get all entity IDs
all_entity_ids = hass.states.async_entity_ids()

# Filter by domain
light_ids = hass.states.async_entity_ids("light")
climate_switch_ids = hass.states.async_entity_ids(["climate", "switch"])
```

Reference: `homeassistant/core.py:2081`

## Setting State

### Basic State Update

```python theme={null}
from homeassistant.core import HomeAssistant

@callback
def update_sensor(hass: HomeAssistant):
    """Update sensor state."""
    hass.states.async_set(
        "sensor.my_sensor",
        "42",
        {
            "unit_of_measurement": "units",
            "device_class": "temperature",
            "friendly_name": "My Sensor"
        }
    )
```

Reference: `homeassistant/core.py:2247`

### State Update with Context

Context tracks what triggered the state change:

```python theme={null}
from homeassistant.core import Context

# Create context (e.g., for automation)
context = Context(user_id="automation.turn_on_lights")

hass.states.async_set(
    "light.living_room",
    "on",
    {"brightness": 255},
    context=context
)
```

Reference: `homeassistant/core.py:1213`

### Force Update

Force a state change event even if state hasn't changed:

```python theme={null}
# Force update - fires event even if state/attributes unchanged
hass.states.async_set(
    "sensor.refresh",
    state.state,
    state.attributes,
    force_update=True  # Always fire EVENT_STATE_CHANGED
)
```

Reference: `homeassistant/core.py:2247`

## State Change Events

### EVENT\_STATE\_CHANGED

Fired when state or attributes change:

```python theme={null}
from homeassistant.const import EVENT_STATE_CHANGED
from homeassistant.core import Event, EventStateChangedData

@callback
def handle_state_change(event: Event[EventStateChangedData]) -> None:
    """Handle state change."""
    entity_id = event.data["entity_id"]
    old_state = event.data["old_state"]  # None if new entity
    new_state = event.data["new_state"]  # None if removed
    
    if old_state is None:
        _LOGGER.info(f"New entity: {entity_id}")
    elif new_state is None:
        _LOGGER.info(f"Removed entity: {entity_id}")
    else:
        _LOGGER.info(
            f"{entity_id}: {old_state.state} -> {new_state.state}"
        )

hass.bus.async_listen(EVENT_STATE_CHANGED, handle_state_change)
```

Reference: `homeassistant/core.py:137`

### EVENT\_STATE\_REPORTED

Fired when state is updated but unchanged:

```python theme={null}
from homeassistant.const import EVENT_STATE_REPORTED
from homeassistant.core import Event, EventStateReportedData

@callback
def handle_state_reported(event: Event[EventStateReportedData]) -> None:
    """Handle state report (no change)."""
    entity_id = event.data["entity_id"]
    new_state = event.data["new_state"]
    last_reported = event.data["last_reported"]
    old_last_reported = event.data["old_last_reported"]
    
    _LOGGER.debug(
        f"{entity_id} reported at {last_reported}, still {new_state.state}"
    )
```

Reference: `homeassistant/core.py:147`

## State Reservations

### Reserve Entity ID

Reserve an entity ID before creating the entity:

```python theme={null}
@callback
def reserve_entity(hass: HomeAssistant, entity_id: str):
    """Reserve entity ID to prevent conflicts."""
    # Reserve the ID
    hass.states.async_reserve(entity_id)
    
    # Now safe to create entity
    # ... entity setup code ...
    
    # Finally set initial state
    hass.states.async_set(entity_id, "unknown", {})
```

Reference: `homeassistant/core.py:2222`

### Check Availability

```python theme={null}
if hass.states.async_available("light.new_light"):
    # Entity ID is available
    hass.states.async_reserve("light.new_light")
else:
    _LOGGER.error("Entity ID already in use")
```

Reference: `homeassistant/core.py:2239`

## Removing State

### Remove Entity State

```python theme={null}
# Remove entity from state machine
removed = hass.states.async_remove("sensor.old_sensor")

if removed:
    _LOGGER.info("Entity removed")
else:
    _LOGGER.warning("Entity not found")
```

This fires `EVENT_STATE_CHANGED` with `new_state=None`.

Reference: `homeassistant/core.py:2169`

## State Persistence

### Internal State Format

States are internally compressed for efficiency:

```python theme={null}
# Compressed state format (used in websocket and recorder)
compressed = {
    "s": "on",              # state
    "a": {"brightness": 255},  # attributes
    "c": "context_id",      # context (or full dict)
    "lc": 1234567890.0,     # last_changed timestamp
    "lu": 1234567891.0,     # last_updated (optional if == lc)
}
```

Reference: `homeassistant/core.py:1708`

## Advanced State Patterns

### State Validation

```python theme={null}
from homeassistant.exceptions import InvalidStateError
from homeassistant.core import validate_state

try:
    # State must be <= 255 characters
    validated = validate_state(user_input)
    hass.states.async_set("sensor.test", validated, {})
except InvalidStateError as err:
    _LOGGER.error("Invalid state: %s", err)
```

Reference: `homeassistant/core.py:200`

### Entity ID Validation

```python theme={null}
from homeassistant.core import valid_entity_id, split_entity_id

# Validate format
if not valid_entity_id("light.living_room"):
    raise ValueError("Invalid entity ID")

# Split into domain and object_id  
domain, object_id = split_entity_id("light.living_room")
# domain = "light", object_id = "living_room"
```

Reference: `homeassistant/core.py:192`, `homeassistant/core.py:171`

### Tracking Multiple Entities

```python theme={null}
from homeassistant.helpers.event import async_track_state_change_event

@callback
def handle_changes(event: Event) -> None:
    """Handle state changes for tracked entities."""
    entity_id = event.data["entity_id"]
    new_state = event.data["new_state"]
    _LOGGER.info(f"{entity_id} changed to {new_state.state}")

# Track multiple entities efficiently
remove = async_track_state_change_event(
    hass,
    ["light.living_room", "light.bedroom", "light.kitchen"],
    handle_changes
)

# Clean up
remove()
```

Reference: `homeassistant/helpers/event.py:309`

### State Attribute Updates

Update only attributes without changing state:

```python theme={null}
# Get current state
current = hass.states.get("climate.thermostat")

if current:
    # Update attributes while keeping same state
    new_attrs = dict(current.attributes)
    new_attrs["temperature"] = 22
    
    hass.states.async_set(
        current.entity_id,
        current.state,  # Same state
        new_attrs       # Updated attributes
    )
    # last_changed stays same, last_updated updates
```

## State Machine Indexes

The state machine maintains indexes for performance:

### Domain Index

```python theme={null}
# Internally indexed by domain for fast lookups
class States(UserDict):
    def __init__(self):
        self._domain_index: dict[str, dict[str, State]] = {}
    
    # Fast domain filtering
    def domain_states(self, domain: str):
        return self._domain_index.get(domain, {}).values()
```

Reference: `homeassistant/core.py:2016`

## Best Practices

### 1. Use Async Methods

Always use async methods in the event loop:

```python theme={null}
# GOOD
@callback
def my_callback():
    state = hass.states.get("light.test")  # Synchronous read OK
    hass.states.async_set("light.test", "on", {})  # Async write

# BAD
def blocking_function():
    hass.states.set("light.test", "on", {})  # Blocks event loop
```

### 2. Check for None

Always handle missing states:

```python theme={null}
state = hass.states.get("sensor.might_not_exist")
if state is None:
    _LOGGER.warning("Sensor not found")
    return

value = float(state.state)
```

### 3. Use Appropriate Tracking

Use helpers instead of manual event listening:

```python theme={null}
# GOOD - Optimized tracking
from homeassistant.helpers.event import async_track_state_change_event

remove = async_track_state_change_event(
    hass, ["light.test"], callback
)

# BAD - Manual tracking is slower
remove = hass.bus.async_listen(
    EVENT_STATE_CHANGED,
    lambda event: callback(event) if event.data["entity_id"] == "light.test" else None
)
```

### 4. Minimize State Updates

Only update when necessary:

```python theme={null}
# Check before updating
current = hass.states.get("sensor.test")
if current is None or current.state != new_value:
    hass.states.async_set("sensor.test", new_value, attrs)
```

### 5. Use Context

Provide context for state changes:

```python theme={null}
context = Context(
    user_id=automation.entity_id,
    parent_id=trigger_context.id
)

hass.states.async_set(
    "light.automated",
    "on",
    {},
    context=context
)
```

## Performance Considerations

1. **State reads are fast** - Direct dictionary lookup
2. **State writes fire events** - Consider batch updates
3. **Domain filtering is optimized** - Uses internal index
4. **Attributes are immutable** - Uses ReadOnlyDict for safety

## Common Pitfalls

<Warning>
  * Don't modify `state.attributes` directly (it's read-only)
  * Don't assume entities exist (always check for None)
  * Don't create excessive state updates (batch when possible)
  * Don't store large data in attributes (use data registry)
  * Clean up entity states when removing entities
</Warning>

## State Machine Lifecycle

```python theme={null}
# 1. Reserve entity ID (optional, prevents races)
hass.states.async_reserve("sensor.new")

# 2. Create initial state
hass.states.async_set("sensor.new", "unknown", {})

# 3. Update state over time
hass.states.async_set("sensor.new", "23.5", {"unit": "°C"})

# 4. Remove when done
hass.states.async_remove("sensor.new")
```

## Related Resources

* [Event Handling](./event-handling)
* [Async Programming](./async-programming)
* [Service Registration](./service-registration)
