mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 02:37:08 +00:00
Deprecate media player sensors for SmartThings (#141469)
* Deprecate media player sensors for SmartThings * Deprecate media player sensors
This commit is contained in:
parent
c8ab5bc796
commit
fe99c39e25
@ -7,7 +7,7 @@ from dataclasses import dataclass
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
from pysmartthings import Attribute, Capability, SmartThings, Status
|
from pysmartthings import Attribute, Capability, ComponentStatus, SmartThings, Status
|
||||||
|
|
||||||
from homeassistant.components.automation import automations_with_entity
|
from homeassistant.components.automation import automations_with_entity
|
||||||
from homeassistant.components.script import scripts_with_entity
|
from homeassistant.components.script import scripts_with_entity
|
||||||
@ -140,6 +140,7 @@ class SmartThingsSensorEntityDescription(SensorEntityDescription):
|
|||||||
options_attribute: Attribute | None = None
|
options_attribute: Attribute | None = None
|
||||||
exists_fn: Callable[[Status], bool] | None = None
|
exists_fn: Callable[[Status], bool] | None = None
|
||||||
use_temperature_unit: bool = False
|
use_temperature_unit: bool = False
|
||||||
|
deprecated: Callable[[ComponentStatus], str | None] | None = None
|
||||||
|
|
||||||
|
|
||||||
CAPABILITY_TO_SENSORS: dict[
|
CAPABILITY_TO_SENSORS: dict[
|
||||||
@ -196,6 +197,17 @@ CAPABILITY_TO_SENSORS: dict[
|
|||||||
key=Attribute.VOLUME,
|
key=Attribute.VOLUME,
|
||||||
translation_key="audio_volume",
|
translation_key="audio_volume",
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
deprecated=(
|
||||||
|
lambda status: "media_player"
|
||||||
|
if all(
|
||||||
|
capability in status
|
||||||
|
for capability in (
|
||||||
|
Capability.AUDIO_MUTE,
|
||||||
|
Capability.MEDIA_PLAYBACK,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else None
|
||||||
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -319,6 +331,7 @@ CAPABILITY_TO_SENSORS: dict[
|
|||||||
translation_key="dryer_machine_state",
|
translation_key="dryer_machine_state",
|
||||||
options=WASHER_OPTIONS,
|
options=WASHER_OPTIONS,
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
|
deprecated=lambda _: "machine_state",
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Attribute.DRYER_JOB_STATE: [
|
Attribute.DRYER_JOB_STATE: [
|
||||||
@ -470,6 +483,7 @@ CAPABILITY_TO_SENSORS: dict[
|
|||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
options_attribute=Attribute.SUPPORTED_INPUT_SOURCES,
|
options_attribute=Attribute.SUPPORTED_INPUT_SOURCES,
|
||||||
value_fn=lambda value: value.lower() if value else None,
|
value_fn=lambda value: value.lower() if value else None,
|
||||||
|
deprecated=lambda _: "media_player",
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -478,6 +492,7 @@ CAPABILITY_TO_SENSORS: dict[
|
|||||||
SmartThingsSensorEntityDescription(
|
SmartThingsSensorEntityDescription(
|
||||||
key=Attribute.PLAYBACK_REPEAT_MODE,
|
key=Attribute.PLAYBACK_REPEAT_MODE,
|
||||||
translation_key="media_playback_repeat",
|
translation_key="media_playback_repeat",
|
||||||
|
deprecated=lambda _: "media_player",
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -486,6 +501,7 @@ CAPABILITY_TO_SENSORS: dict[
|
|||||||
SmartThingsSensorEntityDescription(
|
SmartThingsSensorEntityDescription(
|
||||||
key=Attribute.PLAYBACK_SHUFFLE,
|
key=Attribute.PLAYBACK_SHUFFLE,
|
||||||
translation_key="media_playback_shuffle",
|
translation_key="media_playback_shuffle",
|
||||||
|
deprecated=lambda _: "media_player",
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -504,6 +520,7 @@ CAPABILITY_TO_SENSORS: dict[
|
|||||||
],
|
],
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
value_fn=lambda value: MEDIA_PLAYBACK_STATE_MAP.get(value, value),
|
value_fn=lambda value: MEDIA_PLAYBACK_STATE_MAP.get(value, value),
|
||||||
|
deprecated=lambda _: "media_player",
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -949,6 +966,7 @@ CAPABILITY_TO_SENSORS: dict[
|
|||||||
translation_key="washer_machine_state",
|
translation_key="washer_machine_state",
|
||||||
options=WASHER_OPTIONS,
|
options=WASHER_OPTIONS,
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
|
deprecated=lambda _: "machine_state",
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Attribute.WASHER_JOB_STATE: [
|
Attribute.WASHER_JOB_STATE: [
|
||||||
@ -1102,13 +1120,9 @@ class SmartThingsSensor(SmartThingsEntity, SensorEntity):
|
|||||||
"""Call when entity is added to hass."""
|
"""Call when entity is added to hass."""
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
if (
|
if (
|
||||||
self.capability
|
not self.entity_description.deprecated
|
||||||
not in {
|
or (reason := self.entity_description.deprecated(self.device.status[MAIN]))
|
||||||
Capability.DISHWASHER_OPERATING_STATE,
|
is None
|
||||||
Capability.DRYER_OPERATING_STATE,
|
|
||||||
Capability.WASHER_OPERATING_STATE,
|
|
||||||
}
|
|
||||||
or self._attribute is not Attribute.MACHINE_STATE
|
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
automations = automations_with_entity(self.hass, self.entity_id)
|
automations = automations_with_entity(self.hass, self.entity_id)
|
||||||
@ -1130,11 +1144,11 @@ class SmartThingsSensor(SmartThingsEntity, SensorEntity):
|
|||||||
async_create_issue(
|
async_create_issue(
|
||||||
self.hass,
|
self.hass,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
f"deprecated_machine_state_{self.entity_id}",
|
f"deprecated_{reason}_{self.entity_id}",
|
||||||
breaks_in_ha_version="2025.10.0",
|
breaks_in_ha_version="2025.10.0",
|
||||||
is_fixable=False,
|
is_fixable=False,
|
||||||
severity=IssueSeverity.WARNING,
|
severity=IssueSeverity.WARNING,
|
||||||
translation_key="deprecated_machine_state",
|
translation_key=f"deprecated_{reason}",
|
||||||
translation_placeholders={
|
translation_placeholders={
|
||||||
"entity": self.entity_id,
|
"entity": self.entity_id,
|
||||||
"items": "\n".join(items_list),
|
"items": "\n".join(items_list),
|
||||||
@ -1145,15 +1159,9 @@ class SmartThingsSensor(SmartThingsEntity, SensorEntity):
|
|||||||
"""Call when entity will be removed from hass."""
|
"""Call when entity will be removed from hass."""
|
||||||
await super().async_will_remove_from_hass()
|
await super().async_will_remove_from_hass()
|
||||||
if (
|
if (
|
||||||
self.capability
|
not self.entity_description.deprecated
|
||||||
not in {
|
or (reason := self.entity_description.deprecated(self.device.status[MAIN]))
|
||||||
Capability.DISHWASHER_OPERATING_STATE,
|
is None
|
||||||
Capability.DRYER_OPERATING_STATE,
|
|
||||||
Capability.WASHER_OPERATING_STATE,
|
|
||||||
}
|
|
||||||
or self._attribute is not Attribute.MACHINE_STATE
|
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
async_delete_issue(
|
async_delete_issue(self.hass, DOMAIN, f"deprecated_{reason}_{self.entity_id}")
|
||||||
self.hass, DOMAIN, f"deprecated_machine_state_{self.entity_id}"
|
|
||||||
)
|
|
||||||
|
@ -494,6 +494,10 @@
|
|||||||
"deprecated_switch_appliance": {
|
"deprecated_switch_appliance": {
|
||||||
"title": "Deprecated switch detected in some automations or scripts",
|
"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 them in the above automations or scripts to fix this issue."
|
"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 them in the above automations or scripts to fix this issue."
|
||||||
|
},
|
||||||
|
"deprecated_media_player": {
|
||||||
|
"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 media player entity in the above automations or scripts to fix this issue."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,10 +58,23 @@ async def test_state_update(
|
|||||||
|
|
||||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("device_fixture", "entity_id"),
|
("device_fixture", "entity_id", "translation_key"),
|
||||||
[
|
[
|
||||||
("da_wm_wm_000001", "sensor.washer_machine_state"),
|
("da_wm_wm_000001", "sensor.washer_machine_state", "machine_state"),
|
||||||
("da_wm_wd_000001", "sensor.dryer_machine_state"),
|
("da_wm_wd_000001", "sensor.dryer_machine_state", "machine_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",
|
||||||
|
"media_player",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"im_speaker_ai_0001",
|
||||||
|
"sensor.galaxy_home_mini_media_playback_repeat",
|
||||||
|
"media_player",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_create_issue(
|
async def test_create_issue(
|
||||||
@ -70,9 +83,10 @@ async def test_create_issue(
|
|||||||
mock_config_entry: MockConfigEntry,
|
mock_config_entry: MockConfigEntry,
|
||||||
issue_registry: ir.IssueRegistry,
|
issue_registry: ir.IssueRegistry,
|
||||||
entity_id: str,
|
entity_id: str,
|
||||||
|
translation_key: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test we create an issue when an automation or script is using a deprecated entity."""
|
"""Test we create an issue when an automation or script is using a deprecated entity."""
|
||||||
issue_id = f"deprecated_machine_state_{entity_id}"
|
issue_id = f"deprecated_{translation_key}_{entity_id}"
|
||||||
|
|
||||||
assert await async_setup_component(
|
assert await async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
@ -117,7 +131,7 @@ async def test_create_issue(
|
|||||||
assert len(issue_registry.issues) == 1
|
assert len(issue_registry.issues) == 1
|
||||||
issue = issue_registry.async_get_issue(DOMAIN, issue_id)
|
issue = issue_registry.async_get_issue(DOMAIN, issue_id)
|
||||||
assert issue is not None
|
assert issue is not None
|
||||||
assert issue.translation_key == "deprecated_machine_state"
|
assert issue.translation_key == f"deprecated_{translation_key}"
|
||||||
assert issue.translation_placeholders == {
|
assert issue.translation_placeholders == {
|
||||||
"entity": entity_id,
|
"entity": entity_id,
|
||||||
"items": "- [test](/config/automation/edit/test)\n- [test](/config/script/edit/test)",
|
"items": "- [test](/config/automation/edit/test)\n- [test](/config/script/edit/test)",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user