Create an integration
Generate a new integration with the scaffold script, and learn what the smallest possible integration looks like.
The fastest way to start a new integration is the scaffold script in the core repository. It asks you a few questions and generates a working integration with a config flow, tests, and translations, so you can start with the part that is specific to your device or service.
This page is the reference for the scaffold and the parts of an integration. Want to be walked through it instead? Follow the tutorial.
Check this before you write any code.
For a new integration, the project recommends that you publish it in the Marketplace first, as a custom integration. You gain experience, and you can iterate faster. Once it has matured and has a user base, reach out to the maintainers, for example in the #core channel on Discord, to see whether it should ship built in. Publish a custom integration explains what is different outside core.
To ship built in, an integration has to meet these requirements:
- The product or service must be available for people to buy and use today. Products that are not released yet, private betas, and crowdfunding projects do not qualify.
- It must be established, with an actual user base. Home Assistant is not a marketing platform for new products.
- All communication goes through a Python library on PyPI that meets the dependency-transparency rule. See build a Python library.
Not sure where yours fits? Ask in #core before you start.
A new integration must reach the Bronze tier of the integration quality scale, and nothing more. Reviewers ask for a minimal first pull request:
- One platform only, like just
sensor. - No diagnostics, custom actions, reauthentication flow, or reconfigure flow.
- No options flow, unless the integration really cannot work without one.
- Leave the harder rules, like
dynamic-devicesandstale-devices, for later.
Everything else comes in follow up pull requests, one at a time. Big pull requests that dump a lot of code at once may be closed. Submitting a pull request explains what to put in the description.
You need a development environment for the rest of this page. Run every command from the root of your core checkout.
python3 -m script.scaffold integrationThe script asks for:
- Domain: the short, unique name of your integration, like
airgradient. It becomes the folder name and can never change. See the manifest. - Name: the name users see, like "AirGradient".
- GitHub handle: you become the first integration owner.
- PyPI package: the library that talks to your device or service, pinned with
==. Leave it blank if you do not have one yet. - IoT class: how the integration gets its data, like
local_pollingorcloud_push. - Authentication, discovery, OAuth 2.0, and integration type: these decide which kind of config flow the script generates.
Based on your answers, the script picks one of these config flow templates:
| Your answers | Template |
|---|---|
The integration type is helper |
config_flow_helper |
| Users log in with OAuth 2.0 | config_flow_oauth2 |
| Users need to authenticate, or the device is not discoverable | config_flow |
| Discoverable, no authentication | config_flow_discovery |
When it is done, the script runs hassfest, updates the requirement files, and generates the English translations from strings.json. You end up with a folder in homeassistant/components/<domain>/ and a matching test folder in tests/components/<domain>/.
The scaffold leaves TODO comments where your code goes, and a placeholder class that you replace with your library. Search for TODO before you open a pull request.
The same script adds pieces to an integration that already exists. Run it with the name of a template, and it asks which integration to change:
| Template | Adds |
|---|---|
config_flow |
A config flow with a form |
config_flow_discovery |
A config flow for discoverable devices without authentication |
config_flow_oauth2 |
A config flow that uses OAuth 2.0 |
config_flow_helper |
A config flow for a helper |
device_trigger |
Device triggers |
device_condition |
Device conditions |
device_action |
Device actions |
reproduce_state |
Reproduce state support |
significant_change |
Significant change support |
backup |
A backup platform |
For example, to add device triggers:
python3 -m script.scaffold device_triggerThe scaffold generates more than the bare minimum. It helps to know what is required, so you know what is optional. An integration needs two things:
- A
manifest.jsonwith at least adomainand aname. - An
__init__.pywith a setup function that returns whether setup succeeded.
{
"domain": "hello_state",
"name": "Hello, state!"
}from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType
DOMAIN = "hello_state"
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the integration."""
hass.states.async_set("hello_state.world", "Paulus")
return TrueThis integration loads when hello_state: is in configuration.yaml. That is fine to learn from, but integrations that talk to devices or services are set up from the UI with a config flow, not from YAML. See YAML configuration for the rules.
Your integration provides entities by adding a platform for each entity type it supports. To provide a light, add light.py. To provide a sensor, add sensor.py. Each platform file has an async_setup_entry function that creates the entities, and your integration forwards its config entry to them:
from homeassistant.const import Platform
PLATFORMS = [Platform.LIGHT, Platform.SENSOR]
async def async_setup_entry(hass: HomeAssistant, entry: MyConfigEntry) -> bool:
"""Set up the integration from a config entry."""
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return TrueSee config entries for the full setup and unload flow, and entities and platforms for what each entity type supports.
Your integration never talks to a device or service directly. All protocol and API code lives in a separate Python library, published on PyPI, which your integration lists as a requirement. This keeps Home Assistant maintainable, and lets the rest of the Python community use that code too.
The integration translates between that library and Home Assistant: it sets up the library, turns its data into entities, and turns user actions into library calls. Build a Python library explains how to write one.
Integrations in the core repository live in homeassistant/components/. A custom integration lives in the custom_components/ folder of a user's configuration directory. They are built the same way, with two differences in the manifest: a custom integration needs a version, and its documentation points to its own documentation, not to home-assistant.io.
The example-custom-config repository has small example integrations, such as one that sets up platforms from a config entry. They are custom integrations, so they include a version.
- Build a complete integration step by step in the tutorial.
- Look at the file structure of an integration.
- Fill in the manifest.
- Build the config flow and get the data with a coordinator.
- Check the Bronze tier rules of the quality scale.