Skip to main content
Entities are the building blocks of Home Assistant. They represent devices, sensors, switches, and other controllable or monitorable objects. This guide covers how to create entity components for your integration.

Entity Basics

What is an Entity?

An entity represents a single piece of functionality from a device or service. Examples:
  • A temperature sensor
  • A light bulb
  • A media player
  • A switch
Each entity has:
  • A unique ID for identification
  • A state (on/off, temperature value, etc.)
  • attributes with additional information
  • An entity ID like sensor.living_room_temperature

Entity Platforms

Home Assistant has different entity platforms for different types of entities:
  • sensor - Read-only measurements
  • binary_sensor - On/off sensors
  • switch - On/off switches
  • light - Lights with brightness, color, etc.
  • climate - Thermostats and climate control
  • cover - Blinds, garage doors, etc.
  • And many more…

Creating an Entity Platform

Each entity platform is a separate Python file in your integration directory.

Platform Setup Function

Every platform must have an async_setup_entry function:
sensor.py
"""Sensor platform for Your 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 AddEntitiesCallback

from .const import DOMAIN


async def async_setup_entry(
    hass: HomeAssistant,
    entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up the sensor platform."""
    # Get the API client or coordinator from hass.data
    client = hass.data[DOMAIN][entry.entry_id]["client"]
    
    # Fetch the list of sensors
    sensors = await client.get_sensors()
    
    # Create entity objects
    entities = [
        YourTemperatureSensor(client, sensor_id)
        for sensor_id in sensors
    ]
    
    # Add entities to Home Assistant
    async_add_entities(entities)

Creating an Entity Class

Entity classes inherit from a base entity class specific to their platform.

Basic Entity Example

class YourTemperatureSensor(SensorEntity):
    """Representation of a temperature sensor."""
    
    # Specify the device class
    _attr_device_class = SensorDeviceClass.TEMPERATURE
    # Specify the state class for statistics
    _attr_state_class = SensorStateClass.MEASUREMENT
    # Specify the unit
    _attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS
    
    def __init__(self, client, sensor_id: str) -> None:
        """Initialize the sensor."""
        self._client = client
        self._sensor_id = sensor_id
        
        # Set a unique ID - important for customization
        self._attr_unique_id = f"{DOMAIN}_{sensor_id}"
        # Set the entity name
        self._attr_name = f"Temperature {sensor_id}"
    
    async def async_update(self) -> None:
        """Fetch new state data for the sensor."""
        # Get the current temperature from the API
        temperature = await self._client.get_temperature(self._sensor_id)
        self._attr_native_value = temperature

Entity Properties

The Entity base class provides many properties you can override:

Essential Properties

class YourEntity(SensorEntity):
    """Your entity."""
    
    # Unique identifier for this entity
    _attr_unique_id = "unique_entity_id"
    
    # Display name
    _attr_name = "My Sensor"
    
    # Whether the entity is available
    _attr_available = True
    
    # Icon to display (from Material Design Icons)
    _attr_icon = "mdi:thermometer"

Modern Entity Naming

Use the modern naming pattern with device info:
from homeassistant.helpers.device_registry import DeviceInfo

class YourSensor(SensorEntity):
    """Representation of a sensor."""
    
    # This entity represents a device
    _attr_has_entity_name = True
    # The entity name (will be combined with device name)
    _attr_name = "Temperature"
    
    def __init__(self, device_id: str) -> None:
        """Initialize the sensor."""
        self._attr_unique_id = f"{device_id}_temperature"
        
        # Associate this entity with a device
        self._attr_device_info = DeviceInfo(
            identifiers={(DOMAIN, device_id)},
            name="My Device",
            manufacturer="Your Company",
            model="Model X",
            sw_version="1.0.0",
        )
This creates an entity named “My Device Temperature” and groups it with other entities from the same device.

State Updates

There are several ways to update entity state:

Method 1: async_update (Polling)

class YourSensor(SensorEntity):
    """Polling sensor."""
    
    # Enable polling (default is True)
    _attr_should_poll = True
    
    async def async_update(self) -> None:
        """Fetch new state data for the sensor."""
        # This will be called periodically by Home Assistant
        self._attr_native_value = await self._client.get_value()
class YourSensor(SensorEntity):
    """Push-based sensor."""
    
    # Disable polling since we'll push updates
    _attr_should_poll = False
    
    def __init__(self, client) -> None:
        """Initialize the sensor."""
        self._client = client
        # Register a callback for updates
        self._client.register_callback(self._handle_update)
    
    def _handle_update(self, value) -> None:
        """Handle a pushed update from the API."""
        self._attr_native_value = value
        # Tell Home Assistant the state changed
        self.async_write_ha_state()
    
    async def async_will_remove_from_hass(self) -> None:
        """Clean up when entity is removed."""
        # Unregister the callback
        self._client.unregister_callback(self._handle_update)

Method 3: DataUpdateCoordinator (Best Practice)

from homeassistant.helpers.update_coordinator import (
    CoordinatorEntity,
    DataUpdateCoordinator,
)

class YourSensor(CoordinatorEntity, SensorEntity):
    """Sensor using coordinator."""
    
    def __init__(
        self,
        coordinator: DataUpdateCoordinator,
        sensor_id: str,
    ) -> None:
        """Initialize the sensor."""
        super().__init__(coordinator)
        self._sensor_id = sensor_id
        self._attr_unique_id = f"{DOMAIN}_{sensor_id}"
    
    @property
    def native_value(self):
        """Return the state of the sensor."""
        # Access coordinated data
        return self.coordinator.data[self._sensor_id]
See the DataUpdateCoordinator documentation for setup details.

Platform-Specific Features

Sensor Platform

from homeassistant.components.sensor import (
    SensorDeviceClass,
    SensorEntity,
    SensorStateClass,
)

class YourSensor(SensorEntity):
    """A sensor entity."""
    
    # Device class affects how the entity is displayed
    _attr_device_class = SensorDeviceClass.TEMPERATURE
    
    # State class enables statistics and long-term data
    _attr_state_class = SensorStateClass.MEASUREMENT
    
    # Native value and unit
    _attr_native_value = 20.5
    _attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS
    
    # Precision for rounding
    _attr_suggested_display_precision = 1

Switch Platform

from homeassistant.components.switch import SwitchEntity

class YourSwitch(SwitchEntity):
    """A switch entity."""
    
    @property
    def is_on(self) -> bool:
        """Return true if switch is on."""
        return self._attr_is_on
    
    async def async_turn_on(self, **kwargs) -> None:
        """Turn the switch on."""
        await self._client.turn_on(self._device_id)
        self._attr_is_on = True
        self.async_write_ha_state()
    
    async def async_turn_off(self, **kwargs) -> None:
        """Turn the switch off."""
        await self._client.turn_off(self._device_id)
        self._attr_is_on = False
        self.async_write_ha_state()

Light Platform

from homeassistant.components.light import (
    ATTR_BRIGHTNESS,
    ColorMode,
    LightEntity,
)

class YourLight(LightEntity):
    """A light entity."""
    
    # Supported color modes
    _attr_supported_color_modes = {ColorMode.BRIGHTNESS}
    _attr_color_mode = ColorMode.BRIGHTNESS
    
    @property
    def brightness(self) -> int | None:
        """Return the brightness of this light between 0..255."""
        return self._attr_brightness
    
    @property
    def is_on(self) -> bool:
        """Return true if light is on."""
        return self._attr_is_on
    
    async def async_turn_on(self, **kwargs) -> None:
        """Turn the light on."""
        if ATTR_BRIGHTNESS in kwargs:
            brightness = kwargs[ATTR_BRIGHTNESS]
            await self._client.set_brightness(self._device_id, brightness)
            self._attr_brightness = brightness
        
        await self._client.turn_on(self._device_id)
        self._attr_is_on = True
        self.async_write_ha_state()
    
    async def async_turn_off(self, **kwargs) -> None:
        """Turn the light off."""
        await self._client.turn_off(self._device_id)
        self._attr_is_on = False
        self.async_write_ha_state()

Entity Attributes

You can add extra attributes to entities:
class YourSensor(SensorEntity):
    """Sensor with extra attributes."""
    
    @property
    def extra_state_attributes(self) -> dict[str, Any]:
        """Return extra state attributes."""
        return {
            "last_update": self._last_update,
            "battery_level": self._battery_level,
            "signal_strength": self._signal_strength,
        }

Entity Categories

Use entity categories to organize entities:
from homeassistant.const import EntityCategory

class YourDiagnosticSensor(SensorEntity):
    """A diagnostic sensor."""
    
    # This entity is diagnostic (shown in advanced section)
    _attr_entity_category = EntityCategory.DIAGNOSTIC

class YourConfigSwitch(SwitchEntity):
    """A configuration switch."""
    
    # This entity is for configuration
    _attr_entity_category = EntityCategory.CONFIG
Categories:
  • EntityCategory.CONFIG - Configuration entities
  • EntityCategory.DIAGNOSTIC - Diagnostic information
  • None - Primary entities (default)

Entity Registry

When you set a unique_id, entities are automatically registered:
class YourEntity(SensorEntity):
    """Entity with unique ID."""
    
    def __init__(self, device_id: str) -> None:
        """Initialize."""
        # This enables entity registry features:
        # - User can customize the entity
        # - Entity survives integration reload
        # - Entity can be disabled
        self._attr_unique_id = f"{DOMAIN}_{device_id}"
Benefits of entity registry:
  • Users can customize entity names and icons
  • Users can disable entities they don’t need
  • Entity IDs are stable across restarts
  • Entities can be tracked across config changes

Dynamic Entity Addition

For devices that support dynamic entities:
from homeassistant.helpers.entity_platform import AddEntitiesCallback

async def async_setup_entry(
    hass: HomeAssistant,
    entry: ConfigEntry,
    async_add_entities: AddEntitiesCallback,
) -> None:
    """Set up the platform."""
    client = hass.data[DOMAIN][entry.entry_id]["client"]
    
    # Add initial entities
    async_add_entities([YourSensor(client, "sensor1")])
    
    # Store the callback for later use
    hass.data[DOMAIN][entry.entry_id]["add_entities"] = async_add_entities

# Later, when a new device is discovered:
def handle_new_device(hass, entry_id, device_id):
    """Handle a newly discovered device."""
    add_entities = hass.data[DOMAIN][entry_id]["add_entities"]
    client = hass.data[DOMAIN][entry_id]["client"]
    
    # Add the new entity
    add_entities([YourSensor(client, device_id)])

Entity Availability

Indicate when an entity is unavailable:
class YourSensor(SensorEntity):
    """Sensor that may become unavailable."""
    
    async def async_update(self) -> None:
        """Update the sensor."""
        try:
            self._attr_native_value = await self._client.get_value()
            self._attr_available = True
        except ConnectionError:
            # Device is offline
            self._attr_available = False

Best Practices

Always Use Unique IDs

Provide unique IDs for all entities to enable customization:
self._attr_unique_id = f"{entry.entry_id}_{device_id}_{sensor_type}"

Use Device Info

Group related entities under a single device:
self._attr_device_info = DeviceInfo(
    identifiers={(DOMAIN, device_id)},
    name="Device Name",
    manufacturer="Manufacturer",
    model="Model",
)

Use DataUpdateCoordinator

For polling integrations, use DataUpdateCoordinator to efficiently manage updates.

Disable Polling When Possible

If your API supports push updates, disable polling:
_attr_should_poll = False

Handle Exceptions

Gracefully handle API errors:
try:
    value = await self._client.get_value()
except APIError:
    _LOGGER.error("Failed to update sensor")
    self._attr_available = False

Use Modern Naming

Set _attr_has_entity_name = True and provide device info for better entity naming.

Common Patterns

Entity Descriptions

For multiple similar entities, use entity descriptions:
from dataclasses import dataclass
from homeassistant.components.sensor import SensorEntityDescription

@dataclass
class YourSensorDescription(SensorEntityDescription):
    """Describes a sensor."""
    api_key: str | None = None

SENSOR_TYPES: tuple[YourSensorDescription, ...] = (
    YourSensorDescription(
        key="temperature",
        name="Temperature",
        device_class=SensorDeviceClass.TEMPERATURE,
        api_key="temp",
    ),
    YourSensorDescription(
        key="humidity",
        name="Humidity",
        device_class=SensorDeviceClass.HUMIDITY,
        api_key="humid",
    ),
)

class YourSensor(SensorEntity):
    """Sensor using description."""
    
    def __init__(self, description: YourSensorDescription) -> None:
        """Initialize."""
        self.entity_description = description
        self._attr_unique_id = f"{DOMAIN}_{description.key}"

Next Steps

Build docs developers (and LLMs) love