1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-08 17:49:37 +01:00

Add vacuum area mapping not configured issue (#163965)

This commit is contained in:
Artur Pragacz
2026-02-25 10:45:44 +01:00
committed by GitHub
parent dc133bf7cc
commit 50f39621e9
3 changed files with 176 additions and 2 deletions
@@ -63,6 +63,7 @@ SERVICE_STOP = "stop"
DEFAULT_NAME = "Vacuum cleaner robot"
ISSUE_SEGMENTS_CHANGED = "segments_changed"
ISSUE_SEGMENTS_MAPPING_NOT_CONFIGURED = "segments_mapping_not_configured"
_BATTERY_DEPRECATION_IGNORED_PLATFORMS = ("template",)
@@ -189,6 +190,9 @@ class StateVacuumEntity(
_attr_activity: VacuumActivity | None = None
_attr_supported_features: VacuumEntityFeature = VacuumEntityFeature(0)
_segments_not_configured_issue_created: bool = False
_segments_changed_last_seen: list[dict[str, Any]] | None = None
__vacuum_legacy_battery_level: bool = False
__vacuum_legacy_battery_icon: bool = False
__vacuum_legacy_battery_feature: bool = False
@@ -232,6 +236,17 @@ class StateVacuumEntity(
if self.__vacuum_legacy_battery_icon:
self._report_deprecated_battery_properties("battery_icon")
@callback
def async_write_ha_state(self) -> None:
"""Write the state to the state machine."""
super().async_write_ha_state()
self._async_check_segments_issues()
@callback
def async_registry_entry_updated(self) -> None:
"""Run when the entity registry entry has been updated."""
self._async_check_segments_issues()
@callback
def _report_deprecated_battery_properties(self, property: str) -> None:
"""Report on deprecated use of battery properties.
@@ -489,6 +504,61 @@ class StateVacuumEntity(
"entity_id": self.entity_id,
},
)
options: Mapping[str, Any] = self.registry_entry.options.get(DOMAIN, {})
self._segments_changed_last_seen = options.get("last_seen_segments")
@callback
def _async_check_segments_issues(self) -> None:
"""Create or delete segment-related repair issues."""
if self.registry_entry is None:
return
options: Mapping[str, Any] = self.registry_entry.options.get(DOMAIN, {})
should_have_not_configured_issue = (
VacuumEntityFeature.CLEAN_AREA in self.supported_features
and options.get("area_mapping") is None
)
if (
should_have_not_configured_issue
and not self._segments_not_configured_issue_created
):
issue_id = (
f"{ISSUE_SEGMENTS_MAPPING_NOT_CONFIGURED}_{self.registry_entry.id}"
)
ir.async_create_issue(
self.hass,
DOMAIN,
issue_id,
data={
"entry_id": self.registry_entry.id,
"entity_id": self.entity_id,
},
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
translation_key=ISSUE_SEGMENTS_MAPPING_NOT_CONFIGURED,
translation_placeholders={
"entity_id": self.entity_id,
},
)
self._segments_not_configured_issue_created = True
elif (
not should_have_not_configured_issue
and self._segments_not_configured_issue_created
):
issue_id = (
f"{ISSUE_SEGMENTS_MAPPING_NOT_CONFIGURED}_{self.registry_entry.id}"
)
ir.async_delete_issue(self.hass, DOMAIN, issue_id)
self._segments_not_configured_issue_created = False
if self._segments_changed_last_seen is not None and (
VacuumEntityFeature.CLEAN_AREA not in self.supported_features
or options.get("last_seen_segments") != self._segments_changed_last_seen
):
issue_id = f"{ISSUE_SEGMENTS_CHANGED}_{self.registry_entry.id}"
ir.async_delete_issue(self.hass, DOMAIN, issue_id)
self._segments_changed_last_seen = None
def locate(self, **kwargs: Any) -> None:
"""Locate the vacuum cleaner."""
@@ -93,6 +93,10 @@
"segments_changed": {
"description": "",
"title": "Vacuum segments have changed for {entity_id}"
},
"segments_mapping_not_configured": {
"description": "",
"title": "Vacuum segment mapping not configured for {entity_id}"
}
},
"selector": {
+102 -2
View File
@@ -430,10 +430,10 @@ async def test_last_seen_segments(
@pytest.mark.usefixtures("config_flow_fixture")
async def test_last_seen_segments_and_issue_creation(
async def test_segments_changed_issue(
hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None:
"""Test last_seen_segments property and segments issue creation."""
"""Test segments changed issue."""
mock_vacuum = MockVacuumWithCleanArea(name="Testing", entity_id="vacuum.testing")
config_entry = MockConfigEntry(domain="test")
@@ -452,6 +452,17 @@ async def test_last_seen_segments_and_issue_creation(
await hass.async_block_till_done()
entity_entry = entity_registry.async_get(mock_vacuum.entity_id)
entity_registry.async_update_entity_options(
mock_vacuum.entity_id,
DOMAIN,
{
"area_mapping": {"area_1": ["seg_1"]},
"last_seen_segments": [asdict(segment) for segment in mock_vacuum.segments],
},
)
await hass.async_block_till_done()
mock_vacuum.async_create_segments_issue()
issue_id = f"segments_changed_{entity_entry.id}"
@@ -460,6 +471,95 @@ async def test_last_seen_segments_and_issue_creation(
assert issue.severity == ir.IssueSeverity.WARNING
assert issue.translation_key == "segments_changed"
entity_registry.async_update_entity_options(
mock_vacuum.entity_id,
DOMAIN,
{
"area_mapping": {"area_1": ["seg_1"], "area_2": ["seg_new"]},
"last_seen_segments": [
{"id": "seg_1", "name": "Kitchen"},
{"id": "seg_new", "name": "New Room"},
],
},
)
await hass.async_block_till_done()
assert ir.async_get(hass).async_get_issue(DOMAIN, issue_id) is None
@pytest.mark.usefixtures("config_flow_fixture")
@pytest.mark.parametrize("area_mapping", [{"area_1": ["seg_1"]}, {}])
async def test_segments_mapping_not_configured_issue(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
area_mapping: dict[str, list[str]],
) -> None:
"""Test segments_mapping_not_configured issue."""
mock_vacuum = MockVacuumWithCleanArea(name="Testing", entity_id="vacuum.testing")
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,
),
)
setup_test_component_platform(hass, DOMAIN, [mock_vacuum], from_config_entry=True)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entity_entry = entity_registry.async_get(mock_vacuum.entity_id)
issue_id = f"segments_mapping_not_configured_{entity_entry.id}"
issue = ir.async_get(hass).async_get_issue(DOMAIN, issue_id)
assert issue is not None
assert issue.severity == ir.IssueSeverity.WARNING
assert issue.translation_key == "segments_mapping_not_configured"
entity_registry.async_update_entity_options(
mock_vacuum.entity_id,
DOMAIN,
{
"area_mapping": area_mapping,
"last_seen_segments": [asdict(segment) for segment in mock_vacuum.segments],
},
)
await hass.async_block_till_done()
assert ir.async_get(hass).async_get_issue(DOMAIN, issue_id) is None
@pytest.mark.usefixtures("config_flow_fixture")
async def test_no_segments_mapping_issue_without_clean_area(
hass: HomeAssistant,
) -> None:
"""Test no repair issue is created when CLEAN_AREA is not supported."""
mock_vacuum = MockVacuum(name="Testing", entity_id="vacuum.testing")
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,
),
)
setup_test_component_platform(hass, DOMAIN, [mock_vacuum], from_config_entry=True)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
issues = ir.async_get(hass).issues
assert not any(
issue_id[1].startswith("segments_mapping_not_configured") for issue_id in issues
)
@pytest.mark.parametrize(("is_built_in", "log_warnings"), [(True, 0), (False, 3)])
async def test_vacuum_log_deprecated_battery_using_properties(