> ## 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.

# Creating Components

> Step-by-step guide to building your first Home Assistant integration

# Creating Components

This guide walks you through creating a complete Home Assistant integration from scratch. We'll build a simple integration that demonstrates all the key concepts.

## Integration Structure

Every integration follows a standard directory structure:

```
homeassistant/components/your_integration/
├── __init__.py          # Main integration file
├── manifest.json        # Integration metadata
├── config_flow.py       # UI configuration (optional)
├── const.py            # Constants
├── light.py            # Light platform (example)
├── sensor.py           # Sensor platform (example)
└── strings.json        # Translations
```

## Step 1: Create the Manifest

The `manifest.json` file defines your integration's metadata:

<Steps>
  ### Choose Your Domain

  Pick a unique domain name for your integration:

  ```json manifest.json theme={null}
  {
    "domain": "my_integration",
    "name": "My Integration",
    "codeowners": ["@yourusername"],
    "config_flow": true,
    "documentation": "https://www.home-assistant.io/integrations/my_integration",
    "integration_type": "hub",
    "iot_class": "local_polling",
    "requirements": ["my-library==1.0.0"]
  }
  ```

  ### Add Dependencies

  If your integration depends on other integrations:

  ```json theme={null}
  {
    "domain": "my_integration",
    "dependencies": ["http"],
    "after_dependencies": ["hassio"]
  }
  ```

  <Info>
    See the [Integration Manifest](/integrations/integration-manifest) guide for complete manifest options.
  </Info>
</Steps>

## Step 2: Implement the Main Component

The `__init__.py` file is the entry point for your integration.

### YAML-Based Setup (Legacy)

For simple integrations or those requiring YAML configuration:

```python __init__.py theme={null}
"""The My Integration integration."""
from __future__ import annotations

import logging
import voluptuous as vol

from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType

_LOGGER = logging.getLogger(__name__)

DOMAIN = "my_integration"

# Validation schema for configuration.yaml
CONFIG_SCHEMA = vol.Schema(
    {
        DOMAIN: vol.Schema(
            {
                vol.Required(CONF_HOST): cv.string,
            }
        )
    },
    extra=vol.ALLOW_EXTRA,
)


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
    """Set up the My Integration component."""
    conf = config.get(DOMAIN)
    if conf is None:
        return True
    
    host = conf[CONF_HOST]
    _LOGGER.info("Setting up My Integration with host: %s", host)
    
    # Store configuration data
    hass.data[DOMAIN] = {
        "host": host,
    }
    
    # Load platforms
    await hass.helpers.discovery.async_load_platform(
        "sensor", DOMAIN, {}, config
    )
    
    return True
```

### Config Entry-Based Setup (Recommended)

For modern integrations with UI configuration:

```python __init__.py theme={null}
"""The My Integration integration."""
from __future__ import annotations

import logging

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, Platform
from homeassistant.core import HomeAssistant

_LOGGER = logging.getLogger(__name__)

DOMAIN = "my_integration"

# List of platforms your integration supports
PLATFORMS = [Platform.LIGHT, Platform.SENSOR]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Set up My Integration from a config entry."""
    host = entry.data[CONF_HOST]
    
    # Initialize your API client
    # api = MyIntegrationAPI(host)
    # await api.connect()
    
    # Store the API client for platforms to use
    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.entry_id] = {
        "host": host,
        # "api": api,
    }
    
    # Forward entry 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
```

<Note>
  The `async_setup_entry` method is called when a user configures your integration through the UI. See [Config Flow](/integrations/config-flow) for implementation details.
</Note>

## Step 3: Create Platform Files

Each platform (light, sensor, etc.) lives in its own file.

### Example: Light Platform

```python light.py theme={null}
"""Light platform for My Integration."""
from __future__ import annotations

from typing import Any

from homeassistant.components.light import (
    ATTR_BRIGHTNESS,
    ColorMode,
    LightEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import DOMAIN


async def async_setup_entry(
    hass: HomeAssistant,
    entry: ConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up light platform."""
    # Get data from the main component
    data = hass.data[DOMAIN][entry.entry_id]
    
    # Create light entities
    async_add_entities([
        MyLight("Living Room Light", "light_1"),
        MyLight("Bedroom Light", "light_2"),
    ])


class MyLight(LightEntity):
    """Representation of a My Integration Light."""
    
    _attr_has_entity_name = True
    _attr_color_mode = ColorMode.BRIGHTNESS
    _attr_supported_color_modes = {ColorMode.BRIGHTNESS}
    
    def __init__(self, name: str, unique_id: str) -> None:
        """Initialize the light."""
        self._attr_name = name
        self._attr_unique_id = unique_id
        self._attr_is_on = False
        self._attr_brightness = 255
    
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn the light on."""
        if ATTR_BRIGHTNESS in kwargs:
            self._attr_brightness = kwargs[ATTR_BRIGHTNESS]
        
        self._attr_is_on = True
        # Call your API here to turn on the light
        # await self.api.turn_on(self._attr_brightness)
        
        self.async_write_ha_state()
    
    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the light off."""
        self._attr_is_on = False
        # Call your API here to turn off the light
        # await self.api.turn_off()
        
        self.async_write_ha_state()
```

### Example: Sensor Platform

```python sensor.py theme={null}
"""Sensor platform for My Integration."""
from __future__ import annotations

from homeassistant.components.sensor import (
    SensorDeviceClass,
    SensorEntity,
    SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback

from . import DOMAIN


async def async_setup_entry(
    hass: HomeAssistant,
    entry: ConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up sensor platform."""
    data = hass.data[DOMAIN][entry.entry_id]
    
    async_add_entities([
        MyTemperatureSensor("Living Room", "temp_1"),
    ])


class MyTemperatureSensor(SensorEntity):
    """Representation of a temperature sensor."""
    
    _attr_has_entity_name = True
    _attr_device_class = SensorDeviceClass.TEMPERATURE
    _attr_state_class = SensorStateClass.MEASUREMENT
    _attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS
    
    def __init__(self, name: str, unique_id: str) -> None:
        """Initialize the sensor."""
        self._attr_name = name
        self._attr_unique_id = unique_id
        self._attr_native_value = None
    
    async def async_update(self) -> None:
        """Fetch new state data for the sensor."""
        # Fetch temperature from your API
        # self._attr_native_value = await self.api.get_temperature()
        self._attr_native_value = 22.5  # Example value
```

<Tip>
  See [Entity Platforms](/integrations/entity-platforms) for detailed information on implementing different entity types.
</Tip>

## Step 4: Add Constants

Create a `const.py` file for constants:

```python const.py theme={null}
"""Constants for My Integration."""

DOMAIN = "my_integration"

# Configuration
CONF_API_KEY = "api_key"
DEFAULT_PORT = 8080

# Defaults
DEFAULT_SCAN_INTERVAL = 60
```

## Step 5: Testing Your Integration

<Steps>
  ### Install in Development Mode

  ```bash theme={null}
  # Copy to custom_components for testing
  mkdir -p config/custom_components/my_integration
  cp -r homeassistant/components/my_integration/* config/custom_components/my_integration/
  ```

  ### Add to configuration.yaml (if YAML-based)

  ```yaml configuration.yaml theme={null}
  my_integration:
    host: "192.168.1.100"
  ```

  ### Restart Home Assistant

  ```bash theme={null}
  hass --script check_config
  hass
  ```

  ### Check Logs

  Monitor logs for errors:

  ```bash theme={null}
  tail -f home-assistant.log | grep my_integration
  ```
</Steps>

## Best Practices

<Warning>
  **Never block the event loop**: Always use async methods and await I/O operations.
</Warning>

### Use Async/Await

```python theme={null}
# Good
async def async_turn_on(self):
    await self.api.turn_on()

# Bad - blocks event loop
def turn_on(self):
    self.api.turn_on()  # Blocking call
```

### Handle Errors Gracefully

```python theme={null}
async def async_update(self):
    """Update the sensor."""
    try:
        self._attr_native_value = await self.api.get_value()
    except ConnectionError:
        _LOGGER.error("Failed to connect to device")
        self._attr_available = False
    except Exception as err:
        _LOGGER.exception("Unexpected error: %s", err)
```

### Use Type Hints

```python theme={null}
from typing import Any

async def async_turn_on(self, **kwargs: Any) -> None:
    """Turn on the device."""
    pass
```

### Follow Naming Conventions

* Integration domain: lowercase with underscores (e.g., `my_integration`)
* Class names: PascalCase (e.g., `MyLight`)
* Functions: snake\_case (e.g., `async_setup_entry`)
* Private members: prefix with underscore (e.g., `_attr_name`)

## Real-World Example: Demo Integration

The Demo integration is a great reference:

```python theme={null}
# From homeassistant/components/demo/__init__.py
async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry
) -> bool:
    """Set up a config entry."""
    await hass.config_entries.async_forward_entry_setups(
        entry, COMPONENTS_WITH_CONFIG_ENTRY_DEMO_PLATFORM
    )
    return True
```

Location: `homeassistant/components/demo/__init__.py:163`

## Next Steps

<Card title="Integration Manifest" icon="file-code" href="/integrations/integration-manifest">
  Learn about all manifest.json options
</Card>

<Card title="Config Flow" icon="arrow-right-arrow-left" href="/integrations/config-flow">
  Add UI-based configuration to your integration
</Card>

<Card title="Entity Platforms" icon="cube" href="/integrations/entity-platforms">
  Deep dive into entity platform implementation
</Card>
