Entity lifecycle
What happens when Home Assistant adds and removes an entity, and the hooks you use to subscribe, clean up, and react to registry changes.
You create entity objects in the platform setup of your integration and hand them to Home Assistant with async_add_entities. From then on, Home Assistant decides when the entity is added, updated, and removed. Lifecycle hooks let you run code at each of those moments. All of them are optional.
When you pass an entity to async_add_entities, Home Assistant goes through these steps:
- It gives the entity its
hassandplatformattributes. - It calls
async_prepare_to_add_to_hass(). - If you passed
update_before_add=True, it calls the update method. If the update raises, adding stops here. - If the entity has a unique ID, it registers the device and the entity in the registries, and picks the entity ID. If the entity is disabled, or its unique ID or entity ID is already taken, adding stops here.
- It calls
async_added_to_hass(). - It writes the first state.
Your __init__ runs before all of this, so self.hass and self.entity_id aren't set there yet. Keep __init__ about storing what the entity needs, and do the rest in the hooks.
The main hook. It runs only when adding succeeds, right before the first state is written. The entity has its entity ID and registry entry by then. Use it to subscribe to updates, register listeners, or restore an earlier state.
async def async_added_to_hass(self) -> None:
"""Subscribe to the device once the entity is added."""
await super().async_added_to_hass()
self.async_on_remove(
self._device.subscribe(self._handle_update)
)Call super() when you inherit from a class that might implement the hook too, like CoordinatorEntity or RestoreEntity.
Because disabled entities are never added, this hook is also the right place to keep a reference to an entity, if your integration needs one. Anything you register here is only registered for entities that are actually running.
Runs on every attempt to add the entity, before Home Assistant looks at the registry. It also runs for entities that won't be added in the end, for example because they are disabled. You rarely need it. If you set anything up here, register its cleanup with async_on_remove, because async_will_remove_from_hass doesn't run when adding is aborted.
An entity is removed when its config entry unloads, when the user disables it, or when it is deleted from the entity registry. Stopping Home Assistant does not remove entities, so these hooks don't run on shutdown. If something must happen on shutdown, listen for EVENT_HOMEASSISTANT_STOP. When an entity is removed, Home Assistant:
- Calls every callback registered with
async_on_remove. - Calls
async_will_remove_from_hass(). - Removes the state. Or, when the entity is still in the registry and enabled, like when the config entry is just unloaded, it sets the state to
unavailablewith arestoredattribute.
Registers a function to call when the entity is removed, or when adding it is aborted. Most subscription helpers return an unsubscribe function, so you can pass that straight in. This is the cleanest way to make sure you never leak a listener.
The counterpart of async_added_to_hass. Use it to undo work that async_on_remove can't, like closing a connection that belongs to this entity only.
Runs when the entity is deleted from the entity registry, not just removed for now. Use it to clean up data stored outside the entity, like a file or a setting on the device that only made sense for this entity.
The user can change an entity in the registry while it runs: rename it, give it another entity ID, change its options.
Runs after the registry entry of the entity changed. self.registry_entry holds the new entry. Use it when your entity depends on registry options, like a unit or a precision the user picked.
Runs when the user changed the entity ID. By then, self.entity_id is the new ID, and Home Assistant has moved its own bookkeeping to it. If you track something by entity ID, like a state change listener on your own entity, move it to the new ID here and call super(). The method must not await. Home Assistant writes the state under the new ID after it returns.
Some entities have to remember their state across restarts, because the device can't tell them. Inherit from RestoreEntity in homeassistant.helpers.restore_state as well, and read the last state in async_added_to_hass:
from homeassistant.helpers.restore_state import RestoreEntity
class ExampleSwitch(SwitchEntity, RestoreEntity):
async def async_added_to_hass(self) -> None:
await super().async_added_to_hass()
if (last_state := await self.async_get_last_state()) is not None:
self._attr_is_on = last_state.state == "on"Sensors use RestoreSensor instead, and read the last state with RestoreSensor.async_get_last_sensor_data(), which also restores the native value and unit. See the sensor entity.