diff --git a/homeassistant/components/smartthings/sensor.py b/homeassistant/components/smartthings/sensor.py index 424483d9617..346516be480 100644 --- a/homeassistant/components/smartthings/sensor.py +++ b/homeassistant/components/smartthings/sensor.py @@ -9,9 +9,8 @@ from typing import Any, cast from pysmartthings import Attribute, Capability, ComponentStatus, SmartThings, Status -from homeassistant.components.automation import automations_with_entity -from homeassistant.components.script import scripts_with_entity from homeassistant.components.sensor import ( + DOMAIN as SENSOR_DOMAIN, SensorDeviceClass, SensorEntity, SensorEntityDescription, @@ -33,16 +32,12 @@ from homeassistant.const import ( 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 homeassistant.util import dt as dt_util from . import FullDevice, SmartThingsConfigEntry -from .const import DOMAIN, MAIN +from .const import MAIN from .entity import SmartThingsEntity +from .util import deprecate_entity THERMOSTAT_CAPABILITIES = { Capability.TEMPERATURE_MEASUREMENT, @@ -1021,31 +1016,67 @@ async def async_setup_entry( ) -> None: """Add sensors for a config entry.""" entry_data = entry.runtime_data - async_add_entities( - SmartThingsSensor( - entry_data.client, - device, - description, - capability, - attribute, - ) - for device in entry_data.devices.values() - for capability, attributes in CAPABILITY_TO_SENSORS.items() - if capability in device.status[MAIN] - for attribute, descriptions in attributes.items() - for description in descriptions - if ( - not description.capability_ignore_list - or not any( - all(capability in device.status[MAIN] for capability in capability_list) - for capability_list in description.capability_ignore_list - ) - ) - and ( - not description.exists_fn - or description.exists_fn(device.status[MAIN][capability][attribute]) - ) - ) + entities = [] + + entity_registry = er.async_get(hass) + + for device in entry_data.devices.values(): # pylint: disable=too-many-nested-blocks + for capability, attributes in CAPABILITY_TO_SENSORS.items(): + if capability in device.status[MAIN]: + for attribute, descriptions in attributes.items(): + for description in descriptions: + if ( + not description.capability_ignore_list + or not any( + all( + capability in device.status[MAIN] + for capability in capability_list + ) + for capability_list in description.capability_ignore_list + ) + ) and ( + not description.exists_fn + or description.exists_fn( + device.status[MAIN][capability][attribute] + ) + ): + if ( + description.deprecated + and ( + reason := description.deprecated( + device.status[MAIN] + ) + ) + is not None + ): + if deprecate_entity( + hass, + entity_registry, + SENSOR_DOMAIN, + f"{device.device.device_id}_{MAIN}_{capability}_{attribute}_{description.key}", + f"deprecated_{reason}", + ): + entities.append( + SmartThingsSensor( + entry_data.client, + device, + description, + capability, + attribute, + ) + ) + continue + entities.append( + SmartThingsSensor( + entry_data.client, + device, + description, + capability, + attribute, + ) + ) + + async_add_entities(entities) class SmartThingsSensor(SmartThingsEntity, SensorEntity): @@ -1113,53 +1144,3 @@ class SmartThingsSensor(SmartThingsEntity, SensorEntity): return [] return [option.lower() for option in options] return super().options - - async def async_added_to_hass(self) -> None: - """Call when entity is added to hass.""" - await super().async_added_to_hass() - if ( - not self.entity_description.deprecated - or (reason := self.entity_description.deprecated(self.device.status[MAIN])) - is None - ): - 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)) - ] - - async_create_issue( - self.hass, - DOMAIN, - f"deprecated_{reason}_{self.entity_id}", - breaks_in_ha_version="2025.10.0", - is_fixable=False, - severity=IssueSeverity.WARNING, - translation_key=f"deprecated_{reason}", - 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.entity_description.deprecated - or (reason := self.entity_description.deprecated(self.device.status[MAIN])) - is None - ): - return - async_delete_issue(self.hass, DOMAIN, f"deprecated_{reason}_{self.entity_id}") diff --git a/homeassistant/components/smartthings/strings.json b/homeassistant/components/smartthings/strings.json index 1fbe535261e..43c6a22e66a 100644 --- a/homeassistant/components/smartthings/strings.json +++ b/homeassistant/components/smartthings/strings.json @@ -504,8 +504,12 @@ "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." }, "deprecated_media_player": { + "title": "Media player sensors deprecated", + "description": "The sensor {entity_name} (`{entity_id}`) is deprecated because it has been replaced with a media player entity.\n\nPlease update your dashboards, templates to use the new media player entity and disable the entity to fix this issue." + }, + "deprecated_media_player_scripts": { "title": "Deprecated sensor detected in some automations or scripts", - "description": "The sensor `{entity}` 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 the new media player entity in the above automations or scripts 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 use them in the above automations or scripts to use the new media player entity and disable the entity to fix this issue." } } } diff --git a/tests/components/smartthings/snapshots/test_sensor.ambr b/tests/components/smartthings/snapshots/test_sensor.ambr index 7be10ebac91..8ace345be18 100644 --- a/tests/components/smartthings/snapshots/test_sensor.ambr +++ b/tests/components/smartthings/snapshots/test_sensor.ambr @@ -8366,182 +8366,6 @@ 'state': '19.0', }) # --- -# name: test_all_entities[hw_q80r_soundbar][sensor.soundbar_media_input_source-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'wifi', - 'bluetooth', - 'hdmi1', - 'hdmi2', - 'digital', - ]), - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.soundbar_media_input_source', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Media input source', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'media_input_source', - 'unique_id': 'afcf3b91-0000-1111-2222-ddff2a0a6577_main_mediaInputSource_inputSource_inputSource', - 'unit_of_measurement': None, - }) -# --- -# name: test_all_entities[hw_q80r_soundbar][sensor.soundbar_media_input_source-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'Soundbar Media input source', - 'options': list([ - 'wifi', - 'bluetooth', - 'hdmi1', - 'hdmi2', - 'digital', - ]), - }), - 'context': , - 'entity_id': 'sensor.soundbar_media_input_source', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'wifi', - }) -# --- -# name: test_all_entities[hw_q80r_soundbar][sensor.soundbar_media_playback_status-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'paused', - 'playing', - 'stopped', - 'fast_forwarding', - 'rewinding', - 'buffering', - ]), - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.soundbar_media_playback_status', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Media playback status', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'media_playback_status', - 'unique_id': 'afcf3b91-0000-1111-2222-ddff2a0a6577_main_mediaPlayback_playbackStatus_playbackStatus', - 'unit_of_measurement': None, - }) -# --- -# name: test_all_entities[hw_q80r_soundbar][sensor.soundbar_media_playback_status-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'Soundbar Media playback status', - 'options': list([ - 'paused', - 'playing', - 'stopped', - 'fast_forwarding', - 'rewinding', - 'buffering', - ]), - }), - 'context': , - 'entity_id': 'sensor.soundbar_media_playback_status', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'playing', - }) -# --- -# name: test_all_entities[hw_q80r_soundbar][sensor.soundbar_volume-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.soundbar_volume', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Volume', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'audio_volume', - 'unique_id': 'afcf3b91-0000-1111-2222-ddff2a0a6577_main_audioVolume_volume_volume', - 'unit_of_measurement': '%', - }) -# --- -# name: test_all_entities[hw_q80r_soundbar][sensor.soundbar_volume-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'Soundbar Volume', - 'unit_of_measurement': '%', - }), - 'context': , - 'entity_id': 'sensor.soundbar_volume', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '1', - }) -# --- # name: test_all_entities[ikea_kadrilj][sensor.kitchen_ikea_kadrilj_window_blind_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -8591,261 +8415,6 @@ 'state': '37', }) # --- -# name: test_all_entities[im_speaker_ai_0001][sensor.galaxy_home_mini_media_input_source-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.galaxy_home_mini_media_input_source', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Media input source', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'media_input_source', - 'unique_id': 'c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_main_mediaInputSource_inputSource_inputSource', - 'unit_of_measurement': None, - }) -# --- -# name: test_all_entities[im_speaker_ai_0001][sensor.galaxy_home_mini_media_input_source-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'Galaxy Home Mini Media input source', - }), - 'context': , - 'entity_id': 'sensor.galaxy_home_mini_media_input_source', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unknown', - }) -# --- -# name: test_all_entities[im_speaker_ai_0001][sensor.galaxy_home_mini_media_playback_repeat-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.galaxy_home_mini_media_playback_repeat', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Media playback repeat', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'media_playback_repeat', - 'unique_id': 'c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_main_mediaPlaybackRepeat_playbackRepeatMode_playbackRepeatMode', - 'unit_of_measurement': None, - }) -# --- -# name: test_all_entities[im_speaker_ai_0001][sensor.galaxy_home_mini_media_playback_repeat-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'Galaxy Home Mini Media playback repeat', - }), - 'context': , - 'entity_id': 'sensor.galaxy_home_mini_media_playback_repeat', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'off', - }) -# --- -# name: test_all_entities[im_speaker_ai_0001][sensor.galaxy_home_mini_media_playback_shuffle-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.galaxy_home_mini_media_playback_shuffle', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Media playback shuffle', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'media_playback_shuffle', - 'unique_id': 'c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_main_mediaPlaybackShuffle_playbackShuffle_playbackShuffle', - 'unit_of_measurement': None, - }) -# --- -# name: test_all_entities[im_speaker_ai_0001][sensor.galaxy_home_mini_media_playback_shuffle-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'Galaxy Home Mini Media playback shuffle', - }), - 'context': , - 'entity_id': 'sensor.galaxy_home_mini_media_playback_shuffle', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'disabled', - }) -# --- -# name: test_all_entities[im_speaker_ai_0001][sensor.galaxy_home_mini_media_playback_status-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'paused', - 'playing', - 'stopped', - 'fast_forwarding', - 'rewinding', - 'buffering', - ]), - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.galaxy_home_mini_media_playback_status', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Media playback status', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'media_playback_status', - 'unique_id': 'c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_main_mediaPlayback_playbackStatus_playbackStatus', - 'unit_of_measurement': None, - }) -# --- -# name: test_all_entities[im_speaker_ai_0001][sensor.galaxy_home_mini_media_playback_status-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'Galaxy Home Mini Media playback status', - 'options': list([ - 'paused', - 'playing', - 'stopped', - 'fast_forwarding', - 'rewinding', - 'buffering', - ]), - }), - 'context': , - 'entity_id': 'sensor.galaxy_home_mini_media_playback_status', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'stopped', - }) -# --- -# name: test_all_entities[im_speaker_ai_0001][sensor.galaxy_home_mini_volume-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.galaxy_home_mini_volume', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Volume', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'audio_volume', - 'unique_id': 'c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_main_audioVolume_volume_volume', - 'unit_of_measurement': '%', - }) -# --- -# name: test_all_entities[im_speaker_ai_0001][sensor.galaxy_home_mini_volume-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'Galaxy Home Mini Volume', - 'unit_of_measurement': '%', - }), - 'context': , - 'entity_id': 'sensor.galaxy_home_mini_volume', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '52', - }) -# --- # name: test_all_entities[multipurpose_sensor][sensor.deck_door_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -9184,119 +8753,6 @@ 'state': '20', }) # --- -# name: test_all_entities[sonos_player][sensor.elliots_rum_media_playback_status-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'paused', - 'playing', - 'stopped', - 'fast_forwarding', - 'rewinding', - 'buffering', - ]), - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.elliots_rum_media_playback_status', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Media playback status', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'media_playback_status', - 'unique_id': 'c85fced9-c474-4a47-93c2-037cc7829536_main_mediaPlayback_playbackStatus_playbackStatus', - 'unit_of_measurement': None, - }) -# --- -# name: test_all_entities[sonos_player][sensor.elliots_rum_media_playback_status-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'Elliots Rum Media playback status', - 'options': list([ - 'paused', - 'playing', - 'stopped', - 'fast_forwarding', - 'rewinding', - 'buffering', - ]), - }), - 'context': , - 'entity_id': 'sensor.elliots_rum_media_playback_status', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'playing', - }) -# --- -# name: test_all_entities[sonos_player][sensor.elliots_rum_volume-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.elliots_rum_volume', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Volume', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'audio_volume', - 'unique_id': 'c85fced9-c474-4a47-93c2-037cc7829536_main_audioVolume_volume_volume', - 'unit_of_measurement': '%', - }) -# --- -# name: test_all_entities[sonos_player][sensor.elliots_rum_volume-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'Elliots Rum Volume', - 'unit_of_measurement': '%', - }), - 'context': , - 'entity_id': 'sensor.elliots_rum_volume', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '15', - }) -# --- # name: test_all_entities[tplink_p110][sensor.spulmaschine_energy-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -9407,119 +8863,6 @@ 'state': '0.0', }) # --- -# name: test_all_entities[vd_network_audio_002s][sensor.soundbar_living_media_playback_status-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'paused', - 'playing', - 'stopped', - 'fast_forwarding', - 'rewinding', - 'buffering', - ]), - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.soundbar_living_media_playback_status', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Media playback status', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'media_playback_status', - 'unique_id': '0d94e5db-8501-2355-eb4f-214163702cac_main_mediaPlayback_playbackStatus_playbackStatus', - 'unit_of_measurement': None, - }) -# --- -# name: test_all_entities[vd_network_audio_002s][sensor.soundbar_living_media_playback_status-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'Soundbar Living Media playback status', - 'options': list([ - 'paused', - 'playing', - 'stopped', - 'fast_forwarding', - 'rewinding', - 'buffering', - ]), - }), - 'context': , - 'entity_id': 'sensor.soundbar_living_media_playback_status', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'stopped', - }) -# --- -# name: test_all_entities[vd_network_audio_002s][sensor.soundbar_living_volume-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.soundbar_living_volume', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Volume', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'audio_volume', - 'unique_id': '0d94e5db-8501-2355-eb4f-214163702cac_main_audioVolume_volume_volume', - 'unit_of_measurement': '%', - }) -# --- -# name: test_all_entities[vd_network_audio_002s][sensor.soundbar_living_volume-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'Soundbar Living Volume', - 'unit_of_measurement': '%', - }), - 'context': , - 'entity_id': 'sensor.soundbar_living_volume', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '17', - }) -# --- # name: test_all_entities[vd_sensor_light_2023][sensor.light_sensor_55_the_frame_brightness_intensity-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -9571,132 +8914,6 @@ 'state': '2', }) # --- -# name: test_all_entities[vd_stv_2017_k][sensor.tv_samsung_8_series_49_media_input_source-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'digitaltv', - 'hdmi1', - 'hdmi4', - 'hdmi4', - ]), - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.tv_samsung_8_series_49_media_input_source', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Media input source', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'media_input_source', - 'unique_id': '4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_main_mediaInputSource_inputSource_inputSource', - 'unit_of_measurement': None, - }) -# --- -# name: test_all_entities[vd_stv_2017_k][sensor.tv_samsung_8_series_49_media_input_source-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': '[TV] Samsung 8 Series (49) Media input source', - 'options': list([ - 'digitaltv', - 'hdmi1', - 'hdmi4', - 'hdmi4', - ]), - }), - 'context': , - 'entity_id': 'sensor.tv_samsung_8_series_49_media_input_source', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'hdmi1', - }) -# --- -# name: test_all_entities[vd_stv_2017_k][sensor.tv_samsung_8_series_49_media_playback_status-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'paused', - 'playing', - 'stopped', - 'fast_forwarding', - 'rewinding', - 'buffering', - ]), - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.tv_samsung_8_series_49_media_playback_status', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Media playback status', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'media_playback_status', - 'unique_id': '4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_main_mediaPlayback_playbackStatus_playbackStatus', - 'unit_of_measurement': None, - }) -# --- -# name: test_all_entities[vd_stv_2017_k][sensor.tv_samsung_8_series_49_media_playback_status-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': '[TV] Samsung 8 Series (49) Media playback status', - 'options': list([ - 'paused', - 'playing', - 'stopped', - 'fast_forwarding', - 'rewinding', - 'buffering', - ]), - }), - 'context': , - 'entity_id': 'sensor.tv_samsung_8_series_49_media_playback_status', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'unknown', - }) -# --- # name: test_all_entities[vd_stv_2017_k][sensor.tv_samsung_8_series_49_tv_channel-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -9791,54 +9008,6 @@ 'state': '', }) # --- -# name: test_all_entities[vd_stv_2017_k][sensor.tv_samsung_8_series_49_volume-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.tv_samsung_8_series_49_volume', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Volume', - 'platform': 'smartthings', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'audio_volume', - 'unique_id': '4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_main_audioVolume_volume_volume', - 'unit_of_measurement': '%', - }) -# --- -# name: test_all_entities[vd_stv_2017_k][sensor.tv_samsung_8_series_49_volume-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': '[TV] Samsung 8 Series (49) Volume', - 'unit_of_measurement': '%', - }), - 'context': , - 'entity_id': 'sensor.tv_samsung_8_series_49_volume', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '13', - }) -# --- # name: test_all_entities[virtual_thermostat][sensor.asd_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/smartthings/test_binary_sensor.py b/tests/components/smartthings/test_binary_sensor.py index f7fcde3746f..9f9d8d66317 100644 --- a/tests/components/smartthings/test_binary_sensor.py +++ b/tests/components/smartthings/test_binary_sensor.py @@ -60,7 +60,6 @@ async def test_state_update( assert hass.states.get("binary_sensor.refrigerator_cooler_door").state == STATE_ON -@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.parametrize( ("device_fixture", "unique_id", "suggested_object_id", "issue_string", "entity_id"), [ @@ -167,7 +166,6 @@ async def test_create_issue_with_items( assert len(issue_registry.issues) == 0 -@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.parametrize( ("device_fixture", "unique_id", "suggested_object_id", "issue_string", "entity_id"), [ diff --git a/tests/components/smartthings/test_sensor.py b/tests/components/smartthings/test_sensor.py index fe112b3db6b..e90c177bd6d 100644 --- a/tests/components/smartthings/test_sensor.py +++ b/tests/components/smartthings/test_sensor.py @@ -9,8 +9,9 @@ from syrupy import SnapshotAssertion from homeassistant.components import automation, script from homeassistant.components.automation import automations_with_entity from homeassistant.components.script import scripts_with_entity -from homeassistant.components.smartthings.const import DOMAIN -from homeassistant.const import Platform +from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN +from homeassistant.components.smartthings.const import DOMAIN, MAIN +from homeassistant.const import STATE_UNKNOWN, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er, issue_registry as ir from homeassistant.setup import async_setup_component @@ -56,35 +57,80 @@ async def test_state_update( assert hass.states.get("sensor.ac_office_granit_temperature").state == "20" -@pytest.mark.usefixtures("entity_registry_enabled_by_default") @pytest.mark.parametrize( - ("device_fixture", "entity_id", "translation_key"), + ( + "device_fixture", + "unique_id", + "suggested_object_id", + "issue_string", + "entity_id", + "expected_state", + ), [ - ("hw_q80r_soundbar", "sensor.soundbar_volume", "media_player"), - ("hw_q80r_soundbar", "sensor.soundbar_media_playback_status", "media_player"), - ("hw_q80r_soundbar", "sensor.soundbar_media_input_source", "media_player"), ( - "im_speaker_ai_0001", - "sensor.galaxy_home_mini_media_playback_shuffle", + "vd_stv_2017_k", + f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.MEDIA_PLAYBACK}_{Attribute.PLAYBACK_STATUS}_{Attribute.PLAYBACK_STATUS}", + "tv_samsung_8_series_49_media_playback_status", "media_player", + "sensor.tv_samsung_8_series_49_media_playback_status", + STATE_UNKNOWN, + ), + ( + "vd_stv_2017_k", + f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.AUDIO_VOLUME}_{Attribute.VOLUME}_{Attribute.VOLUME}", + "tv_samsung_8_series_49_volume", + "media_player", + "sensor.tv_samsung_8_series_49_volume", + "13", + ), + ( + "vd_stv_2017_k", + f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.MEDIA_INPUT_SOURCE}_{Attribute.INPUT_SOURCE}_{Attribute.INPUT_SOURCE}", + "tv_samsung_8_series_49_media_input_source", + "media_player", + "sensor.tv_samsung_8_series_49_media_input_source", + "hdmi1", ), ( "im_speaker_ai_0001", - "sensor.galaxy_home_mini_media_playback_repeat", + f"c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_{MAIN}_{Capability.MEDIA_PLAYBACK_REPEAT}_{Attribute.PLAYBACK_REPEAT_MODE}_{Attribute.PLAYBACK_REPEAT_MODE}", + "galaxy_home_mini_media_playback_repeat", "media_player", + "sensor.galaxy_home_mini_media_playback_repeat", + "off", + ), + ( + "im_speaker_ai_0001", + f"c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_{MAIN}_{Capability.MEDIA_PLAYBACK_SHUFFLE}_{Attribute.PLAYBACK_SHUFFLE}_{Attribute.PLAYBACK_SHUFFLE}", + "galaxy_home_mini_media_playback_shuffle", + "media_player", + "sensor.galaxy_home_mini_media_playback_shuffle", + "disabled", ), ], ) -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, + unique_id: str, + suggested_object_id: str, + issue_string: str, entity_id: str, - translation_key: str, + expected_state: str, ) -> None: """Test we create an issue when an automation or script is using a deprecated entity.""" - issue_id = f"deprecated_{translation_key}_{entity_id}" + issue_id = f"deprecated_{issue_string}_{entity_id}" + + entity_entry = entity_registry.async_get_or_create( + SENSOR_DOMAIN, + DOMAIN, + unique_id, + suggested_object_id=suggested_object_id, + original_name=suggested_object_id, + ) assert await async_setup_component( hass, @@ -123,19 +169,128 @@ async def test_create_issue( await setup_integration(hass, mock_config_entry) + assert hass.states.get(entity_id).state == expected_state + 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 == f"deprecated_{translation_key}" + assert issue.translation_key == f"deprecated_{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", + "unique_id", + "suggested_object_id", + "issue_string", + "entity_id", + "expected_state", + ), + [ + ( + "vd_stv_2017_k", + f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.MEDIA_PLAYBACK}_{Attribute.PLAYBACK_STATUS}_{Attribute.PLAYBACK_STATUS}", + "tv_samsung_8_series_49_media_playback_status", + "media_player", + "sensor.tv_samsung_8_series_49_media_playback_status", + STATE_UNKNOWN, + ), + ( + "vd_stv_2017_k", + f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.AUDIO_VOLUME}_{Attribute.VOLUME}_{Attribute.VOLUME}", + "tv_samsung_8_series_49_volume", + "media_player", + "sensor.tv_samsung_8_series_49_volume", + "13", + ), + ( + "vd_stv_2017_k", + f"4588d2d9-a8cf-40f4-9a0b-ed5dfbaccda1_{MAIN}_{Capability.MEDIA_INPUT_SOURCE}_{Attribute.INPUT_SOURCE}_{Attribute.INPUT_SOURCE}", + "tv_samsung_8_series_49_media_input_source", + "media_player", + "sensor.tv_samsung_8_series_49_media_input_source", + "hdmi1", + ), + ( + "im_speaker_ai_0001", + f"c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_{MAIN}_{Capability.MEDIA_PLAYBACK_REPEAT}_{Attribute.PLAYBACK_REPEAT_MODE}_{Attribute.PLAYBACK_REPEAT_MODE}", + "galaxy_home_mini_media_playback_repeat", + "media_player", + "sensor.galaxy_home_mini_media_playback_repeat", + "off", + ), + ( + "im_speaker_ai_0001", + f"c9276e43-fe3c-88c3-1dcc-2eb79e292b8c_{MAIN}_{Capability.MEDIA_PLAYBACK_SHUFFLE}_{Attribute.PLAYBACK_SHUFFLE}_{Attribute.PLAYBACK_SHUFFLE}", + "galaxy_home_mini_media_playback_shuffle", + "media_player", + "sensor.galaxy_home_mini_media_playback_shuffle", + "disabled", + ), + ], +) +async def test_create_issue( + hass: HomeAssistant, + devices: AsyncMock, + mock_config_entry: MockConfigEntry, + entity_registry: er.EntityRegistry, + issue_registry: ir.IssueRegistry, + unique_id: str, + suggested_object_id: str, + issue_string: str, + entity_id: str, + expected_state: str, +) -> None: + """Test we create an issue when an automation or script is using a deprecated entity.""" + issue_id = f"deprecated_{issue_string}_{entity_id}" + + entity_entry = entity_registry.async_get_or_create( + SENSOR_DOMAIN, + DOMAIN, + unique_id, + 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 == expected_state + + 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_{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