mirror of
https://github.com/home-assistant/core.git
synced 2025-07-10 06:47:09 +00:00
Start deprecation of battery properties in vacuum (#146401)
* Start deprecation of battery properties in vacuum * Small fixes * Fixes * Deprecate battery supported feature
This commit is contained in:
parent
2afe475234
commit
9719d2ef2b
@ -247,6 +247,9 @@ class StateVacuumEntity(
|
||||
_attr_supported_features: VacuumEntityFeature = VacuumEntityFeature(0)
|
||||
|
||||
__vacuum_legacy_state: bool = False
|
||||
__vacuum_legacy_battery_level: bool = False
|
||||
__vacuum_legacy_battery_icon: bool = False
|
||||
__vacuum_legacy_battery_feature: bool = False
|
||||
|
||||
def __init_subclass__(cls, **kwargs: Any) -> None:
|
||||
"""Post initialisation processing."""
|
||||
@ -255,15 +258,28 @@ class StateVacuumEntity(
|
||||
# Integrations should use the 'activity' property instead of
|
||||
# setting the state directly.
|
||||
cls.__vacuum_legacy_state = True
|
||||
if any(
|
||||
method in cls.__dict__
|
||||
for method in ("_attr_battery_level", "battery_level")
|
||||
):
|
||||
# Integrations should use a separate battery sensor.
|
||||
cls.__vacuum_legacy_battery_level = True
|
||||
if any(
|
||||
method in cls.__dict__ for method in ("_attr_battery_icon", "battery_icon")
|
||||
):
|
||||
# Integrations should use a separate battery sensor.
|
||||
cls.__vacuum_legacy_battery_icon = True
|
||||
|
||||
def __setattr__(self, name: str, value: Any) -> None:
|
||||
"""Set attribute.
|
||||
|
||||
Deprecation warning if setting '_attr_state' directly
|
||||
unless already reported.
|
||||
Deprecation warning if setting state, battery icon or battery level
|
||||
attributes directly unless already reported.
|
||||
"""
|
||||
if name == "_attr_state":
|
||||
self._report_deprecated_activity_handling()
|
||||
if name in {"_attr_battery_level", "_attr_battery_icon"}:
|
||||
self._report_deprecated_battery_properties(name[6:])
|
||||
return super().__setattr__(name, value)
|
||||
|
||||
@callback
|
||||
@ -277,6 +293,10 @@ class StateVacuumEntity(
|
||||
super().add_to_platform_start(hass, platform, parallel_updates)
|
||||
if self.__vacuum_legacy_state:
|
||||
self._report_deprecated_activity_handling()
|
||||
if self.__vacuum_legacy_battery_level:
|
||||
self._report_deprecated_battery_properties("battery_level")
|
||||
if self.__vacuum_legacy_battery_icon:
|
||||
self._report_deprecated_battery_properties("battery_icon")
|
||||
|
||||
@callback
|
||||
def _report_deprecated_activity_handling(self) -> None:
|
||||
@ -295,6 +315,42 @@ class StateVacuumEntity(
|
||||
exclude_integrations={DOMAIN},
|
||||
)
|
||||
|
||||
@callback
|
||||
def _report_deprecated_battery_properties(self, property: str) -> None:
|
||||
"""Report on deprecated use of battery properties.
|
||||
|
||||
Integrations should implement a sensor instead.
|
||||
"""
|
||||
report_usage(
|
||||
f"is setting the {property} which has been deprecated."
|
||||
f" Integration {self.platform.platform_name} should implement a sensor"
|
||||
" instead with a correct device class and link it to the same device",
|
||||
core_integration_behavior=ReportBehavior.LOG,
|
||||
custom_integration_behavior=ReportBehavior.LOG,
|
||||
breaks_in_ha_version="2026.7",
|
||||
integration_domain=self.platform.platform_name if self.platform else None,
|
||||
exclude_integrations={DOMAIN},
|
||||
)
|
||||
|
||||
@callback
|
||||
def _report_deprecated_battery_feature(self) -> None:
|
||||
"""Report on deprecated use of battery supported features.
|
||||
|
||||
Integrations should remove the battery supported feature when migrating
|
||||
battery level and icon to a sensor.
|
||||
"""
|
||||
report_usage(
|
||||
f"is setting the battery supported feature which has been deprecated."
|
||||
f" Integration {self.platform.platform_name} should remove this as part of migrating"
|
||||
" the battery level and icon to a sensor",
|
||||
core_behavior=ReportBehavior.LOG,
|
||||
core_integration_behavior=ReportBehavior.LOG,
|
||||
custom_integration_behavior=ReportBehavior.LOG,
|
||||
breaks_in_ha_version="2026.7",
|
||||
integration_domain=self.platform.platform_name if self.platform else None,
|
||||
exclude_integrations={DOMAIN},
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def battery_level(self) -> int | None:
|
||||
"""Return the battery level of the vacuum cleaner."""
|
||||
@ -333,6 +389,9 @@ class StateVacuumEntity(
|
||||
supported_features = self.supported_features
|
||||
|
||||
if VacuumEntityFeature.BATTERY in supported_features:
|
||||
if self.__vacuum_legacy_battery_feature is False:
|
||||
self._report_deprecated_battery_feature()
|
||||
self.__vacuum_legacy_battery_feature = True
|
||||
data[ATTR_BATTERY_LEVEL] = self.battery_level
|
||||
data[ATTR_BATTERY_ICON] = self.battery_icon
|
||||
|
||||
|
@ -435,3 +435,181 @@ async def test_vacuum_deprecated_state_does_not_break_state(
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
assert state.state == "cleaning"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_as_custom_component")
|
||||
async def test_vacuum_log_deprecated_battery_properties(
|
||||
hass: HomeAssistant,
|
||||
config_flow_fixture: None,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test incorrectly using battery properties logs warning."""
|
||||
|
||||
class MockLegacyVacuum(MockVacuum):
|
||||
"""Mocked vacuum entity."""
|
||||
|
||||
@property
|
||||
def activity(self) -> str:
|
||||
"""Return the state of the entity."""
|
||||
return VacuumActivity.CLEANING
|
||||
|
||||
@property
|
||||
def battery_level(self) -> int:
|
||||
"""Return the battery level of the vacuum."""
|
||||
return 50
|
||||
|
||||
@property
|
||||
def battery_icon(self) -> str:
|
||||
"""Return the battery icon of the vacuum."""
|
||||
return "mdi:battery-50"
|
||||
|
||||
entity = MockLegacyVacuum(
|
||||
name="Testing",
|
||||
entity_id="vacuum.test",
|
||||
)
|
||||
config_entry = MockConfigEntry(domain="test")
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test",
|
||||
async_setup_entry=help_async_setup_entry_init,
|
||||
async_unload_entry=help_async_unload_entry,
|
||||
),
|
||||
built_in=False,
|
||||
)
|
||||
setup_test_component_platform(hass, DOMAIN, [entity], from_config_entry=True)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
|
||||
assert (
|
||||
"Detected that custom integration 'test' is setting the battery_icon which has been deprecated."
|
||||
" Integration test should implement a sensor instead with a correct device class and link it"
|
||||
" to the same device. This will stop working in Home Assistant 2026.7,"
|
||||
" please report it to the author of the 'test' custom integration"
|
||||
in caplog.text
|
||||
)
|
||||
assert (
|
||||
"Detected that custom integration 'test' is setting the battery_level which has been deprecated."
|
||||
" Integration test should implement a sensor instead with a correct device class and link it"
|
||||
" to the same device. This will stop working in Home Assistant 2026.7,"
|
||||
" please report it to the author of the 'test' custom integration"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_as_custom_component")
|
||||
async def test_vacuum_log_deprecated_battery_properties_using_attr(
|
||||
hass: HomeAssistant,
|
||||
config_flow_fixture: None,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test incorrectly using _attr_battery_* attribute does log issue and raise repair."""
|
||||
|
||||
class MockLegacyVacuum(MockVacuum):
|
||||
"""Mocked vacuum entity."""
|
||||
|
||||
def start(self) -> None:
|
||||
"""Start cleaning."""
|
||||
self._attr_battery_level = 50
|
||||
self._attr_battery_icon = "mdi:battery-50"
|
||||
|
||||
entity = MockLegacyVacuum(
|
||||
name="Testing",
|
||||
entity_id="vacuum.test",
|
||||
)
|
||||
config_entry = MockConfigEntry(domain="test")
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test",
|
||||
async_setup_entry=help_async_setup_entry_init,
|
||||
async_unload_entry=help_async_unload_entry,
|
||||
),
|
||||
built_in=False,
|
||||
)
|
||||
setup_test_component_platform(hass, DOMAIN, [entity], from_config_entry=True)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
entity.start()
|
||||
|
||||
assert (
|
||||
"Detected that custom integration 'test' is setting the battery_level which has been deprecated."
|
||||
" Integration test should implement a sensor instead with a correct device class and link it to"
|
||||
" the same device. This will stop working in Home Assistant 2026.7,"
|
||||
" please report it to the author of the 'test' custom integration"
|
||||
in caplog.text
|
||||
)
|
||||
assert (
|
||||
"Detected that custom integration 'test' is setting the battery_icon which has been deprecated."
|
||||
" Integration test should implement a sensor instead with a correct device class and link it to"
|
||||
" the same device. This will stop working in Home Assistant 2026.7,"
|
||||
" please report it to the author of the 'test' custom integration"
|
||||
in caplog.text
|
||||
)
|
||||
|
||||
await async_start(hass, entity.entity_id)
|
||||
|
||||
caplog.clear()
|
||||
await async_start(hass, entity.entity_id)
|
||||
# Test we only log once
|
||||
assert (
|
||||
"Detected that custom integration 'test' is setting the battery_level which has been deprecated."
|
||||
" Integration test should implement a sensor instead with a correct device class and link it to"
|
||||
" the same device. This will stop working in Home Assistant 2026.7,"
|
||||
" please report it to the author of the 'test' custom integration"
|
||||
not in caplog.text
|
||||
)
|
||||
assert (
|
||||
"Detected that custom integration 'test' is setting the battery_icon which has been deprecated."
|
||||
" Integration test should implement a sensor instead with a correct device class and link it to"
|
||||
" the same device. This will stop working in Home Assistant 2026.7,"
|
||||
" please report it to the author of the 'test' custom integration"
|
||||
not in caplog.text
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("mock_as_custom_component")
|
||||
async def test_vacuum_log_deprecated_battery_supported_feature(
|
||||
hass: HomeAssistant,
|
||||
config_flow_fixture: None,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Test incorrectly setting battery supported feature logs warning."""
|
||||
|
||||
entity = MockVacuum(
|
||||
name="Testing",
|
||||
entity_id="vacuum.test",
|
||||
)
|
||||
config_entry = MockConfigEntry(domain="test")
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
"test",
|
||||
async_setup_entry=help_async_setup_entry_init,
|
||||
async_unload_entry=help_async_unload_entry,
|
||||
),
|
||||
built_in=False,
|
||||
)
|
||||
setup_test_component_platform(hass, DOMAIN, [entity], from_config_entry=True)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
|
||||
state = hass.states.get(entity.entity_id)
|
||||
assert state is not None
|
||||
|
||||
assert (
|
||||
"Detected that custom integration 'test' is setting the battery supported feature"
|
||||
" which has been deprecated. Integration test should remove this as part of migrating"
|
||||
" the battery level and icon to a sensor. This will stop working in Home Assistant 2026.7"
|
||||
", please report it to the author of the 'test' custom integration"
|
||||
in caplog.text
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user