1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-17 07:34:07 +01:00
Files
core/tests/components/ecovacs/test_vacuum.py

492 lines
14 KiB
Python

"""Tests for Ecovacs vacuum entities."""
from dataclasses import asdict
import logging
from deebot_client.events import CachedMapInfoEvent, Event, RoomsEvent
from deebot_client.events.map import Map
from deebot_client.models import CleanMode, Room
from deebot_client.rs.map import RotationAngle # pylint: disable=no-name-in-module
import pytest
from homeassistant.components import vacuum
from homeassistant.components.ecovacs.controller import EcovacsController
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er, issue_registry as ir
from .util import notify_and_wait
from tests.typing import WebSocketGenerator
pytestmark = [pytest.mark.usefixtures("init_integration")]
@pytest.fixture
def platforms() -> Platform | list[Platform]:
"""Platforms, which should be loaded during the test."""
return Platform.VACUUM
def _prepare_test(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
entity_id: str,
) -> None:
entity_registry.async_update_entity_options(
entity_id,
vacuum.DOMAIN,
{
"area_mapping": {
"area_kitchen": ["1_1"],
"area_living_room": ["1_2"],
"area_bedroom": ["2_1"],
},
"last_seen_segments": [
{"id": "1_1", "name": "Kitchen", "group": "Main map"},
{"id": "1_2", "name": "Living room", "group": "Main map"},
{"id": "2_1", "name": "Bedroom", "group": "Second map"},
],
},
)
vacuum_obj = hass.data[vacuum.DATA_COMPONENT].get_entity(entity_id)
assert vacuum_obj.last_seen_segments == [
vacuum.Segment(id="1_1", name="Kitchen", group="Main map"),
vacuum.Segment(id="1_2", name="Living room", group="Main map"),
vacuum.Segment(id="2_1", name="Bedroom", group="Second map"),
]
assert vacuum_obj.supported_features & vacuum.VacuumEntityFeature.CLEAN_AREA
@pytest.mark.parametrize(("device_fixture", "entity_id"), [("qhe2o2", "vacuum.dusty")])
async def test_clean_area(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
controller: EcovacsController,
entity_id: str,
) -> None:
"""Test clean_area service call."""
_prepare_test(hass, entity_registry, entity_id)
device = controller.devices[0]
event_bus = device.events
await notify_and_wait(
hass,
event_bus,
CachedMapInfoEvent(
{
Map(
id="1",
name="Main map",
using=True,
built=True,
angle=RotationAngle.DEG_0,
),
Map(
id="2",
name="Second map",
using=False,
built=True,
angle=RotationAngle.DEG_0,
),
}
),
)
device._execute_command.reset_mock()
await hass.services.async_call(
vacuum.DOMAIN,
vacuum.SERVICE_CLEAN_AREA,
{
ATTR_ENTITY_ID: entity_id,
"cleaning_area_id": ["area_living_room", "area_kitchen"],
},
blocking=True,
)
assert device._execute_command.call_count == 1
command = device._execute_command.call_args.args[0]
expected_command = device.capabilities.clean.action.area(
CleanMode.SPOT_AREA, [2, 1], 1
)
assert command == expected_command
@pytest.mark.parametrize(("device_fixture", "entity_id"), [("qhe2o2", "vacuum.dusty")])
async def test_clean_area_no_map(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
caplog: pytest.LogCaptureFixture,
controller: EcovacsController,
entity_id: str,
) -> None:
"""Test clean_area service call logs warning when no map info is available."""
_prepare_test(hass, entity_registry, entity_id)
device = controller.devices[0]
device._execute_command.reset_mock()
await hass.services.async_call(
vacuum.DOMAIN,
vacuum.SERVICE_CLEAN_AREA,
{
ATTR_ENTITY_ID: entity_id,
"cleaning_area_id": ["area_living_room", "area_kitchen"],
},
blocking=True,
)
assert caplog.record_tuples == [
(
"homeassistant.components.ecovacs.vacuum",
logging.WARNING,
"No map information available, cannot clean segments",
),
]
assert device._execute_command.call_count == 0
@pytest.mark.parametrize(("device_fixture", "entity_id"), [("qhe2o2", "vacuum.dusty")])
async def test_clean_area_invalid_map_id(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
caplog: pytest.LogCaptureFixture,
controller: EcovacsController,
entity_id: str,
) -> None:
"""Test clean_area service call logs warning when invalid map ID is provided."""
_prepare_test(hass, entity_registry, entity_id)
device = controller.devices[0]
event_bus = device.events
await notify_and_wait(
hass,
event_bus,
CachedMapInfoEvent(
{
Map(
id="2",
name="Second map",
using=False,
built=True,
angle=RotationAngle.DEG_0,
),
}
),
)
device._execute_command.reset_mock()
caplog.clear()
await hass.services.async_call(
vacuum.DOMAIN,
vacuum.SERVICE_CLEAN_AREA,
{
ATTR_ENTITY_ID: entity_id,
"cleaning_area_id": ["area_living_room", "area_kitchen"],
},
blocking=True,
)
assert caplog.record_tuples == [
(
"homeassistant.components.ecovacs.vacuum",
logging.WARNING,
"Map ID 1 not found in available maps",
),
# twice as both areas reference the same missing map ID
(
"homeassistant.components.ecovacs.vacuum",
logging.WARNING,
"Map ID 1 not found in available maps",
),
(
"homeassistant.components.ecovacs.vacuum",
logging.WARNING,
"No valid segments to clean after validation, skipping clean segments command",
),
]
assert device._execute_command.call_count == 0
@pytest.mark.parametrize(("device_fixture", "entity_id"), [("qhe2o2", "vacuum.dusty")])
async def test_clean_area_room_from_not_current_map(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
caplog: pytest.LogCaptureFixture,
controller: EcovacsController,
entity_id: str,
) -> None:
"""Test clean_area service call logs warning when room is from a not current map."""
_prepare_test(hass, entity_registry, entity_id)
device = controller.devices[0]
event_bus = device.events
await notify_and_wait(
hass,
event_bus,
CachedMapInfoEvent(
{
Map(
id="1",
name="Main map",
using=True,
built=True,
angle=RotationAngle.DEG_0,
),
Map(
id="2",
name="Second map",
using=False,
built=True,
angle=RotationAngle.DEG_0,
),
}
),
)
await notify_and_wait(
hass,
event_bus,
RoomsEvent(
map_id="1",
rooms=[
Room(name="Kitchen", id=1, coordinates=""),
Room(name="Living room", id=2, coordinates=""),
],
),
)
device._execute_command.reset_mock()
caplog.clear()
await hass.services.async_call(
vacuum.DOMAIN,
vacuum.SERVICE_CLEAN_AREA,
{
ATTR_ENTITY_ID: entity_id,
"cleaning_area_id": ["area_bedroom", "area_kitchen"],
},
blocking=True,
)
assert caplog.record_tuples == [
(
"homeassistant.components.ecovacs.vacuum",
logging.WARNING,
'Map "Second map" is not currently selected, skipping segment "Bedroom" (1)',
),
]
assert device._execute_command.call_count == 1
command = device._execute_command.call_args.args[0]
expected_command = device.capabilities.clean.action.area(
CleanMode.SPOT_AREA, [1], 1
)
assert command == expected_command
@pytest.mark.parametrize(
"events",
[
(
CachedMapInfoEvent(
{
Map(
id="1",
name="Main map",
using=True,
built=True,
angle=RotationAngle.DEG_0,
),
Map(
id="2",
name="Second map",
using=False,
built=True,
angle=RotationAngle.DEG_0,
),
}
),
RoomsEvent(
map_id="1",
rooms=[
Room(name="Kitchen", id=1, coordinates=""),
],
),
),
(
CachedMapInfoEvent(
{
Map(
id="1",
name="Main map",
using=True,
built=True,
angle=RotationAngle.DEG_0,
),
}
),
RoomsEvent(
map_id="1",
rooms=[
Room(name="Kitchen", id=1, coordinates=""),
Room(name="Living room", id=2, coordinates=""),
],
),
),
(
CachedMapInfoEvent(
{
Map(
id="1",
name="Main map",
using=True,
built=True,
angle=RotationAngle.DEG_0,
),
Map(
id="2",
name="Second map",
using=False,
built=True,
angle=RotationAngle.DEG_0,
),
}
),
RoomsEvent(
map_id="1",
rooms=[
Room(name="Kitchen", id=1, coordinates=""),
Room(name="Living room", id=2, coordinates=""),
Room(name="Bedroom", id=3, coordinates=""),
],
),
),
],
ids=[
"room removed",
"map removed",
"room added",
],
)
@pytest.mark.parametrize(("device_fixture", "entity_id"), [("qhe2o2", "vacuum.dusty")])
async def test_raise_segment_changed_issue(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
controller: EcovacsController,
entity_id: str,
events: tuple[Event, ...],
) -> None:
"""Test that the issue is raised on segment changes."""
_prepare_test(hass, entity_registry, entity_id)
device = controller.devices[0]
event_bus = device.events
for event in events:
await notify_and_wait(hass, event_bus, event)
entity_entry = entity_registry.async_get(entity_id)
issue_id = f"{vacuum.ISSUE_SEGMENTS_CHANGED}_{entity_entry.id}"
issue = ir.async_get(hass).async_get_issue(vacuum.DOMAIN, issue_id)
assert issue is not None
@pytest.mark.parametrize(
("events", "expected_segments", "expected_log_messages"),
[
((), [], []),
(
(
CachedMapInfoEvent(
{
Map(
id="1",
name="Main map",
using=True,
built=True,
angle=RotationAngle.DEG_0,
),
}
),
RoomsEvent(
map_id="2",
rooms=[
Room(name="Kitchen", id=1, coordinates=""),
Room(name="Living room", id=2, coordinates=""),
],
),
),
[],
[
(
"homeassistant.components.ecovacs.vacuum",
logging.WARNING,
"Map ID 2 not found in available maps",
)
],
),
(
(
CachedMapInfoEvent(
{
Map(
id="1",
name="Main map",
using=True,
built=True,
angle=RotationAngle.DEG_0,
),
}
),
RoomsEvent(
map_id="1",
rooms=[
Room(name="Kitchen", id=1, coordinates=""),
Room(name="Living room", id=2, coordinates=""),
],
),
),
[
vacuum.Segment(id="1_1", name="Kitchen", group="Main map"),
vacuum.Segment(id="1_2", name="Living room", group="Main map"),
],
[],
),
],
ids=[
"no room event available",
"invalid map ID in room event",
"room added",
],
)
@pytest.mark.parametrize(("device_fixture", "entity_id"), [("qhe2o2", "vacuum.dusty")])
async def test_get_segments(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
caplog: pytest.LogCaptureFixture,
controller: EcovacsController,
entity_id: str,
events: tuple[Event, ...],
expected_segments: list[vacuum.Segment],
expected_log_messages: list[tuple[str, int, str]],
) -> None:
"""Test vacuum/get_segments websocket command."""
device = controller.devices[0]
event_bus = device.events
for event in events:
await notify_and_wait(hass, event_bus, event)
caplog.clear()
client = await hass_ws_client(hass)
await client.send_json_auto_id(
{"type": "vacuum/get_segments", "entity_id": entity_id}
)
msg = await client.receive_json()
assert msg["success"]
assert msg["result"] == {"segments": [asdict(seg) for seg in expected_segments]}
for log_message in expected_log_messages:
assert log_message in caplog.record_tuples