Home Assistant is built on Python’s asyncio framework, making it event-driven and highly concurrent. Understanding async programming patterns is essential for writing efficient integrations.
The Event Loop
Home Assistant runs a single asyncio event loop that coordinates all async operations. All integration code must respect this event loop.
Thread Safety
The event loop runs in a specific thread. Most Home Assistant operations must run in this thread:
Reference: homeassistant/core.py:422
The @callback Decorator
The @callback decorator marks functions as safe to call from within the event loop:
Reference: homeassistant/core.py:210
When to Use @callback
- Event handlers that only do synchronous work
- State change callbacks
- Timer callbacks
- Any function called directly from the event loop
Benefits of @callback
- Performance: No task creation overhead
- Immediate execution: Runs right away, not scheduled
- Guaranteed order: Executes before other scheduled tasks
Creating Tasks
Basic Task Creation
Use async_create_task to schedule coroutines:
Reference: homeassistant/core.py:755
Eager Task Execution
By default, Home Assistant uses eager task execution for better performance:
Eager tasks can complete synchronously if they don’t await, reducing overhead.
Reference: homeassistant/util/async_.py:25
Task Types
Regular Tasks
Regular tasks block startup and shutdown:
- Home Assistant waits for these during startup
- Prevents shutdown until complete
- Use for critical initialization
Background Tasks
Background tasks don’t block startup or shutdown:
- Don’t block startup
- Automatically cancelled on shutdown
- Use for long-running monitoring
- Not waited for in
async_block_till_done
Reference: homeassistant/core.py:806
HassJob: Job Type Detection
Home Assistant uses HassJob to optimize job execution based on callable type:
Reference: homeassistant/core.py:296
Job Type Optimization
Reference: homeassistant/core.py:347
Executor Jobs
For CPU-intensive or blocking I/O operations, use the executor:
Reference: homeassistant/core.py:838
When to Use Executor
- File I/O operations
- CPU-intensive computations
- Third-party libraries that block
- Any operation that takes > 10ms
Never perform blocking operations directly in the event loop. Always use the executor for blocking code.
Async Context Managers
Timeout Management
Home Assistant provides timeout utilities:
Reference: homeassistant/core.py:414
Thread-Safe Operations
run_callback_threadsafe
Call event loop code from another thread:
Reference: homeassistant/util/async_.py:52
run_callback_threadsafe cannot be called after Home Assistant begins shutdown. It will raise RuntimeError to prevent deadlocks.
Async Patterns
Concurrent Operations
Run multiple operations concurrently:
Limited Concurrency
Limit concurrent operations to avoid overwhelming resources:
Reference: homeassistant/util/async_.py:100
Async Initialization
Async Utilities
Semaphores for Rate Limiting
Locks for Resource Protection
Shutdown Handling
Graceful Shutdown
Register shutdown handlers for cleanup:
Reference: homeassistant/core.py:1020
Cancel on Shutdown
Mark jobs as cancellable during shutdown:
Reference: homeassistant/core.py:1191
Best Practices
1. Always Use Async APIs
2. Use @callback for Synchronous Code
3. Create Tasks for Async Work in Callbacks
4. Handle Exceptions
5. Use Appropriate Task Types
- Use eager tasks - They complete faster when possible
- Batch operations - Reduce event loop overhead
- Cache expensive results - Avoid redundant async operations
- Use executor for blocking code - Keep event loop responsive
- Limit concurrency - Prevent resource exhaustion
Common Pitfalls
- Never call
asyncio.sleep(0) excessively - it’s not free
- Don’t create tasks for every tiny operation - use @callback
- Avoid blocking the event loop - use executor for blocking code
- Don’t forget to handle task exceptions
- Clean up resources in shutdown handlers
Debugging Async Issues
Enable Async Debugging
Find Blocking Code
Home Assistant logs slow operations automatically. Look for warnings about blocking tasks.