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.
This guide will walk you through creating a new integration for Home Assistant. We’ll cover the essential files, structure, and best practices for building a high-quality integration.
Prerequisites
Before you begin, ensure you have:
- A working Home Assistant development environment
- Python 3.12 or later installed
- Familiarity with async/await patterns in Python
- Understanding of the device or service you want to integrate
Integration Structure
A basic integration consists of several key files:
homeassistant/components/your_integration/
├── __init__.py # Main integration setup
├── manifest.json # Integration metadata
├── config_flow.py # Configuration UI flow
├── const.py # Constants and configuration keys
├── sensor.py # Entity platform (example)
└── strings.json # Translations for UI
Step 1: Create the Manifest
The manifest.json file defines your integration’s metadata. This is required for Home Assistant to recognize your integration.
{
"domain": "your_integration",
"name": "Your Integration",
"codeowners": ["@your-github-username"],
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/your_integration",
"iot_class": "cloud_polling",
"requirements": ["your-library==1.0.0"],
"version": "1.0.0"
}
Key Manifest Fields
- domain: Unique identifier for your integration (lowercase, no spaces)
- name: Human-readable name displayed in the UI
- config_flow: Set to
true if your integration uses the UI configuration flow
- iot_class: How the integration communicates (see IoT class documentation)
- requirements: Python packages required by your integration
- codeowners: GitHub usernames responsible for maintaining this integration
Step 2: Define Constants
Create a const.py file to store configuration keys and constants:
"""Constants for the Your Integration integration."""
DOMAIN = "your_integration"
# Configuration keys
CONF_API_KEY = "api_key"
CONF_HOST = "host"
# Default values
DEFAULT_PORT = 8080
DEFAULT_SCAN_INTERVAL = 60
Step 3: Implement the Main Integration
The __init__.py file contains the core integration setup logic:
"""The Your Integration integration."""
from __future__ import annotations
import logging
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
# List of platforms to support
PLATFORMS: list[Platform] = [Platform.SENSOR]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Your Integration from a config entry."""
# Store an API client or coordinator in hass.data
hass.data.setdefault(DOMAIN, {})
try:
# Initialize your API client or data coordinator
# Example: api_client = YourAPIClient(entry.data[CONF_API_KEY])
# await api_client.async_connect()
# Store the client for use by platforms
hass.data[DOMAIN][entry.entry_id] = {
"client": None, # Your API client here
}
except Exception as err:
raise ConfigEntryNotReady(f"Unable to connect: {err}") from err
# Forward the setup to platforms
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
# Unload platforms
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
# Clean up stored data
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok
Key Functions
async_setup_entry
This is the main entry point for modern integrations. It:
- Initializes API clients or data coordinators
- Stores shared data in
hass.data[DOMAIN]
- Forwards setup to entity platforms
- Returns
True on success or raises ConfigEntryNotReady on failure
async_unload_entry
Cleans up when the integration is removed:
- Unloads all entity platforms
- Cleans up stored data
- Closes API connections if needed
Step 4: Create a Config Flow
The config flow handles user configuration through the UI. See the Config Entries guide for detailed information.
"""Config flow for Your Integration."""
from __future__ import annotations
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.data_entry_flow import FlowResult
from .const import CONF_API_KEY, DOMAIN
class YourIntegrationConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Your Integration."""
VERSION = 1
async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
"""Handle the initial step."""
errors = {}
if user_input is not None:
# Validate the input
try:
# Test the connection with provided credentials
# await validate_credentials(user_input[CONF_API_KEY])
# Create the config entry
return self.async_create_entry(
title="Your Integration",
data=user_input,
)
except Exception:
errors["base"] = "cannot_connect"
# Show the configuration form
return self.async_show_form(
step_id="user",
data_schema=vol.Schema({
vol.Required(CONF_API_KEY): str,
}),
errors=errors,
)
Entity platforms provide the actual functionality. For example, a sensor platform:
"""Sensor platform for Your Integration."""
from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN
async def async_setup_entry(
hass: HomeAssistant,
entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up sensor platform."""
# Get the API client from hass.data
client = hass.data[DOMAIN][entry.entry_id]["client"]
# Create sensor entities
async_add_entities([
YourSensor(client, "temperature"),
YourSensor(client, "humidity"),
])
class YourSensor(SensorEntity):
"""Representation of a Your Integration sensor."""
def __init__(self, client, sensor_type):
"""Initialize the sensor."""
self._client = client
self._sensor_type = sensor_type
self._attr_name = f"Your Integration {sensor_type}"
self._attr_unique_id = f"{DOMAIN}_{sensor_type}"
async def async_update(self) -> None:
"""Fetch new state data for the sensor."""
# Update the sensor value
# self._attr_native_value = await self._client.get_value(self._sensor_type)
pass
See the Entity Component guide for more details on creating entities.
Step 6: Add Translations
Create a strings.json file for UI translations:
{
"config": {
"step": {
"user": {
"title": "Connect to Your Integration",
"description": "Enter your API credentials",
"data": {
"api_key": "API Key"
}
}
},
"error": {
"cannot_connect": "Failed to connect, please check your API key"
}
}
}
Testing Your Integration
Before submitting your integration:
- Run tests: Ensure your integration has comprehensive test coverage
- Check code quality: Run
pylint and mypy on your code
- Test manually: Install your integration in a development Home Assistant instance
- Review the checklist: Follow the integration quality scale requirements
Best Practices
Use DataUpdateCoordinator
For integrations that poll data, use DataUpdateCoordinator to efficiently manage updates:
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
name="your_integration",
update_method=async_update_data,
update_interval=timedelta(seconds=60),
)
Handle Connection Errors
Always handle connection errors gracefully:
- Raise
ConfigEntryNotReady during setup if the device is temporarily unavailable
- Raise
ConfigEntryAuthFailed if authentication fails
- Set entity
available property based on connection status
Use Unique IDs
Always provide unique IDs for entities to enable customization:
self._attr_unique_id = f"{entry.entry_id}_{device_id}_{sensor_type}"
Follow the Quality Scale
Aim for at least Silver quality scale:
- Use config flow (no YAML configuration)
- Implement proper entity naming
- Handle errors gracefully
- Provide translations
- Include tests
Next Steps
Common Patterns
Single Config Entry Integrations
For services that should only have one configuration:
{
"single_config_entry": true
}
Virtual Integrations
For integrations that re-use another integration’s code:
{
"integration_type": "virtual"
}
Resources