Skip to main content
Home Assistant is built on a robust event-driven architecture that enables flexible home automation. The core consists of several interconnected components that work together to manage state, process events, and execute services.

Core Components

The architecture is centered around four primary systems:

HomeAssistant Core

The central hub that coordinates all operations and manages the event loop

Event System

Event-driven communication enabling loose coupling between components

State Machine

Centralized storage and management of all entity states

Service Registry

Registration and execution of callable services across domains

Architectural Principles

Event-Driven Design

Home Assistant uses an event-driven architecture where components communicate through events rather than direct function calls. This provides:
  • Loose coupling between components
  • Asynchronous operation for better performance
  • Extensibility allowing easy addition of new features

Async-First Approach

The entire core runs on Python’s asyncio event loop, providing:
homeassistant/core.py
class HomeAssistant:
    def __init__(self, config_dir: str) -> None:
        """Initialize new Home Assistant object."""
        self.data = HassDict()
        self.loop = asyncio.get_running_loop()
        self.bus = EventBus(self)
        self.services = ServiceRegistry(self)
        self.states = StateMachine(self.bus, self.loop)
All core operations are designed to be non-blocking, allowing thousands of entities and automations to run concurrently without performance degradation.

Component Interaction Flow

1

State Change Occurs

A device or integration updates the state of an entity through the State Machine.
2

Event Fired

The State Machine fires a state_changed event on the Event Bus.
3

Listeners Notified

All registered listeners (automations, scripts, integrations) receive the event.
4

Service Calls Executed

Listeners may call services through the Service Registry to trigger actions.

Core State Lifecycle

Home Assistant progresses through several states during its lifecycle:
homeassistant/core.py
class CoreState(enum.Enum):
    """Represent the current state of Home Assistant."""
    
    not_running = "NOT_RUNNING"
    starting = "STARTING"
    running = "RUNNING"
    stopping = "STOPPING"
    final_write = "FINAL_WRITE"
    stopped = "STOPPED"

Startup Sequence

The bootstrap process (defined in homeassistant/bootstrap.py) follows a staged approach:
Stage 0: Core integrations (logging, frontend, recorder)
Stage 1: Discovery integrations (bluetooth, DHCP, SSDP, USB)
Stage 2: All remaining integrations from configuration

Thread Safety

Home Assistant enforces strict thread safety rules:
homeassistant/core.py
def verify_event_loop_thread(self, what: str) -> None:
    """Report and raise if we are not running in the event loop thread."""
    if self.loop_thread_id != threading.get_ident():
        from .helpers import frame
        frame.report_non_thread_safe_operation(what)
All state changes, event firing, and service calls must occur within the event loop thread. Use run_callback_threadsafe when calling from external threads.

Job Execution System

Home Assistant uses a sophisticated job execution system to handle different types of callables:
homeassistant/core.py
class HassJobType(enum.Enum):
    """Represent a job type."""
    
    Coroutinefunction = 1  # async def functions
    Callback = 2           # @callback decorated functions
    Executor = 3           # Regular blocking functions
  • Coroutine functions: Run directly in the event loop
  • Callbacks: Executed immediately without task creation overhead
  • Executor jobs: Run in a thread pool to avoid blocking

Context Tracking

Every event, state change, and service call is associated with a Context:
homeassistant/core.py
class Context:
    """The context that triggered something."""
    
    def __init__(self, user_id: str | None = None, 
                 parent_id: str | None = None,
                 id: str | None = None) -> None:
        self.id = id or ulid_now()
        self.user_id = user_id
        self.parent_id = parent_id
Contexts enable:
  • Tracking which user triggered an action
  • Following chains of automation executions
  • Debugging complex automation flows

Performance Optimizations

The architecture includes several performance optimizations:
Eager task creation: Tasks start executing immediately without scheduler overhead
Cached properties: Expensive computations are cached using @cached_property
Direct dict access: Internal code bypasses public APIs for speed
Event filtering: Listeners can filter events before job creation

Next Steps

Explore each core component in detail:

Build docs developers (and LLMs) love