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

# Entity Platforms

> Implementing entity platforms for lights, sensors, switches, and more

# Entity Platforms

Entity platforms are the core building blocks that represent controllable or observable elements in Home Assistant. This guide covers implementing different entity types for your integration.

## Platform Architecture

Platforms are separate Python modules within your integration, one for each entity type you support:

```
homeassistant/components/your_integration/
├── __init__.py
├── manifest.json
├── light.py          # Light platform
├── sensor.py         # Sensor platform
├── switch.py         # Switch platform
└── climate.py        # Climate platform
```

## Available Platforms

From `homeassistant.const.Platform`:

* **light** - Lights
* **switch** - Switches
* **sensor** - Sensors
* **binary\_sensor** - Binary sensors
* **climate** - Climate devices (thermostats)
* **cover** - Covers (blinds, garage doors)
* **fan** - Fans
* **lock** - Locks
* **media\_player** - Media players
* **camera** - Cameras
* **vacuum** - Vacuum cleaners
* **water\_heater** - Water heaters
* And many more...

## Basic Platform Structure

Every platform follows the same pattern:

```python theme={null}
"""Platform implementation."""
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback


async def async_setup_entry(
    hass: HomeAssistant,
    entry: ConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up the platform from a config entry."""
    # Get data from main integration
    # Create entities
    # Add entities to Home Assistant
    pass
```

## Entity Base Class

All entities inherit from `Entity` (from `homeassistant/helpers/entity.py`):

```python theme={null}
from homeassistant.helpers.entity import Entity

class MyEntity(Entity):
    """Representation of my entity."""
    
    _attr_has_entity_name = True
    _attr_name = None
    
    def __init__(self) -> None:
        """Initialize the entity."""
        self._attr_unique_id = "unique_id_here"
```

<Info>
  Using `_attr_*` attributes is the modern approach. They're automatically exposed as properties.
</Info>

## Light Platform

### Basic Light Implementation

```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 stored data
    data = hass.data[DOMAIN][entry.entry_id]
    
    # Create light entities
    async_add_entities([
        MyLight("Living Room", "light_1"),
        MyLight("Bedroom", "light_2"),
    ])


class MyLight(LightEntity):
    """Representation of a 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
        self.async_write_ha_state()
    
    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the light off."""
        self._attr_is_on = False
        self.async_write_ha_state()
```

### Color Support

For RGB/RGBW lights:

```python theme={null}
from homeassistant.components.light import (
    ATTR_HS_COLOR,
    ATTR_RGBW_COLOR,
    ColorMode,
    LightEntity,
)

class MyRGBLight(LightEntity):
    """RGB light."""
    
    _attr_color_mode = ColorMode.HS
    _attr_supported_color_modes = {ColorMode.HS}
    
    def __init__(self) -> None:
        """Initialize."""
        self._attr_hs_color = (0, 0)
    
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn on."""
        if ATTR_HS_COLOR in kwargs:
            self._attr_hs_color = kwargs[ATTR_HS_COLOR]
        
        self._attr_is_on = True
        self.async_write_ha_state()
```

Real example from Demo integration (`homeassistant/components/demo/light.py:94`):

```python theme={null}
class DemoLight(LightEntity):
    """Representation of a demo light."""
    
    _attr_has_entity_name = True
    _attr_name = None
    _attr_should_poll = False
```

## Sensor Platform

### Basic Sensor

```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."""
    async_add_entities([
        MyTemperatureSensor("Living Room", "temp_1"),
        MyHumiditySensor("Living Room", "humidity_1"),
    ])


class MyTemperatureSensor(SensorEntity):
    """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."""
        # Fetch from API
        self._attr_native_value = 22.5
```

<Note>
  **Device Class**: Indicates the type of sensor (temperature, humidity, etc.)

  **State Class**: For statistics and long-term data (`measurement`, `total`, `total_increasing`)

  **Native Value**: The sensor's value in its native unit
</Note>

### Statistics and Units

```python theme={null}
class MyEnergySensor(SensorEntity):
    """Energy sensor with statistics."""
    
    _attr_device_class = SensorDeviceClass.ENERGY
    _attr_state_class = SensorStateClass.TOTAL_INCREASING
    _attr_native_unit_of_measurement = UnitOfEnergy.KILO_WATT_HOUR
    _attr_suggested_display_precision = 2
```

Home Assistant automatically handles:

* Unit conversion
* Statistics collection
* Long-term storage
* Graphing

## Switch Platform

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

from typing import Any

from homeassistant.components.switch import SwitchEntity
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 switch platform."""
    async_add_entities([
        MySwitch("Outlet 1", "switch_1"),
    ])


class MySwitch(SwitchEntity):
    """Representation of a Switch."""
    
    _attr_has_entity_name = True
    
    def __init__(self, name: str, unique_id: str) -> None:
        """Initialize the switch."""
        self._attr_name = name
        self._attr_unique_id = unique_id
        self._attr_is_on = False
    
    async def async_turn_on(self, **kwargs: Any) -> None:
        """Turn the switch on."""
        self._attr_is_on = True
        self.async_write_ha_state()
    
    async def async_turn_off(self, **kwargs: Any) -> None:
        """Turn the switch off."""
        self._attr_is_on = False
        self.async_write_ha_state()
```

## Binary Sensor Platform

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

from homeassistant.components.binary_sensor import (
    BinarySensorDeviceClass,
    BinarySensorEntity,
)
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 binary sensor platform."""
    async_add_entities([
        MyMotionSensor("Living Room", "motion_1"),
        MyDoorSensor("Front Door", "door_1"),
    ])


class MyMotionSensor(BinarySensorEntity):
    """Motion sensor."""
    
    _attr_has_entity_name = True
    _attr_device_class = BinarySensorDeviceClass.MOTION
    
    def __init__(self, name: str, unique_id: str) -> None:
        """Initialize the sensor."""
        self._attr_name = name
        self._attr_unique_id = unique_id
        self._attr_is_on = False
    
    async def async_update(self) -> None:
        """Update the sensor."""
        # Fetch from API
        self._attr_is_on = False  # No motion


class MyDoorSensor(BinarySensorEntity):
    """Door sensor."""
    
    _attr_has_entity_name = True
    _attr_device_class = BinarySensorDeviceClass.DOOR
    
    def __init__(self, name: str, unique_id: str) -> None:
        """Initialize the sensor."""
        self._attr_name = name
        self._attr_unique_id = unique_id
        self._attr_is_on = False  # Closed
```

## Climate Platform

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

from typing import Any

from homeassistant.components.climate import (
    ATTR_TEMPERATURE,
    ClimateEntity,
    ClimateEntityFeature,
    HVACMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, 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 climate platform."""
    async_add_entities([
        MyThermostat("Living Room", "thermostat_1"),
    ])


class MyThermostat(ClimateEntity):
    """Thermostat entity."""
    
    _attr_has_entity_name = True
    _attr_temperature_unit = UnitOfTemperature.CELSIUS
    _attr_hvac_modes = [HVACMode.OFF, HVACMode.HEAT, HVACMode.COOL, HVACMode.AUTO]
    _attr_supported_features = (
        ClimateEntityFeature.TARGET_TEMPERATURE
        | ClimateEntityFeature.TURN_ON
        | ClimateEntityFeature.TURN_OFF
    )
    
    def __init__(self, name: str, unique_id: str) -> None:
        """Initialize the thermostat."""
        self._attr_name = name
        self._attr_unique_id = unique_id
        self._attr_hvac_mode = HVACMode.OFF
        self._attr_current_temperature = 20.0
        self._attr_target_temperature = 22.0
    
    async def async_set_temperature(self, **kwargs: Any) -> None:
        """Set new target temperature."""
        if (temperature := kwargs.get(ATTR_TEMPERATURE)) is not None:
            self._attr_target_temperature = temperature
            self.async_write_ha_state()
    
    async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
        """Set new target hvac mode."""
        self._attr_hvac_mode = hvac_mode
        self.async_write_ha_state()
```

## Entity Features

### Unique ID

Every entity should have a unique ID:

```python theme={null}
def __init__(self) -> None:
    """Initialize."""
    self._attr_unique_id = f"{device_id}_{entity_type}"
```

<Warning>
  Unique IDs must be stable across restarts and unique across all integrations.
</Warning>

### Device Info

Group entities under devices:

```python theme={null}
from homeassistant.helpers.device_registry import DeviceInfo

class MyEntity(SensorEntity):
    """Entity with device info."""
    
    def __init__(self) -> None:
        """Initialize."""
        self._attr_device_info = DeviceInfo(
            identifiers={(DOMAIN, "device_id")},
            name="My Device",
            manufacturer="My Company",
            model="Model X",
            sw_version="1.0.0",
        )
```

### Availability

Indicate when entities are unavailable:

```python theme={null}
async def async_update(self) -> None:
    """Update the entity."""
    try:
        data = await self.api.get_data()
        self._attr_native_value = data
        self._attr_available = True
    except ConnectionError:
        self._attr_available = False
```

### Entity Category

Categorize entities:

```python theme={null}
from homeassistant.const import EntityCategory

class MyDiagnosticSensor(SensorEntity):
    """Diagnostic sensor."""
    
    _attr_entity_category = EntityCategory.DIAGNOSTIC
```

Categories:

* `CONFIG` - Configuration entities
* `DIAGNOSTIC` - Diagnostic information
* `None` - Regular entities (default)

### State Updates

<Steps>
  ### Push Updates

  For entities that receive push updates:

  ```python theme={null}
  class MyPushEntity(SensorEntity):
      """Entity with push updates."""
      
      _attr_should_poll = False
      
      async def async_added_to_hass(self) -> None:
          """Register callbacks."""
          self.api.register_callback(self._handle_update)
      
      def _handle_update(self, data: Any) -> None:
          """Handle push update."""
          self._attr_native_value = data
          self.async_write_ha_state()
  ```

  ### Polling Updates

  For entities that need polling:

  ```python theme={null}
  class MyPollingEntity(SensorEntity):
      """Entity with polling."""
      
      _attr_should_poll = True
      
      async def async_update(self) -> None:
          """Poll for updates."""
          self._attr_native_value = await self.api.get_value()
  ```
</Steps>

## Platform Setup Methods

From `homeassistant/helpers/entity_platform.py:96`:

```python theme={null}
class EntityPlatformModule(Protocol):
    """Protocol type for entity platform modules."""
    
    async def async_setup_platform(
        self,
        hass: HomeAssistant,
        config: ConfigType,
        async_add_entities: AddEntitiesCallback,
        discovery_info: DiscoveryInfoType | None = None,
    ) -> None:
        """Set up an integration platform async."""
    
    async def async_setup_entry(
        self,
        hass: HomeAssistant,
        entry: ConfigEntry,
        async_add_entities: AddConfigEntryEntitiesCallback,
    ) -> None:
        """Set up an integration platform from a config entry."""
```

<Note>
  Use `async_setup_entry` for modern config-entry-based integrations.

  Use `async_setup_platform` only for legacy YAML-based platforms.
</Note>

## Best Practices

### Use Async Methods

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

# Bad
def turn_on(self) -> None:
    self.api.turn_on()  # Blocking!
```

### Batch Entity Creation

```python theme={null}
async def async_setup_entry(
    hass: HomeAssistant,
    entry: ConfigEntry,
    async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
    """Set up platform."""
    # Good - add all at once
    entities = [
        MyEntity(device)
        for device in await api.get_devices()
    ]
    async_add_entities(entities)
    
    # Bad - multiple calls
    for device in await api.get_devices():
        async_add_entities([MyEntity(device)])
```

### Handle Missing Data

```python theme={null}
@property
def native_value(self) -> float | None:
    """Return the value."""
    if self._value is None:
        return None
    return float(self._value)
```

## Next Steps

<Card title="Integration Overview" icon="book" href="/integrations/overview">
  Understand the full integration architecture
</Card>

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