2024-09-25 19:47:40 +00:00
|
|
|
"""Helper class for deprecating entities."""
|
|
|
|
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
from collections.abc import Sequence
|
|
|
|
from dataclasses import dataclass
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
|
2025-01-23 18:51:56 +00:00
|
|
|
from kasa import Device
|
|
|
|
|
2024-09-25 19:47:40 +00:00
|
|
|
from homeassistant.components.automation import automations_with_entity
|
2025-01-23 18:51:56 +00:00
|
|
|
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
2024-09-25 19:47:40 +00:00
|
|
|
from homeassistant.components.script import scripts_with_entity
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
from homeassistant.helpers import entity_registry as er
|
|
|
|
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
|
|
|
|
2025-01-23 18:51:56 +00:00
|
|
|
from . import legacy_device_id
|
2024-09-25 19:47:40 +00:00
|
|
|
from .const import DOMAIN
|
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
2025-01-23 18:51:56 +00:00
|
|
|
from .entity import CoordinatedTPLinkEntity, TPLinkEntityDescription
|
2024-09-25 19:47:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
@dataclass(slots=True)
|
|
|
|
class DeprecatedInfo:
|
|
|
|
"""Class to define deprecation info for deprecated entities."""
|
|
|
|
|
|
|
|
platform: str
|
|
|
|
new_platform: str
|
|
|
|
breaks_in_ha_version: str
|
|
|
|
|
|
|
|
|
|
|
|
def async_check_create_deprecated(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
unique_id: str,
|
2025-01-23 18:51:56 +00:00
|
|
|
entity_description: TPLinkEntityDescription,
|
2024-09-25 19:47:40 +00:00
|
|
|
) -> bool:
|
|
|
|
"""Return true if the entity should be created based on the deprecated_info.
|
|
|
|
|
|
|
|
If deprecated_info is not defined will return true.
|
|
|
|
If entity not yet created will return false.
|
|
|
|
If entity disabled will return false.
|
|
|
|
"""
|
|
|
|
if not entity_description.deprecated_info:
|
|
|
|
return True
|
|
|
|
|
|
|
|
deprecated_info = entity_description.deprecated_info
|
|
|
|
platform = deprecated_info.platform
|
|
|
|
|
|
|
|
ent_reg = er.async_get(hass)
|
|
|
|
entity_id = ent_reg.async_get_entity_id(
|
|
|
|
platform,
|
|
|
|
DOMAIN,
|
|
|
|
unique_id,
|
|
|
|
)
|
|
|
|
if not entity_id:
|
|
|
|
return False
|
|
|
|
|
|
|
|
entity_entry = ent_reg.async_get(entity_id)
|
|
|
|
assert entity_entry
|
|
|
|
return not entity_entry.disabled
|
|
|
|
|
|
|
|
|
2025-01-23 18:51:56 +00:00
|
|
|
def async_process_deprecated(
|
2024-09-25 19:47:40 +00:00
|
|
|
hass: HomeAssistant,
|
2025-01-23 18:51:56 +00:00
|
|
|
platform_domain: str,
|
2024-09-25 19:47:40 +00:00
|
|
|
entry_id: str,
|
2025-01-23 18:51:56 +00:00
|
|
|
entities: Sequence[CoordinatedTPLinkEntity],
|
|
|
|
device: Device,
|
2024-09-25 19:47:40 +00:00
|
|
|
) -> None:
|
2025-01-23 18:51:56 +00:00
|
|
|
"""Process deprecated entities for a device.
|
|
|
|
|
|
|
|
Create issues for deprececated entities that appear in automations.
|
|
|
|
Delete entities that are no longer provided by the integration either
|
|
|
|
because they have been removed at the end of the deprecation period, or
|
|
|
|
they are disabled by the user so the async_check_create_deprecated
|
|
|
|
returned false.
|
|
|
|
"""
|
2024-09-25 19:47:40 +00:00
|
|
|
ent_reg = er.async_get(hass)
|
|
|
|
for entity in entities:
|
|
|
|
if not (deprecated_info := entity.entity_description.deprecated_info):
|
|
|
|
continue
|
|
|
|
|
|
|
|
assert entity.unique_id
|
|
|
|
entity_id = ent_reg.async_get_entity_id(
|
2025-01-23 18:51:56 +00:00
|
|
|
platform_domain,
|
2024-09-25 19:47:40 +00:00
|
|
|
DOMAIN,
|
|
|
|
entity.unique_id,
|
|
|
|
)
|
|
|
|
assert entity_id
|
|
|
|
# Check for issues that need to be created
|
|
|
|
entity_automations = automations_with_entity(hass, entity_id)
|
|
|
|
entity_scripts = scripts_with_entity(hass, entity_id)
|
|
|
|
|
|
|
|
for item in entity_automations + entity_scripts:
|
|
|
|
async_create_issue(
|
|
|
|
hass,
|
|
|
|
DOMAIN,
|
|
|
|
f"deprecated_entity_{entity_id}_{item}",
|
|
|
|
breaks_in_ha_version=deprecated_info.breaks_in_ha_version,
|
|
|
|
is_fixable=False,
|
|
|
|
is_persistent=False,
|
|
|
|
severity=IssueSeverity.WARNING,
|
|
|
|
translation_key="deprecated_entity",
|
|
|
|
translation_placeholders={
|
|
|
|
"entity": entity_id,
|
|
|
|
"info": item,
|
2025-01-23 18:51:56 +00:00
|
|
|
"platform": platform_domain,
|
2024-09-25 19:47:40 +00:00
|
|
|
"new_platform": deprecated_info.new_platform,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2025-01-23 18:51:56 +00:00
|
|
|
# The light platform does not currently support cleaning up disabled
|
|
|
|
# deprecated entities because it uses two entity classes so a completeness
|
|
|
|
# check is not possible. It also uses the mac address as device id in some
|
|
|
|
# instances instead of device_id.
|
|
|
|
if platform_domain == LIGHT_DOMAIN:
|
|
|
|
return
|
|
|
|
|
2024-09-25 19:47:40 +00:00
|
|
|
# Remove entities that are no longer provided and have been disabled.
|
2025-01-23 18:51:56 +00:00
|
|
|
device_id = legacy_device_id(device)
|
|
|
|
|
2024-09-25 19:47:40 +00:00
|
|
|
unique_ids = {entity.unique_id for entity in entities}
|
|
|
|
for entity_entry in er.async_entries_for_config_entry(ent_reg, entry_id):
|
|
|
|
if (
|
2025-01-23 18:51:56 +00:00
|
|
|
entity_entry.domain == platform_domain
|
2024-09-25 19:47:40 +00:00
|
|
|
and entity_entry.disabled
|
2025-01-23 18:51:56 +00:00
|
|
|
and entity_entry.unique_id.startswith(device_id)
|
2024-09-25 19:47:40 +00:00
|
|
|
and entity_entry.unique_id not in unique_ids
|
|
|
|
):
|
|
|
|
ent_reg.async_remove(entity_entry.entity_id)
|
|
|
|
continue
|