mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Deprecate tplink alarm button entities (#126349)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
a1e6d4b693
commit
4f0211cdd8
@ -75,6 +75,7 @@ async def async_setup_entry(
|
||||
device = parent_coordinator.device
|
||||
|
||||
entities = CoordinatedTPLinkFeatureEntity.entities_for_device_and_its_children(
|
||||
hass=hass,
|
||||
device=device,
|
||||
coordinator=parent_coordinator,
|
||||
feature_type=Feature.Type.BinarySensor,
|
||||
|
@ -7,11 +7,17 @@ from typing import Final
|
||||
|
||||
from kasa import Feature
|
||||
|
||||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||
from homeassistant.components.button import (
|
||||
DOMAIN as BUTTON_DOMAIN,
|
||||
ButtonEntity,
|
||||
ButtonEntityDescription,
|
||||
)
|
||||
from homeassistant.components.siren import DOMAIN as SIREN_DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import TPLinkConfigEntry
|
||||
from .deprecate import DeprecatedInfo, async_cleanup_deprecated
|
||||
from .entity import CoordinatedTPLinkFeatureEntity, TPLinkFeatureEntityDescription
|
||||
|
||||
|
||||
@ -25,9 +31,19 @@ class TPLinkButtonEntityDescription(
|
||||
BUTTON_DESCRIPTIONS: Final = [
|
||||
TPLinkButtonEntityDescription(
|
||||
key="test_alarm",
|
||||
deprecated_info=DeprecatedInfo(
|
||||
platform=BUTTON_DOMAIN,
|
||||
new_platform=SIREN_DOMAIN,
|
||||
breaks_in_ha_version="2025.4.0",
|
||||
),
|
||||
),
|
||||
TPLinkButtonEntityDescription(
|
||||
key="stop_alarm",
|
||||
deprecated_info=DeprecatedInfo(
|
||||
platform=BUTTON_DOMAIN,
|
||||
new_platform=SIREN_DOMAIN,
|
||||
breaks_in_ha_version="2025.4.0",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
@ -46,6 +62,7 @@ async def async_setup_entry(
|
||||
device = parent_coordinator.device
|
||||
|
||||
entities = CoordinatedTPLinkFeatureEntity.entities_for_device_and_its_children(
|
||||
hass=hass,
|
||||
device=device,
|
||||
coordinator=parent_coordinator,
|
||||
feature_type=Feature.Type.Action,
|
||||
@ -53,6 +70,7 @@ async def async_setup_entry(
|
||||
descriptions=BUTTON_DESCRIPTIONS_MAP,
|
||||
child_coordinators=children_coordinators,
|
||||
)
|
||||
async_cleanup_deprecated(hass, BUTTON_DOMAIN, config_entry.entry_id, entities)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
|
111
homeassistant/components/tplink/deprecate.py
Normal file
111
homeassistant/components/tplink/deprecate.py
Normal file
@ -0,0 +1,111 @@
|
||||
"""Helper class for deprecating entities."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from homeassistant.components.automation import automations_with_entity
|
||||
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
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .entity import CoordinatedTPLinkFeatureEntity, TPLinkFeatureEntityDescription
|
||||
|
||||
|
||||
@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,
|
||||
entity_description: TPLinkFeatureEntityDescription,
|
||||
) -> 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
|
||||
|
||||
|
||||
def async_cleanup_deprecated(
|
||||
hass: HomeAssistant,
|
||||
platform: str,
|
||||
entry_id: str,
|
||||
entities: Sequence[CoordinatedTPLinkFeatureEntity],
|
||||
) -> None:
|
||||
"""Remove disabled deprecated entities or create issues if necessary."""
|
||||
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(
|
||||
platform,
|
||||
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,
|
||||
"platform": platform,
|
||||
"new_platform": deprecated_info.new_platform,
|
||||
},
|
||||
)
|
||||
|
||||
# Remove entities that are no longer provided and have been disabled.
|
||||
unique_ids = {entity.unique_id for entity in entities}
|
||||
for entity_entry in er.async_entries_for_config_entry(ent_reg, entry_id):
|
||||
if (
|
||||
entity_entry.domain == platform
|
||||
and entity_entry.disabled
|
||||
and entity_entry.unique_id not in unique_ids
|
||||
):
|
||||
ent_reg.async_remove(entity_entry.entity_id)
|
||||
continue
|
@ -18,7 +18,7 @@ from kasa import (
|
||||
)
|
||||
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
@ -36,6 +36,7 @@ from .const import (
|
||||
PRIMARY_STATE_ID,
|
||||
)
|
||||
from .coordinator import TPLinkDataUpdateCoordinator
|
||||
from .deprecate import DeprecatedInfo, async_check_create_deprecated
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@ -87,6 +88,8 @@ LEGACY_KEY_MAPPING = {
|
||||
class TPLinkFeatureEntityDescription(EntityDescription):
|
||||
"""Base class for a TPLink feature based entity description."""
|
||||
|
||||
deprecated_info: DeprecatedInfo | None = None
|
||||
|
||||
|
||||
def async_refresh_after[_T: CoordinatedTPLinkEntity, **_P](
|
||||
func: Callable[Concatenate[_T, _P], Awaitable[None]],
|
||||
@ -251,18 +254,25 @@ class CoordinatedTPLinkFeatureEntity(CoordinatedTPLinkEntity, ABC):
|
||||
|
||||
def _get_unique_id(self) -> str:
|
||||
"""Return unique ID for the entity."""
|
||||
key = self.entity_description.key
|
||||
return self._get_feature_unique_id(self._device, self.entity_description)
|
||||
|
||||
@staticmethod
|
||||
def _get_feature_unique_id(
|
||||
device: Device, entity_description: TPLinkFeatureEntityDescription
|
||||
) -> str:
|
||||
"""Return unique ID for the entity."""
|
||||
key = entity_description.key
|
||||
# The unique id for the state feature in the switch platform is the
|
||||
# device_id
|
||||
if key == PRIMARY_STATE_ID:
|
||||
return legacy_device_id(self._device)
|
||||
return legacy_device_id(device)
|
||||
|
||||
# Historically the legacy device emeter attributes which are now
|
||||
# replaced with features used slightly different keys. This ensures
|
||||
# that those entities are not orphaned. Returns the mapped key or the
|
||||
# provided key if not mapped.
|
||||
key = LEGACY_KEY_MAPPING.get(key, key)
|
||||
return f"{legacy_device_id(self._device)}_{key}"
|
||||
return f"{legacy_device_id(device)}_{key}"
|
||||
|
||||
@classmethod
|
||||
def _category_for_feature(cls, feature: Feature | None) -> EntityCategory | None:
|
||||
@ -334,6 +344,7 @@ class CoordinatedTPLinkFeatureEntity(CoordinatedTPLinkEntity, ABC):
|
||||
_D: TPLinkFeatureEntityDescription,
|
||||
](
|
||||
cls,
|
||||
hass: HomeAssistant,
|
||||
device: Device,
|
||||
coordinator: TPLinkDataUpdateCoordinator,
|
||||
*,
|
||||
@ -368,6 +379,11 @@ class CoordinatedTPLinkFeatureEntity(CoordinatedTPLinkEntity, ABC):
|
||||
feat, descriptions, device=device, parent=parent
|
||||
)
|
||||
)
|
||||
and async_check_create_deprecated(
|
||||
hass,
|
||||
cls._get_feature_unique_id(device, desc),
|
||||
desc,
|
||||
)
|
||||
]
|
||||
return entities
|
||||
|
||||
@ -377,6 +393,7 @@ class CoordinatedTPLinkFeatureEntity(CoordinatedTPLinkEntity, ABC):
|
||||
_D: TPLinkFeatureEntityDescription,
|
||||
](
|
||||
cls,
|
||||
hass: HomeAssistant,
|
||||
device: Device,
|
||||
coordinator: TPLinkDataUpdateCoordinator,
|
||||
*,
|
||||
@ -393,6 +410,7 @@ class CoordinatedTPLinkFeatureEntity(CoordinatedTPLinkEntity, ABC):
|
||||
# Add parent entities before children so via_device id works.
|
||||
entities.extend(
|
||||
cls._entities_for_device(
|
||||
hass,
|
||||
device,
|
||||
coordinator=coordinator,
|
||||
feature_type=feature_type,
|
||||
@ -412,6 +430,7 @@ class CoordinatedTPLinkFeatureEntity(CoordinatedTPLinkEntity, ABC):
|
||||
child_coordinator = coordinator
|
||||
entities.extend(
|
||||
cls._entities_for_device(
|
||||
hass,
|
||||
child,
|
||||
coordinator=child_coordinator,
|
||||
feature_type=feature_type,
|
||||
|
@ -67,6 +67,7 @@ async def async_setup_entry(
|
||||
children_coordinators = data.children_coordinators
|
||||
device = parent_coordinator.device
|
||||
entities = CoordinatedTPLinkFeatureEntity.entities_for_device_and_its_children(
|
||||
hass=hass,
|
||||
device=device,
|
||||
coordinator=parent_coordinator,
|
||||
feature_type=Feature.Type.Number,
|
||||
|
@ -54,6 +54,7 @@ async def async_setup_entry(
|
||||
device = parent_coordinator.device
|
||||
|
||||
entities = CoordinatedTPLinkFeatureEntity.entities_for_device_and_its_children(
|
||||
hass=hass,
|
||||
device=device,
|
||||
coordinator=parent_coordinator,
|
||||
feature_type=Feature.Type.Choice,
|
||||
|
@ -8,6 +8,7 @@ from typing import cast
|
||||
from kasa import Feature
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
DOMAIN as SENSOR_DOMAIN,
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
@ -18,6 +19,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import TPLinkConfigEntry
|
||||
from .const import UNIT_MAPPING
|
||||
from .deprecate import async_cleanup_deprecated
|
||||
from .entity import CoordinatedTPLinkFeatureEntity, TPLinkFeatureEntityDescription
|
||||
|
||||
|
||||
@ -128,6 +130,7 @@ async def async_setup_entry(
|
||||
device = parent_coordinator.device
|
||||
|
||||
entities = CoordinatedTPLinkFeatureEntity.entities_for_device_and_its_children(
|
||||
hass=hass,
|
||||
device=device,
|
||||
coordinator=parent_coordinator,
|
||||
feature_type=Feature.Type.Sensor,
|
||||
@ -135,6 +138,7 @@ async def async_setup_entry(
|
||||
descriptions=SENSOR_DESCRIPTIONS_MAP,
|
||||
child_coordinators=children_coordinators,
|
||||
)
|
||||
async_cleanup_deprecated(hass, SENSOR_DOMAIN, config_entry.entry_id, entities)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
|
@ -311,5 +311,11 @@
|
||||
"device_authentication": {
|
||||
"message": "Device authentication error {func}: {exc}"
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_entity": {
|
||||
"title": "Detected deprecated `{platform}` entity usage",
|
||||
"description": "We detected that entity `{entity}` is being used in `{info}`\n\nWe have created a new `{new_platform}` entity and you should migrate `{info}` to use this new entity.\n\nWhen you are done migrating `{info}` and are ready to have the deprecated `{entity}` entity removed, disable the entity and restart Home Assistant."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,8 @@ async def async_setup_entry(
|
||||
device = parent_coordinator.device
|
||||
|
||||
entities = CoordinatedTPLinkFeatureEntity.entities_for_device_and_its_children(
|
||||
device,
|
||||
hass=hass,
|
||||
device=device,
|
||||
coordinator=parent_coordinator,
|
||||
feature_type=Feature.Switch,
|
||||
entity_class=TPLinkSwitch,
|
||||
|
@ -21,6 +21,7 @@ from kasa.protocol import BaseProtocol
|
||||
from kasa.smart.modules.alarm import Alarm
|
||||
from syrupy import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.automation import DOMAIN as AUTOMATION_DOMAIN
|
||||
from homeassistant.components.tplink import (
|
||||
CONF_AES_KEYS,
|
||||
CONF_ALIAS,
|
||||
@ -184,6 +185,21 @@ async def snapshot_platform(
|
||||
), f"state snapshot failed for {entity_entry.entity_id}"
|
||||
|
||||
|
||||
async def setup_automation(hass: HomeAssistant, alias: str, entity_id: str) -> None:
|
||||
"""Set up an automation for tests."""
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
AUTOMATION_DOMAIN,
|
||||
{
|
||||
AUTOMATION_DOMAIN: {
|
||||
"alias": alias,
|
||||
"trigger": {"platform": "state", "entity_id": entity_id, "to": "on"},
|
||||
"action": {"action": "notify.notify", "metadata": {}, "data": {}},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def _mock_protocol() -> BaseProtocol:
|
||||
protocol = MagicMock(spec=BaseProtocol)
|
||||
protocol.close = AsyncMock()
|
||||
|
@ -11,7 +11,11 @@ from homeassistant.components.tplink.const import DOMAIN
|
||||
from homeassistant.components.tplink.entity import EXCLUDED_FEATURES
|
||||
from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||
from homeassistant.helpers import (
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
issue_registry as ir,
|
||||
)
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from . import (
|
||||
@ -22,6 +26,7 @@ from . import (
|
||||
_mocked_strip_children,
|
||||
_patch_connect,
|
||||
_patch_discovery,
|
||||
setup_automation,
|
||||
setup_platform_for_device,
|
||||
snapshot_platform,
|
||||
)
|
||||
@ -29,6 +34,53 @@ from . import (
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_deprecated_button_entities(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
):
|
||||
"""Create the entity so it is not ignored by the deprecation check."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
|
||||
def create_entry(device_name, device_id, key):
|
||||
unique_id = f"{device_id}_{key}"
|
||||
|
||||
entity_registry.async_get_or_create(
|
||||
domain=BUTTON_DOMAIN,
|
||||
platform=DOMAIN,
|
||||
unique_id=unique_id,
|
||||
suggested_object_id=f"{device_name}_{key}",
|
||||
config_entry=mock_config_entry,
|
||||
)
|
||||
|
||||
create_entry("my_device", "123456789ABCDEFGH", "stop_alarm")
|
||||
create_entry("my_device", "123456789ABCDEFGH", "test_alarm")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def create_deprecated_child_button_entities(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
):
|
||||
"""Create the entity so it is not ignored by the deprecation check."""
|
||||
|
||||
def create_entry(device_name, key):
|
||||
for plug_id in range(2):
|
||||
unique_id = f"PLUG{plug_id}DEVICEID_{key}"
|
||||
entity_registry.async_get_or_create(
|
||||
domain=BUTTON_DOMAIN,
|
||||
platform=DOMAIN,
|
||||
unique_id=unique_id,
|
||||
suggested_object_id=f"my_device_plug{plug_id}_{key}",
|
||||
config_entry=mock_config_entry,
|
||||
)
|
||||
|
||||
create_entry("my_device", "stop_alarm")
|
||||
create_entry("my_device", "test_alarm")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mocked_feature_button() -> Feature:
|
||||
"""Return mocked tplink binary sensor feature."""
|
||||
@ -47,6 +99,7 @@ async def test_states(
|
||||
entity_registry: er.EntityRegistry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
snapshot: SnapshotAssertion,
|
||||
create_deprecated_button_entities,
|
||||
) -> None:
|
||||
"""Test a sensor unique ids."""
|
||||
features = {description.key for description in BUTTON_DESCRIPTIONS}
|
||||
@ -66,6 +119,7 @@ async def test_button(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mocked_feature_button: Feature,
|
||||
create_deprecated_button_entities,
|
||||
) -> None:
|
||||
"""Test a sensor unique ids."""
|
||||
mocked_feature = mocked_feature_button
|
||||
@ -74,13 +128,13 @@ async def test_button(
|
||||
)
|
||||
already_migrated_config_entry.add_to_hass(hass)
|
||||
|
||||
plug = _mocked_device(alias="my_plug", features=[mocked_feature])
|
||||
plug = _mocked_device(alias="my_device", features=[mocked_feature])
|
||||
with _patch_discovery(device=plug), _patch_connect(device=plug):
|
||||
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# The entity_id is based on standard name from core.
|
||||
entity_id = "button.my_plug_test_alarm"
|
||||
entity_id = "button.my_device_test_alarm"
|
||||
entity = entity_registry.async_get(entity_id)
|
||||
assert entity
|
||||
assert entity.unique_id == f"{DEVICE_ID}_{mocked_feature.id}"
|
||||
@ -91,6 +145,8 @@ async def test_button_children(
|
||||
entity_registry: er.EntityRegistry,
|
||||
device_registry: dr.DeviceRegistry,
|
||||
mocked_feature_button: Feature,
|
||||
create_deprecated_button_entities,
|
||||
create_deprecated_child_button_entities,
|
||||
) -> None:
|
||||
"""Test a sensor unique ids."""
|
||||
mocked_feature = mocked_feature_button
|
||||
@ -99,7 +155,7 @@ async def test_button_children(
|
||||
)
|
||||
already_migrated_config_entry.add_to_hass(hass)
|
||||
plug = _mocked_device(
|
||||
alias="my_plug",
|
||||
alias="my_device",
|
||||
features=[mocked_feature],
|
||||
children=_mocked_strip_children(features=[mocked_feature]),
|
||||
)
|
||||
@ -107,13 +163,13 @@ async def test_button_children(
|
||||
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "button.my_plug_test_alarm"
|
||||
entity_id = "button.my_device_test_alarm"
|
||||
entity = entity_registry.async_get(entity_id)
|
||||
assert entity
|
||||
device = device_registry.async_get(entity.device_id)
|
||||
|
||||
for plug_id in range(2):
|
||||
child_entity_id = f"button.my_plug_plug{plug_id}_test_alarm"
|
||||
child_entity_id = f"button.my_device_plug{plug_id}_test_alarm"
|
||||
child_entity = entity_registry.async_get(child_entity_id)
|
||||
assert child_entity
|
||||
assert child_entity.unique_id == f"PLUG{plug_id}DEVICEID_{mocked_feature.id}"
|
||||
@ -127,6 +183,7 @@ async def test_button_press(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mocked_feature_button: Feature,
|
||||
create_deprecated_button_entities,
|
||||
) -> None:
|
||||
"""Test a number entity limits and setting values."""
|
||||
mocked_feature = mocked_feature_button
|
||||
@ -134,12 +191,12 @@ async def test_button_press(
|
||||
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
|
||||
)
|
||||
already_migrated_config_entry.add_to_hass(hass)
|
||||
plug = _mocked_device(alias="my_plug", features=[mocked_feature])
|
||||
plug = _mocked_device(alias="my_device", features=[mocked_feature])
|
||||
with _patch_discovery(device=plug), _patch_connect(device=plug):
|
||||
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "button.my_plug_test_alarm"
|
||||
entity_id = "button.my_device_test_alarm"
|
||||
entity = entity_registry.async_get(entity_id)
|
||||
assert entity
|
||||
assert entity.unique_id == f"{DEVICE_ID}_test_alarm"
|
||||
@ -151,3 +208,84 @@ async def test_button_press(
|
||||
blocking=True,
|
||||
)
|
||||
mocked_feature.set_value.assert_called_with(True)
|
||||
|
||||
|
||||
async def test_button_not_exists_with_deprecation(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mocked_feature_button: Feature,
|
||||
) -> None:
|
||||
"""Test deprecated buttons are not created if they don't previously exist."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
entity_id = "button.my_device_test_alarm"
|
||||
|
||||
assert not hass.states.get(entity_id)
|
||||
mocked_feature = mocked_feature_button
|
||||
dev = _mocked_device(alias="my_device", features=[mocked_feature])
|
||||
with _patch_discovery(device=dev), _patch_connect(device=dev):
|
||||
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert not entity_registry.async_get(entity_id)
|
||||
assert not er.async_entries_for_config_entry(entity_registry, config_entry.entry_id)
|
||||
assert not hass.states.get(entity_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("entity_disabled", "entity_has_automations"),
|
||||
[
|
||||
pytest.param(False, False, id="without-automations"),
|
||||
pytest.param(False, True, id="with-automations"),
|
||||
pytest.param(True, False, id="disabled"),
|
||||
],
|
||||
)
|
||||
async def test_button_exists_with_deprecation(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
mocked_feature_button: Feature,
|
||||
entity_disabled: bool,
|
||||
entity_has_automations: bool,
|
||||
) -> None:
|
||||
"""Test the deprecated buttons are deleted or raise issues."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=DOMAIN, data={CONF_HOST: "127.0.0.1"}, unique_id=MAC_ADDRESS
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
object_id = "my_device_test_alarm"
|
||||
entity_id = f"button.{object_id}"
|
||||
unique_id = f"{DEVICE_ID}_test_alarm"
|
||||
issue_id = f"deprecated_entity_{entity_id}_automation.test_automation"
|
||||
|
||||
if entity_has_automations:
|
||||
await setup_automation(hass, "test_automation", entity_id)
|
||||
|
||||
entity = entity_registry.async_get_or_create(
|
||||
domain=BUTTON_DOMAIN,
|
||||
platform=DOMAIN,
|
||||
unique_id=unique_id,
|
||||
suggested_object_id=object_id,
|
||||
config_entry=config_entry,
|
||||
disabled_by=er.RegistryEntryDisabler.USER if entity_disabled else None,
|
||||
)
|
||||
assert entity.entity_id == entity_id
|
||||
assert not hass.states.get(entity_id)
|
||||
|
||||
mocked_feature = mocked_feature_button
|
||||
dev = _mocked_device(alias="my_device", features=[mocked_feature])
|
||||
with _patch_discovery(device=dev), _patch_connect(device=dev):
|
||||
await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity = entity_registry.async_get(entity_id)
|
||||
# entity and state will be none if removed from registry
|
||||
assert (entity is None) == entity_disabled
|
||||
assert (hass.states.get(entity_id) is None) == entity_disabled
|
||||
|
||||
assert (
|
||||
issue_registry.async_get_issue(DOMAIN, issue_id) is not None
|
||||
) == entity_has_automations
|
||||
|
Loading…
x
Reference in New Issue
Block a user