Start deprecation of battery properties in vacuum

This commit is contained in:
G Johansson
2025-06-09 17:10:49 +00:00
parent 8cead00bc7
commit 446c62d7cd
2 changed files with 155 additions and 0 deletions

View File

@@ -247,6 +247,8 @@ 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
def __init_subclass__(cls, **kwargs: Any) -> None:
"""Post initialisation processing."""
@@ -255,6 +257,19 @@ 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 the 'activity' property instead of
# setting the state directly.
cls.__vacuum_legacy_battery_level = True
if any(
method in cls.__dict__ for method in ("_attr_battery_icon", "battery_icon")
):
# Integrations should use the 'activity' property instead of
# setting the state directly.
cls.__vacuum_legacy_battery_icon = True
def __setattr__(self, name: str, value: Any) -> None:
"""Set attribute.
@@ -264,6 +279,8 @@ class StateVacuumEntity(
"""
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 +294,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 +316,23 @@ 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},
)
@cached_property
def battery_level(self) -> int | None:
"""Return the battery level of the vacuum cleaner."""

View File

@@ -435,3 +435,120 @@ 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 watning."""
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
)
@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
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
)
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
)