mirror of
https://github.com/home-assistant/developers.home-assistant.git
synced 2025-07-14 12:56:30 +00:00
Add entity description docs (#1963)
* Add entity description docs * Fix typing * Set available True * Correct English Co-authored-by: Allen Porter <allen@thebends.org> * Sort imports * Mention description key --------- Co-authored-by: Allen Porter <allen@thebends.org>
This commit is contained in:
parent
b615e0b645
commit
55ee5f1d9b
@ -233,32 +233,117 @@ entity class for details.
|
||||
If an integration needs to access its own properties it should access the property (`self.name`), not the class or instance attribute (`self._attr_name`).
|
||||
:::
|
||||
|
||||
### Entity description
|
||||
|
||||
The third way of setting entity properties is to use an entity description. To do this set an attribute named `entity_description` on the `Entity` instance with an `EntityDescription` instance. The entity description is a dataclass with attributes corresponding to most of the available `Entity` properties. Each entity integration that supports an entity platform, eg the `switch` integration, will define their own `EntityDescription` subclass that should be used by implementing platforms that want to use entity descriptions.
|
||||
|
||||
By default the `EntityDescription` instance has one required attribute named `key`. This is a string which is meant to be unique for all the entity descriptions of an implementing platform. A common use case for this attribute is to include it in the `unique_id` of the described entity.
|
||||
|
||||
The main benefit of using entity descriptions is that it defines the different entity types of a platform in a declarative manner, making the code much easier to read when there are many different entity types.
|
||||
|
||||
### Example
|
||||
|
||||
The below code snippet gives an example of best practices for when to implement property functions, and when to use class or instance attributes.
|
||||
The below code snippet gives an example of best practices for when to implement property functions, when to use class or instance attributes and when to use entity descriptions.
|
||||
|
||||
```py
|
||||
class SomeEntity():
|
||||
_attr_device_class = SensorDeviceClass.TEMPERATURE # This will be common to all instances of SomeEntity
|
||||
def __init__(self, device):
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from example import ExampleDevice, ExampleException
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
EntityCategory,
|
||||
UnitOfElectricCurrent,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from .const import DOMAIN, LOGGER
|
||||
|
||||
@dataclass
|
||||
class ExampleSensorEntityDescriptionMixin:
|
||||
"""Mixin for required keys."""
|
||||
|
||||
value_fn: Callable[[ExampleDevice], StateType]
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExampleSensorEntityDescription(
|
||||
SensorEntityDescription, ExampleSensorEntityDescriptionMixin
|
||||
):
|
||||
"""Describes Example sensor entity."""
|
||||
|
||||
exists_fn: Callable[[ExampleDevice], bool] = lambda _: True
|
||||
|
||||
|
||||
SENSORS: tuple[ExampleSensorEntityDescription, ...] = (
|
||||
ExampleSensorEntityDescription(
|
||||
key="estimated_current",
|
||||
native_unit_of_measurement=UnitOfElectricCurrent.MILLIAMPERE,
|
||||
device_class=SensorDeviceClass.CURRENT,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
value_fn=lambda device: device.power,
|
||||
exists_fn=lambda device: bool(device.max_power),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Example sensor based on a config entry."""
|
||||
device: ExampleDevice = hass.data[DOMAIN][entry.entry_id]
|
||||
async_add_entities(
|
||||
ExampleSensorEntity(device, description)
|
||||
for description in SENSORS
|
||||
if description.exists_fn(device)
|
||||
)
|
||||
|
||||
|
||||
class ExampleSensorEntity(SensorEntity):
|
||||
"""Represent an Example sensor."""
|
||||
|
||||
entity_description: ExampleSensorEntityDescription
|
||||
_attr_entity_category = (
|
||||
EntityCategory.DIAGNOSTIC
|
||||
) # This will be common to all instances of ExampleSensorEntity
|
||||
|
||||
def __init__(
|
||||
self, device: ExampleDevice, entity_description: ExampleSensorEntityDescription
|
||||
) -> None:
|
||||
"""Set up the instance."""
|
||||
self._device = device
|
||||
self.entity_description = entity_description
|
||||
self._attr_available = False # This overrides the default
|
||||
self._attr_name = device.get_friendly_name()
|
||||
self._attr_unique_id = f"{device.serial}_{entity_description.key}"
|
||||
|
||||
# The following should be avoided:
|
||||
if some_complex_condition and some_other_condition and something_is_none_and_only_valid_after_update and device_available:
|
||||
...
|
||||
|
||||
def update(self)
|
||||
if self.available # Read current state, no need to prefix with _attr_
|
||||
# Update the entity
|
||||
def update(self) -> None:
|
||||
"""Update entity state."""
|
||||
try:
|
||||
self._device.update()
|
||||
|
||||
if error:
|
||||
except ExampleException:
|
||||
if self.available: # Read current state, no need to prefix with _attr_
|
||||
LOGGER.warning("Update failed for %s", self.entity_id)
|
||||
self._attr_available = False # Set property value
|
||||
return
|
||||
|
||||
self._attr_available = True
|
||||
# We don't need to check if device available here
|
||||
self._attr_is_on = self._device.get_state() # Update "is_on" property
|
||||
self._attr_native_value = self.entity_description.value_fn(
|
||||
self._device
|
||||
) # Update "native_value" property
|
||||
```
|
||||
|
||||
## Lifecycle hooks
|
||||
|
Loading…
x
Reference in New Issue
Block a user