mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 09:17:53 +00:00
Improve SmartThings switch deprecation (#142072)
This commit is contained in:
parent
4e0f581747
commit
02d182239a
@ -19,7 +19,7 @@ from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from . import FullDevice, SmartThingsConfigEntry
|
||||
from .const import MAIN
|
||||
from .const import INVALID_SWITCH_CATEGORIES, MAIN
|
||||
from .entity import SmartThingsEntity
|
||||
from .util import deprecate_entity
|
||||
|
||||
@ -127,14 +127,7 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
key=Attribute.SWITCH,
|
||||
device_class=BinarySensorDeviceClass.POWER,
|
||||
is_on_key="on",
|
||||
category={
|
||||
Category.CLOTHING_CARE_MACHINE,
|
||||
Category.COOKTOP,
|
||||
Category.DISHWASHER,
|
||||
Category.DRYER,
|
||||
Category.MICROWAVE,
|
||||
Category.WASHER,
|
||||
},
|
||||
category=INVALID_SWITCH_CATEGORIES,
|
||||
)
|
||||
},
|
||||
Capability.TAMPER_ALERT: {
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""Constants used by the SmartThings component and platforms."""
|
||||
|
||||
from pysmartthings import Attribute, Capability
|
||||
from pysmartthings import Attribute, Capability, Category
|
||||
|
||||
DOMAIN = "smartthings"
|
||||
|
||||
@ -109,3 +109,12 @@ SENSOR_ATTRIBUTES_TO_CAPABILITIES: dict[str, str] = {
|
||||
Attribute.WASHER_MODE: Capability.WASHER_MODE,
|
||||
Attribute.WASHER_JOB_STATE: Capability.WASHER_OPERATING_STATE,
|
||||
}
|
||||
|
||||
INVALID_SWITCH_CATEGORIES = {
|
||||
Category.CLOTHING_CARE_MACHINE,
|
||||
Category.COOKTOP,
|
||||
Category.DRYER,
|
||||
Category.WASHER,
|
||||
Category.MICROWAVE,
|
||||
Category.DISHWASHER,
|
||||
}
|
||||
|
@ -496,12 +496,20 @@
|
||||
"description": "The refrigerator door binary sensor {entity_name} (`{entity_id}`) is deprecated and will be removed in the future. The entity is used in the following automations or scripts:\n{items}\n\nSeparate entities for cooler and freezer door are available and should be used going forward. Please use them in the above automations or scripts and disable the entity to fix this issue."
|
||||
},
|
||||
"deprecated_switch_appliance": {
|
||||
"title": "Deprecated switch detected in some automations or scripts",
|
||||
"description": "The switch `{entity}` is deprecated because the actions did not work, so it has been replaced with a binary sensor instead.\n\nThe switch was used in the following automations or scripts:\n{items}\n\nPlease use the new binary sensor in the above automations or scripts to fix this issue."
|
||||
"title": "Appliance switch deprecated",
|
||||
"description": "The switch {entity_name} (`{entity_id}`) is deprecated because the actions did not work, so it has been replaced with a binary sensor instead.\n\nPlease update your dashboards, templates accordingly and disable the entity to fix this issue."
|
||||
},
|
||||
"deprecated_switch_appliance_scripts": {
|
||||
"title": "[%key:component::smartthings::issues::deprecated_switch_appliance::title%]",
|
||||
"description": "The switch {entity_name} (`{entity_id}`) is deprecated because the actions did not work, so it has been replaced with a binary sensor instead.\n\nThe switch was used in the following automations or scripts:\n{items}\n\nPlease use the new binary sensor in the above automations or scripts and disable the entity to fix this issue."
|
||||
},
|
||||
"deprecated_switch_media_player": {
|
||||
"title": "[%key:component::smartthings::issues::deprecated_switch_appliance::title%]",
|
||||
"description": "The switch `{entity}` is deprecated and a media player entity has been added to replace it.\n\nThe switch was used in the following automations or scripts:\n{items}\n\nPlease use the new media player entity in the above automations or scripts to fix this issue."
|
||||
"description": "The switch {entity_name} (`{entity_id}`) is deprecated and a media player entity has been added to replace it.\n\nPlease use the new media player entity in the above automations or scripts and disable the entity to fix this issue."
|
||||
},
|
||||
"deprecated_switch_media_player_scripts": {
|
||||
"title": "[%key:component::smartthings::issues::deprecated_switch_appliance::title%]",
|
||||
"description": "The switch {entity_name} (`{entity_id}`) is deprecated and a media player entity has been added to replace it.\n\nThe switch was used in the following automations or scripts:\n{items}\n\nPlease use the new media player entity in the above automations or scripts and disable the entity to fix this issue."
|
||||
},
|
||||
"deprecated_media_player": {
|
||||
"title": "Media player sensors deprecated",
|
||||
@ -509,7 +517,7 @@
|
||||
},
|
||||
"deprecated_media_player_scripts": {
|
||||
"title": "Deprecated sensor detected in some automations or scripts",
|
||||
"description": "The sensor {entity_name} (`{entity_id}`) is deprecated because it has been replaced with a media player entity.\n\nThe sensor was used in the following automations or scripts:\n{items}\n\nPlease use them in the above automations or scripts to use the new media player entity and disable the entity to fix this issue."
|
||||
"description": "The sensor {entity_name} (`{entity_id}`) is deprecated because it has been replaced with a media player entity.\n\nThe sensor was used in the following automations or scripts:\n{items}\n\nPlease update the above automations or scripts to use the new media player entity and disable the entity to fix this issue."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,23 +5,21 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
from pysmartthings import Attribute, Capability, Category, Command, SmartThings
|
||||
from pysmartthings import Attribute, Capability, Command, SmartThings
|
||||
|
||||
from homeassistant.components.automation import automations_with_entity
|
||||
from homeassistant.components.script import scripts_with_entity
|
||||
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
||||
from homeassistant.components.switch import (
|
||||
DOMAIN as SWITCH_DOMAIN,
|
||||
SwitchEntity,
|
||||
SwitchEntityDescription,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.issue_registry import (
|
||||
IssueSeverity,
|
||||
async_create_issue,
|
||||
async_delete_issue,
|
||||
)
|
||||
|
||||
from . import FullDevice, SmartThingsConfigEntry
|
||||
from .const import DOMAIN, MAIN
|
||||
from .const import INVALID_SWITCH_CATEGORIES, MAIN
|
||||
from .entity import SmartThingsEntity
|
||||
from .util import deprecate_entity
|
||||
|
||||
CAPABILITIES = (
|
||||
Capability.SWITCH_LEVEL,
|
||||
@ -37,6 +35,12 @@ AC_CAPABILITIES = (
|
||||
Capability.THERMOSTAT_COOLING_SETPOINT,
|
||||
)
|
||||
|
||||
MEDIA_PLAYER_CAPABILITIES = (
|
||||
Capability.AUDIO_MUTE,
|
||||
Capability.AUDIO_VOLUME,
|
||||
Capability.MEDIA_PLAYBACK,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class SmartThingsSwitchEntityDescription(SwitchEntityDescription):
|
||||
@ -92,13 +96,6 @@ async def async_setup_entry(
|
||||
"""Add switches for a config entry."""
|
||||
entry_data = entry.runtime_data
|
||||
entities: list[SmartThingsEntity] = [
|
||||
SmartThingsSwitch(entry_data.client, device, SWITCH, Capability.SWITCH)
|
||||
for device in entry_data.devices.values()
|
||||
if Capability.SWITCH in device.status[MAIN]
|
||||
and not any(capability in device.status[MAIN] for capability in CAPABILITIES)
|
||||
and not all(capability in device.status[MAIN] for capability in AC_CAPABILITIES)
|
||||
]
|
||||
entities.extend(
|
||||
SmartThingsCommandSwitch(
|
||||
entry_data.client,
|
||||
device,
|
||||
@ -108,7 +105,7 @@ async def async_setup_entry(
|
||||
for device in entry_data.devices.values()
|
||||
for capability, description in CAPABILITY_TO_COMMAND_SWITCHES.items()
|
||||
if capability in device.status[MAIN]
|
||||
)
|
||||
]
|
||||
entities.extend(
|
||||
SmartThingsSwitch(
|
||||
entry_data.client,
|
||||
@ -129,6 +126,51 @@ async def async_setup_entry(
|
||||
)
|
||||
)
|
||||
)
|
||||
entity_registry = er.async_get(hass)
|
||||
for device in entry_data.devices.values():
|
||||
if (
|
||||
Capability.SWITCH in device.status[MAIN]
|
||||
and not any(
|
||||
capability in device.status[MAIN] for capability in CAPABILITIES
|
||||
)
|
||||
and not all(
|
||||
capability in device.status[MAIN] for capability in AC_CAPABILITIES
|
||||
)
|
||||
):
|
||||
media_player = all(
|
||||
capability in device.status[MAIN]
|
||||
for capability in MEDIA_PLAYER_CAPABILITIES
|
||||
)
|
||||
appliance = (
|
||||
device.device.components[MAIN].manufacturer_category
|
||||
in INVALID_SWITCH_CATEGORIES
|
||||
)
|
||||
if media_player or appliance:
|
||||
issue = "media_player" if media_player else "appliance"
|
||||
if deprecate_entity(
|
||||
hass,
|
||||
entity_registry,
|
||||
SWITCH_DOMAIN,
|
||||
f"{device.device.device_id}_{MAIN}_{Capability.SWITCH}_{Attribute.SWITCH}_{Attribute.SWITCH}",
|
||||
f"deprecated_switch_{issue}",
|
||||
):
|
||||
entities.append(
|
||||
SmartThingsSwitch(
|
||||
entry_data.client,
|
||||
device,
|
||||
SWITCH,
|
||||
Capability.SWITCH,
|
||||
)
|
||||
)
|
||||
continue
|
||||
entities.append(
|
||||
SmartThingsSwitch(
|
||||
entry_data.client,
|
||||
device,
|
||||
SWITCH,
|
||||
Capability.SWITCH,
|
||||
)
|
||||
)
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
@ -136,7 +178,6 @@ class SmartThingsSwitch(SmartThingsEntity, SwitchEntity):
|
||||
"""Define a SmartThings switch."""
|
||||
|
||||
entity_description: SmartThingsSwitchEntityDescription
|
||||
created_issue: bool = False
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -182,70 +223,6 @@ class SmartThingsSwitch(SmartThingsEntity, SwitchEntity):
|
||||
== "on"
|
||||
)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Call when entity is added to hass."""
|
||||
await super().async_added_to_hass()
|
||||
media_player = all(
|
||||
capability in self.device.status[MAIN]
|
||||
for capability in (
|
||||
Capability.AUDIO_MUTE,
|
||||
Capability.AUDIO_VOLUME,
|
||||
Capability.MEDIA_PLAYBACK,
|
||||
)
|
||||
)
|
||||
if (
|
||||
self.entity_description != SWITCH
|
||||
and self.device.device.components[MAIN].manufacturer_category
|
||||
not in {
|
||||
Category.CLOTHING_CARE_MACHINE,
|
||||
Category.COOKTOP,
|
||||
Category.DRYER,
|
||||
Category.WASHER,
|
||||
Category.MICROWAVE,
|
||||
Category.DISHWASHER,
|
||||
}
|
||||
) or (self.entity_description != SWITCH and not media_player):
|
||||
return
|
||||
automations = automations_with_entity(self.hass, self.entity_id)
|
||||
scripts = scripts_with_entity(self.hass, self.entity_id)
|
||||
if not automations and not scripts:
|
||||
return
|
||||
|
||||
entity_reg: er.EntityRegistry = er.async_get(self.hass)
|
||||
items_list = [
|
||||
f"- [{item.original_name}](/config/{integration}/edit/{item.unique_id})"
|
||||
for integration, entities in (
|
||||
("automation", automations),
|
||||
("script", scripts),
|
||||
)
|
||||
for entity_id in entities
|
||||
if (item := entity_reg.async_get(entity_id))
|
||||
]
|
||||
|
||||
identifier = "media_player" if media_player else "appliance"
|
||||
|
||||
self.created_issue = True
|
||||
async_create_issue(
|
||||
self.hass,
|
||||
DOMAIN,
|
||||
f"deprecated_switch_{self.entity_id}",
|
||||
breaks_in_ha_version="2025.10.0",
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key=f"deprecated_switch_{identifier}",
|
||||
translation_placeholders={
|
||||
"entity": self.entity_id,
|
||||
"items": "\n".join(items_list),
|
||||
},
|
||||
)
|
||||
|
||||
async def async_will_remove_from_hass(self) -> None:
|
||||
"""Call when entity will be removed from hass."""
|
||||
await super().async_will_remove_from_hass()
|
||||
if not self.created_issue:
|
||||
return
|
||||
async_delete_issue(self.hass, DOMAIN, f"deprecated_switch_{self.entity_id}")
|
||||
|
||||
|
||||
class SmartThingsCommandSwitch(SmartThingsSwitch):
|
||||
"""Define a SmartThings command switch."""
|
||||
|
@ -46,100 +46,6 @@
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_ks_cooktop_31001][switch.induction_hob-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.induction_hob',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '808dbd84-f357-47e2-a0cd-3b66fa22d584_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_ks_cooktop_31001][switch.induction_hob-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Induction Hob',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.induction_hob',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_ks_microwave_0101x][switch.microwave-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.microwave',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '2bad3237-4886-e699-1b90-4a51a3d55c8a_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_ks_microwave_0101x][switch.microwave-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Microwave',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.microwave',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_ref_normal_000001][switch.refrigerator_ice_maker-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@ -281,147 +187,6 @@
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_dw_000001][switch.dishwasher-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.dishwasher',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'f36dc7ce-cac0-0667-dc14-a3704eb5e676_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_dw_000001][switch.dishwasher-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Dishwasher',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.dishwasher',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_sc_000001][switch.airdresser-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.airdresser',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'b93211bf-9d96-bd21-3b2f-964fcc87f5cc_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_sc_000001][switch.airdresser-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'AirDresser',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.airdresser',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wd_000001][switch.dryer-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.dryer',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '02f7256e-8353-5bdd-547f-bd5b1647e01b_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wd_000001][switch.dryer-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Dryer',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.dryer',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wd_000001][switch.dryer_wrinkle_prevent-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@ -469,53 +234,6 @@
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wd_000001_1][switch.seca_roupa-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.seca_roupa',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '3a6c4e05-811d-5041-e956-3d04c424cbcd_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wd_000001_1][switch.seca_roupa-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Seca-Roupa',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.seca_roupa',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wd_000001_1][switch.seca_roupa_wrinkle_prevent-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@ -563,100 +281,6 @@
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wm_000001][switch.washer-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.washer',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'f984b91d-f250-9d42-3436-33f09a422a47_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wm_000001][switch.washer-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Washer',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.washer',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wm_000001_1][switch.washing_machine-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.washing_machine',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '63803fae-cbed-f356-a063-2cf148ae3ca7_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wm_000001_1][switch.washing_machine-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Washing Machine',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.washing_machine',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[da_wm_wm_000001_1][switch.washing_machine_bubble_soak-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@ -751,53 +375,6 @@
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[hw_q80r_soundbar][switch.soundbar-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.soundbar',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'afcf3b91-0000-1111-2222-ddff2a0a6577_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[hw_q80r_soundbar][switch.soundbar-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Soundbar',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.soundbar',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensibo_airconditioner_1][switch.office-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@ -939,53 +516,6 @@
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[vd_network_audio_002s][switch.soundbar_living-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.soundbar_living',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '0d94e5db-8501-2355-eb4f-214163702cac_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[vd_network_audio_002s][switch.soundbar_living-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Soundbar Living',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.soundbar_living',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[vd_sensor_light_2023][switch.light_sensor_55_the_frame-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@ -1033,50 +563,3 @@
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[vd_stv_2017_k][switch.tv_samsung_8_series_49-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'switch',
|
||||
'entity_category': None,
|
||||
'entity_id': 'switch.tv_samsung_8_series_49',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': None,
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_main_switch_switch_switch',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[vd_stv_2017_k][switch.tv_samsung_8_series_49-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': '[TV] Samsung 8 Series (49)',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'switch.tv_samsung_8_series_49',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'on',
|
||||
})
|
||||
# ---
|
||||
|
@ -126,25 +126,86 @@ async def test_state_update(
|
||||
assert hass.states.get("switch.2nd_floor_hallway").state == STATE_OFF
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
@pytest.mark.parametrize(
|
||||
("device_fixture", "entity_id", "translation_key"),
|
||||
("device_fixture", "device_id", "suggested_object_id", "issue_string"),
|
||||
[
|
||||
("da_wm_wm_000001", "switch.washer", "deprecated_switch_appliance"),
|
||||
("da_wm_wd_000001", "switch.dryer", "deprecated_switch_appliance"),
|
||||
("hw_q80r_soundbar", "switch.soundbar", "deprecated_switch_media_player"),
|
||||
(
|
||||
"da_ks_cooktop_31001",
|
||||
"808dbd84-f357-47e2-a0cd-3b66fa22d584",
|
||||
"induction_hob",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"da_ks_microwave_0101x",
|
||||
"2bad3237-4886-e699-1b90-4a51a3d55c8a",
|
||||
"microwave",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"da_wm_dw_000001",
|
||||
"f36dc7ce-cac0-0667-dc14-a3704eb5e676",
|
||||
"dishwasher",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"da_wm_sc_000001",
|
||||
"b93211bf-9d96-bd21-3b2f-964fcc87f5cc",
|
||||
"airdresser",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"da_wm_wd_000001",
|
||||
"02f7256e-8353-5bdd-547f-bd5b1647e01b",
|
||||
"dryer",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"da_wm_wm_000001",
|
||||
"f984b91d-f250-9d42-3436-33f09a422a47",
|
||||
"washer",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"hw_q80r_soundbar",
|
||||
"afcf3b91-0000-1111-2222-ddff2a0a6577",
|
||||
"soundbar",
|
||||
"media_player",
|
||||
),
|
||||
(
|
||||
"vd_network_audio_002s",
|
||||
"0d94e5db-8501-2355-eb4f-214163702cac",
|
||||
"soundbar_living",
|
||||
"media_player",
|
||||
),
|
||||
(
|
||||
"vd_stv_2017_k",
|
||||
"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1",
|
||||
"tv_samsung_8_series_49",
|
||||
"media_player",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_create_issue(
|
||||
async def test_create_issue_with_items(
|
||||
hass: HomeAssistant,
|
||||
devices: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
entity_id: str,
|
||||
translation_key: str,
|
||||
device_id: str,
|
||||
suggested_object_id: str,
|
||||
issue_string: str,
|
||||
) -> None:
|
||||
"""Test we create an issue when an automation or script is using a deprecated entity."""
|
||||
issue_id = f"deprecated_switch_{entity_id}"
|
||||
entity_id = f"switch.{suggested_object_id}"
|
||||
issue_id = f"deprecated_switch_{issue_string}_{entity_id}"
|
||||
|
||||
entity_entry = entity_registry.async_get_or_create(
|
||||
SWITCH_DOMAIN,
|
||||
DOMAIN,
|
||||
f"{device_id}_{MAIN}_{Capability.SWITCH}_{Attribute.SWITCH}_{Attribute.SWITCH}",
|
||||
suggested_object_id=suggested_object_id,
|
||||
original_name=suggested_object_id,
|
||||
)
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
@ -183,19 +244,134 @@ async def test_create_issue(
|
||||
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert hass.states.get(entity_id).state in [STATE_OFF, STATE_ON]
|
||||
|
||||
assert automations_with_entity(hass, entity_id)[0] == "automation.test"
|
||||
assert scripts_with_entity(hass, entity_id)[0] == "script.test"
|
||||
|
||||
assert len(issue_registry.issues) == 1
|
||||
issue = issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||
assert issue is not None
|
||||
assert issue.translation_key == translation_key
|
||||
assert issue.translation_key == f"deprecated_switch_{issue_string}_scripts"
|
||||
assert issue.translation_placeholders == {
|
||||
"entity": entity_id,
|
||||
"entity_id": entity_id,
|
||||
"entity_name": suggested_object_id,
|
||||
"items": "- [test](/config/automation/edit/test)\n- [test](/config/script/edit/test)",
|
||||
}
|
||||
|
||||
await hass.config_entries.async_unload(mock_config_entry.entry_id)
|
||||
entity_registry.async_update_entity(
|
||||
entity_entry.entity_id,
|
||||
disabled_by=er.RegistryEntryDisabler.USER,
|
||||
)
|
||||
|
||||
await hass.config_entries.async_reload(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Assert the issue is no longer present
|
||||
assert not issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||
assert len(issue_registry.issues) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("device_fixture", "device_id", "suggested_object_id", "issue_string"),
|
||||
[
|
||||
(
|
||||
"da_ks_cooktop_31001",
|
||||
"808dbd84-f357-47e2-a0cd-3b66fa22d584",
|
||||
"induction_hob",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"da_ks_microwave_0101x",
|
||||
"2bad3237-4886-e699-1b90-4a51a3d55c8a",
|
||||
"microwave",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"da_wm_dw_000001",
|
||||
"f36dc7ce-cac0-0667-dc14-a3704eb5e676",
|
||||
"dishwasher",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"da_wm_sc_000001",
|
||||
"b93211bf-9d96-bd21-3b2f-964fcc87f5cc",
|
||||
"airdresser",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"da_wm_wd_000001",
|
||||
"02f7256e-8353-5bdd-547f-bd5b1647e01b",
|
||||
"dryer",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"da_wm_wm_000001",
|
||||
"f984b91d-f250-9d42-3436-33f09a422a47",
|
||||
"washer",
|
||||
"appliance",
|
||||
),
|
||||
(
|
||||
"hw_q80r_soundbar",
|
||||
"afcf3b91-0000-1111-2222-ddff2a0a6577",
|
||||
"soundbar",
|
||||
"media_player",
|
||||
),
|
||||
(
|
||||
"vd_network_audio_002s",
|
||||
"0d94e5db-8501-2355-eb4f-214163702cac",
|
||||
"soundbar_living",
|
||||
"media_player",
|
||||
),
|
||||
(
|
||||
"vd_stv_2017_k",
|
||||
"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1",
|
||||
"tv_samsung_8_series_49",
|
||||
"media_player",
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_create_issue(
|
||||
hass: HomeAssistant,
|
||||
devices: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
entity_registry: er.EntityRegistry,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
device_id: str,
|
||||
suggested_object_id: str,
|
||||
issue_string: str,
|
||||
) -> None:
|
||||
"""Test we create an issue when an automation or script is using a deprecated entity."""
|
||||
entity_id = f"switch.{suggested_object_id}"
|
||||
issue_id = f"deprecated_switch_{issue_string}_{entity_id}"
|
||||
|
||||
entity_entry = entity_registry.async_get_or_create(
|
||||
SWITCH_DOMAIN,
|
||||
DOMAIN,
|
||||
f"{device_id}_{MAIN}_{Capability.SWITCH}_{Attribute.SWITCH}_{Attribute.SWITCH}",
|
||||
suggested_object_id=suggested_object_id,
|
||||
original_name=suggested_object_id,
|
||||
)
|
||||
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert hass.states.get(entity_id).state in [STATE_OFF, STATE_ON]
|
||||
|
||||
assert len(issue_registry.issues) == 1
|
||||
issue = issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||
assert issue is not None
|
||||
assert issue.translation_key == f"deprecated_switch_{issue_string}"
|
||||
assert issue.translation_placeholders == {
|
||||
"entity_id": entity_id,
|
||||
"entity_name": suggested_object_id,
|
||||
}
|
||||
|
||||
entity_registry.async_update_entity(
|
||||
entity_entry.entity_id,
|
||||
disabled_by=er.RegistryEntryDisabler.USER,
|
||||
)
|
||||
|
||||
await hass.config_entries.async_reload(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Assert the issue is no longer present
|
||||
|
Loading…
x
Reference in New Issue
Block a user