mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Ecovacs get_positions service (#118572)
Co-authored-by: Robert Resch <robert@resch.dev>
This commit is contained in:
parent
9a6902d827
commit
78c7af40ed
@ -140,5 +140,8 @@
|
|||||||
"default": "mdi:laser-pointer"
|
"default": "mdi:laser-pointer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"services": {
|
||||||
|
"raw_get_positions": "mdi:map-marker-radius-outline"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
homeassistant/components/ecovacs/services.yaml
Normal file
4
homeassistant/components/ecovacs/services.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
raw_get_positions:
|
||||||
|
target:
|
||||||
|
entity:
|
||||||
|
domain: vacuum
|
@ -226,6 +226,9 @@
|
|||||||
},
|
},
|
||||||
"vacuum_send_command_params_required": {
|
"vacuum_send_command_params_required": {
|
||||||
"message": "Params are required for the command: {command}"
|
"message": "Params are required for the command: {command}"
|
||||||
|
},
|
||||||
|
"vacuum_raw_get_positions_not_supported": {
|
||||||
|
"message": "Getting the positions of the charges and the device itself is not supported"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"issues": {
|
"issues": {
|
||||||
@ -261,5 +264,11 @@
|
|||||||
"self_hosted": "Self-hosted"
|
"self_hosted": "Self-hosted"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"services": {
|
||||||
|
"raw_get_positions": {
|
||||||
|
"name": "Get raw positions",
|
||||||
|
"description": "Get the raw response for the positions of the chargers and the device itself."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,9 @@ from homeassistant.components.vacuum import (
|
|||||||
StateVacuumEntityDescription,
|
StateVacuumEntityDescription,
|
||||||
VacuumEntityFeature,
|
VacuumEntityFeature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant, SupportsResponse
|
||||||
from homeassistant.exceptions import ServiceValidationError
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
|
from homeassistant.helpers import entity_platform
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.icon import icon_for_battery_level
|
from homeassistant.helpers.icon import icon_for_battery_level
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
@ -39,6 +40,8 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
ATTR_ERROR = "error"
|
ATTR_ERROR = "error"
|
||||||
ATTR_COMPONENT_PREFIX = "component_"
|
ATTR_COMPONENT_PREFIX = "component_"
|
||||||
|
|
||||||
|
SERVICE_RAW_GET_POSITIONS = "raw_get_positions"
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -46,6 +49,7 @@ async def async_setup_entry(
|
|||||||
async_add_entities: AddEntitiesCallback,
|
async_add_entities: AddEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up the Ecovacs vacuums."""
|
"""Set up the Ecovacs vacuums."""
|
||||||
|
|
||||||
controller = config_entry.runtime_data
|
controller = config_entry.runtime_data
|
||||||
vacuums: list[EcovacsVacuum | EcovacsLegacyVacuum] = [
|
vacuums: list[EcovacsVacuum | EcovacsLegacyVacuum] = [
|
||||||
EcovacsVacuum(device) for device in controller.devices(VacuumCapabilities)
|
EcovacsVacuum(device) for device in controller.devices(VacuumCapabilities)
|
||||||
@ -56,6 +60,14 @@ async def async_setup_entry(
|
|||||||
_LOGGER.debug("Adding Ecovacs Vacuums to Home Assistant: %s", vacuums)
|
_LOGGER.debug("Adding Ecovacs Vacuums to Home Assistant: %s", vacuums)
|
||||||
async_add_entities(vacuums)
|
async_add_entities(vacuums)
|
||||||
|
|
||||||
|
platform = entity_platform.async_get_current_platform()
|
||||||
|
platform.async_register_entity_service(
|
||||||
|
SERVICE_RAW_GET_POSITIONS,
|
||||||
|
{},
|
||||||
|
"async_raw_get_positions",
|
||||||
|
supports_response=SupportsResponse.ONLY,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EcovacsLegacyVacuum(StateVacuumEntity):
|
class EcovacsLegacyVacuum(StateVacuumEntity):
|
||||||
"""Legacy Ecovacs vacuums."""
|
"""Legacy Ecovacs vacuums."""
|
||||||
@ -197,6 +209,15 @@ class EcovacsLegacyVacuum(StateVacuumEntity):
|
|||||||
"""Send a command to a vacuum cleaner."""
|
"""Send a command to a vacuum cleaner."""
|
||||||
self.device.run(sucks.VacBotCommand(command, params))
|
self.device.run(sucks.VacBotCommand(command, params))
|
||||||
|
|
||||||
|
async def async_raw_get_positions(
|
||||||
|
self,
|
||||||
|
) -> None:
|
||||||
|
"""Get bot and chargers positions."""
|
||||||
|
raise ServiceValidationError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="vacuum_raw_get_positions_not_supported",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
_STATE_TO_VACUUM_STATE = {
|
_STATE_TO_VACUUM_STATE = {
|
||||||
State.IDLE: STATE_IDLE,
|
State.IDLE: STATE_IDLE,
|
||||||
@ -377,3 +398,19 @@ class EcovacsVacuum(
|
|||||||
await self._device.execute_command(
|
await self._device.execute_command(
|
||||||
self._capability.custom.set(command, params)
|
self._capability.custom.set(command, params)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_raw_get_positions(
|
||||||
|
self,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Get bot and chargers positions."""
|
||||||
|
_LOGGER.debug("async_raw_get_positions")
|
||||||
|
|
||||||
|
if not (map_cap := self._capability.map) or not (
|
||||||
|
position_commands := map_cap.position.get
|
||||||
|
):
|
||||||
|
raise ServiceValidationError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="vacuum_raw_get_positions_not_supported",
|
||||||
|
)
|
||||||
|
|
||||||
|
return await self._device.execute_command(position_commands[0])
|
||||||
|
89
tests/components/ecovacs/test_services.py
Normal file
89
tests/components/ecovacs/test_services.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
"""Tests for Ecovacs services."""
|
||||||
|
|
||||||
|
from collections.abc import Generator
|
||||||
|
from typing import Any
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from deebot_client.device import Device
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.ecovacs.const import DOMAIN
|
||||||
|
from homeassistant.components.ecovacs.vacuum import SERVICE_RAW_GET_POSITIONS
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.usefixtures("init_integration")]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_device_execute_response(
|
||||||
|
data: dict[str, Any],
|
||||||
|
) -> Generator[dict[str, Any], None, None]:
|
||||||
|
"""Mock the device execute function response."""
|
||||||
|
|
||||||
|
response = {
|
||||||
|
"ret": "ok",
|
||||||
|
"resp": {
|
||||||
|
"header": {
|
||||||
|
"pri": 1,
|
||||||
|
"tzm": 480,
|
||||||
|
"ts": "1717113600000",
|
||||||
|
"ver": "0.0.1",
|
||||||
|
"fwVer": "1.2.0",
|
||||||
|
"hwVer": "0.1.0",
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"code": 0,
|
||||||
|
"msg": "ok",
|
||||||
|
"data": data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"id": "xRV3",
|
||||||
|
"payloadType": "j",
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch.object(
|
||||||
|
Device,
|
||||||
|
"execute_command",
|
||||||
|
return_value=response,
|
||||||
|
):
|
||||||
|
yield response
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("mock_device_execute_response")
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"data",
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"deebotPos": {"x": 1, "y": 5, "a": 85},
|
||||||
|
"chargePos": {"x": 5, "y": 9, "a": 85},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"deebotPos": {"x": 375, "y": 313, "a": 90},
|
||||||
|
"chargePos": [{"x": 112, "y": 768, "a": 32}, {"x": 489, "y": 322, "a": 0}],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("device_fixture", "entity_id"),
|
||||||
|
[
|
||||||
|
("yna5x1", "vacuum.ozmo_950"),
|
||||||
|
],
|
||||||
|
ids=["yna5x1"],
|
||||||
|
)
|
||||||
|
async def test_get_positions_service(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_device_execute_response: dict[str],
|
||||||
|
entity_id: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test that get_positions service response snapshots match."""
|
||||||
|
vacuum = hass.states.get(entity_id)
|
||||||
|
assert vacuum
|
||||||
|
|
||||||
|
assert await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_RAW_GET_POSITIONS,
|
||||||
|
{ATTR_ENTITY_ID: entity_id},
|
||||||
|
blocking=True,
|
||||||
|
return_response=True,
|
||||||
|
) == {entity_id: mock_device_execute_response}
|
Loading…
x
Reference in New Issue
Block a user