diff --git a/homeassistant/components/roborock/__init__.py b/homeassistant/components/roborock/__init__.py index 955e50cd15b..c382a56cde7 100644 --- a/homeassistant/components/roborock/__init__.py +++ b/homeassistant/components/roborock/__init__.py @@ -83,13 +83,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: RoborockConfigEntry) -> # Get a Coordinator if the device is available or if we have connected to the device before coordinators = await asyncio.gather( *build_setup_functions( - hass, - entry, - device_map, - user_data, - product_info, - home_data.rooms, - api_client, + hass, entry, device_map, user_data, product_info, home_data.rooms ), return_exceptions=True, ) @@ -141,7 +135,6 @@ def build_setup_functions( user_data: UserData, product_info: dict[str, HomeDataProduct], home_data_rooms: list[HomeDataRoom], - api_client: RoborockApiClient, ) -> list[ Coroutine[ Any, @@ -158,7 +151,6 @@ def build_setup_functions( device, product_info[device.product_id], home_data_rooms, - api_client, ) for device in device_map.values() ] @@ -171,12 +163,11 @@ async def setup_device( device: HomeDataDevice, product_info: HomeDataProduct, home_data_rooms: list[HomeDataRoom], - api_client: RoborockApiClient, ) -> RoborockDataUpdateCoordinator | RoborockDataUpdateCoordinatorA01 | None: """Set up a coordinator for a given device.""" if device.pv == "1.0": return await setup_device_v1( - hass, entry, user_data, device, product_info, home_data_rooms, api_client + hass, entry, user_data, device, product_info, home_data_rooms ) if device.pv == "A01": return await setup_device_a01(hass, entry, user_data, device, product_info) @@ -196,7 +187,6 @@ async def setup_device_v1( device: HomeDataDevice, product_info: HomeDataProduct, home_data_rooms: list[HomeDataRoom], - api_client: RoborockApiClient, ) -> RoborockDataUpdateCoordinator | None: """Set up a device Coordinator.""" mqtt_client = await hass.async_add_executor_job( @@ -218,15 +208,7 @@ async def setup_device_v1( await mqtt_client.async_release() raise coordinator = RoborockDataUpdateCoordinator( - hass, - entry, - device, - networking, - product_info, - mqtt_client, - home_data_rooms, - api_client, - user_data, + hass, entry, device, networking, product_info, mqtt_client, home_data_rooms ) try: await coordinator.async_config_entry_first_refresh() diff --git a/homeassistant/components/roborock/const.py b/homeassistant/components/roborock/const.py index fe9091a3ea7..cc8d34fbadc 100644 --- a/homeassistant/components/roborock/const.py +++ b/homeassistant/components/roborock/const.py @@ -36,7 +36,6 @@ PLATFORMS = [ Platform.BUTTON, Platform.IMAGE, Platform.NUMBER, - Platform.SCENE, Platform.SELECT, Platform.SENSOR, Platform.SWITCH, diff --git a/homeassistant/components/roborock/coordinator.py b/homeassistant/components/roborock/coordinator.py index 6690b0ac07e..806651c9ac5 100644 --- a/homeassistant/components/roborock/coordinator.py +++ b/homeassistant/components/roborock/coordinator.py @@ -10,26 +10,17 @@ import logging from propcache.api import cached_property from roborock import HomeDataRoom from roborock.code_mappings import RoborockCategory -from roborock.containers import ( - DeviceData, - HomeDataDevice, - HomeDataProduct, - HomeDataScene, - NetworkInfo, - UserData, -) +from roborock.containers import DeviceData, HomeDataDevice, HomeDataProduct, NetworkInfo from roborock.exceptions import RoborockException from roborock.roborock_message import RoborockDyadDataProtocol, RoborockZeoProtocol from roborock.roborock_typing import DeviceProp from roborock.version_1_apis.roborock_local_client_v1 import RoborockLocalClientV1 from roborock.version_1_apis.roborock_mqtt_client_v1 import RoborockMqttClientV1 from roborock.version_a01_apis import RoborockClientA01 -from roborock.web_api import RoborockApiClient from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_CONNECTIONS from homeassistant.core import HomeAssistant -from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import device_registry as dr from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.typing import StateType @@ -76,8 +67,6 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]): product_info: HomeDataProduct, cloud_api: RoborockMqttClientV1, home_data_rooms: list[HomeDataRoom], - api_client: RoborockApiClient, - user_data: UserData, ) -> None: """Initialize.""" super().__init__( @@ -100,7 +89,7 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]): self.cloud_api = cloud_api self.device_info = DeviceInfo( name=self.roborock_device_info.device.name, - identifiers={(DOMAIN, self.duid)}, + identifiers={(DOMAIN, self.roborock_device_info.device.duid)}, manufacturer="Roborock", model=self.roborock_device_info.product.model, model_id=self.roborock_device_info.product.model, @@ -114,10 +103,8 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]): self.maps: dict[int, RoborockMapInfo] = {} self._home_data_rooms = {str(room.id): room.name for room in home_data_rooms} self.map_storage = RoborockMapStorage( - hass, self.config_entry.entry_id, self.duid_slug + hass, self.config_entry.entry_id, slugify(self.duid) ) - self._user_data = user_data - self._api_client = api_client async def _async_setup(self) -> None: """Set up the coordinator.""" @@ -147,7 +134,7 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]): except RoborockException: _LOGGER.warning( "Using the cloud API for device %s. This is not recommended as it can lead to rate limiting. We recommend making your vacuum accessible by your Home Assistant instance", - self.duid, + self.roborock_device_info.device.duid, ) await self.api.async_disconnect() # We use the cloud api if the local api fails to connect. @@ -207,34 +194,6 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]): for room in room_mapping or () } - async def get_scenes(self) -> list[HomeDataScene]: - """Get scenes.""" - try: - return await self._api_client.get_scenes(self._user_data, self.duid) - except RoborockException as err: - _LOGGER.error("Failed to get scenes %s", err) - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="command_failed", - translation_placeholders={ - "command": "get_scenes", - }, - ) from err - - async def execute_scene(self, scene_id: int) -> None: - """Execute scene.""" - try: - await self._api_client.execute_scene(self._user_data, scene_id) - except RoborockException as err: - _LOGGER.error("Failed to execute scene %s %s", scene_id, err) - raise HomeAssistantError( - translation_domain=DOMAIN, - translation_key="command_failed", - translation_placeholders={ - "command": "execute_scene", - }, - ) from err - @cached_property def duid(self) -> str: """Get the unique id of the device as specified by Roborock.""" diff --git a/homeassistant/components/roborock/scene.py b/homeassistant/components/roborock/scene.py deleted file mode 100644 index ff418a2810c..00000000000 --- a/homeassistant/components/roborock/scene.py +++ /dev/null @@ -1,64 +0,0 @@ -"""Support for Roborock scene.""" - -from __future__ import annotations - -import asyncio -from typing import Any - -from homeassistant.components.scene import Scene as SceneEntity -from homeassistant.core import HomeAssistant -from homeassistant.helpers.entity import EntityDescription -from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback - -from . import RoborockConfigEntry -from .coordinator import RoborockDataUpdateCoordinator -from .entity import RoborockEntity - - -async def async_setup_entry( - hass: HomeAssistant, - config_entry: RoborockConfigEntry, - async_add_entities: AddConfigEntryEntitiesCallback, -) -> None: - """Set up scene platform.""" - scene_lists = await asyncio.gather( - *[coordinator.get_scenes() for coordinator in config_entry.runtime_data.v1], - ) - async_add_entities( - RoborockSceneEntity( - coordinator, - EntityDescription( - key=str(scene.id), - name=scene.name, - ), - ) - for coordinator, scenes in zip( - config_entry.runtime_data.v1, scene_lists, strict=True - ) - for scene in scenes - ) - - -class RoborockSceneEntity(RoborockEntity, SceneEntity): - """A class to define Roborock scene entities.""" - - entity_description: EntityDescription - - def __init__( - self, - coordinator: RoborockDataUpdateCoordinator, - entity_description: EntityDescription, - ) -> None: - """Create a scene entity.""" - super().__init__( - f"{entity_description.key}_{coordinator.duid_slug}", - coordinator.device_info, - coordinator.api, - ) - self._scene_id = int(entity_description.key) - self._coordinator = coordinator - self.entity_description = entity_description - - async def async_activate(self, **kwargs: Any) -> None: - """Activate the scene.""" - await self._coordinator.execute_scene(self._scene_id) diff --git a/tests/components/roborock/conftest.py b/tests/components/roborock/conftest.py index 9b3a6633c62..43e5148c9a8 100644 --- a/tests/components/roborock/conftest.py +++ b/tests/components/roborock/conftest.py @@ -30,7 +30,6 @@ from .mock_data import ( MULTI_MAP_LIST, NETWORK_INFO, PROP, - SCENES, USER_DATA, USER_EMAIL, ) @@ -68,24 +67,8 @@ class A01Mock(RoborockMqttClientA01): return {prot: self.protocol_responses[prot] for prot in dyad_data_protocols} -@pytest.fixture(name="bypass_api_client_fixture") -def bypass_api_client_fixture() -> None: - """Skip calls to the API client.""" - with ( - patch( - "homeassistant.components.roborock.RoborockApiClient.get_home_data_v2", - return_value=HOME_DATA, - ), - patch( - "homeassistant.components.roborock.RoborockApiClient.get_scenes", - return_value=SCENES, - ), - ): - yield - - @pytest.fixture(name="bypass_api_fixture") -def bypass_api_fixture(bypass_api_client_fixture: Any) -> None: +def bypass_api_fixture() -> None: """Skip calls to the API.""" with ( patch("homeassistant.components.roborock.RoborockMqttClientV1.async_connect"), @@ -93,6 +76,10 @@ def bypass_api_fixture(bypass_api_client_fixture: Any) -> None: patch( "homeassistant.components.roborock.coordinator.RoborockMqttClientV1._send_command" ), + patch( + "homeassistant.components.roborock.RoborockApiClient.get_home_data_v2", + return_value=HOME_DATA, + ), patch( "homeassistant.components.roborock.RoborockMqttClientV1.get_networking", return_value=NETWORK_INFO, diff --git a/tests/components/roborock/mock_data.py b/tests/components/roborock/mock_data.py index 59c54892687..6e3fb229aa9 100644 --- a/tests/components/roborock/mock_data.py +++ b/tests/components/roborock/mock_data.py @@ -9,7 +9,6 @@ from roborock.containers import ( Consumable, DnDTimer, HomeData, - HomeDataScene, MultiMapsList, NetworkInfo, S7Status, @@ -1151,19 +1150,3 @@ MAP_DATA = MapData(0, 0) MAP_DATA.image = ImageData( 100, 10, 10, 10, 10, ImageConfig(), Image.new("RGB", (1, 1)), lambda p: p ) - - -SCENES = [ - HomeDataScene.from_dict( - { - "name": "sc1", - "id": 12, - }, - ), - HomeDataScene.from_dict( - { - "name": "sc2", - "id": 24, - }, - ), -] diff --git a/tests/components/roborock/test_scene.py b/tests/components/roborock/test_scene.py deleted file mode 100644 index 15707784feb..00000000000 --- a/tests/components/roborock/test_scene.py +++ /dev/null @@ -1,112 +0,0 @@ -"""Test Roborock Scene platform.""" - -from unittest.mock import ANY, patch - -import pytest -from roborock import RoborockException - -from homeassistant.const import SERVICE_TURN_ON, Platform -from homeassistant.core import HomeAssistant -from homeassistant.exceptions import HomeAssistantError - -from tests.common import MockConfigEntry - - -@pytest.fixture -def bypass_api_client_get_scenes_fixture(bypass_api_fixture) -> None: - """Fixture to raise when getting scenes.""" - with ( - patch( - "homeassistant.components.roborock.RoborockApiClient.get_scenes", - side_effect=RoborockException(), - ), - ): - yield - - -@pytest.mark.parametrize( - ("entity_id"), - [ - ("scene.roborock_s7_maxv_sc1"), - ("scene.roborock_s7_maxv_sc2"), - ], -) -@pytest.mark.usefixtures("entity_registry_enabled_by_default") -async def test_get_scenes_failure( - hass: HomeAssistant, - bypass_api_client_get_scenes_fixture, - setup_entry: MockConfigEntry, - entity_id: str, -) -> None: - """Test that if scene retrieval fails, no entity is being created.""" - # Ensure that the entity does not exist - assert hass.states.get(entity_id) is None - - -@pytest.fixture -def platforms() -> list[Platform]: - """Fixture to set platforms used in the test.""" - return [Platform.SCENE] - - -@pytest.mark.parametrize( - ("entity_id", "scene_id"), - [ - ("scene.roborock_s7_maxv_sc1", 12), - ("scene.roborock_s7_maxv_sc2", 24), - ], -) -@pytest.mark.freeze_time("2023-10-30 08:50:00") -@pytest.mark.usefixtures("entity_registry_enabled_by_default") -async def test_execute_success( - hass: HomeAssistant, - bypass_api_fixture, - setup_entry: MockConfigEntry, - entity_id: str, - scene_id: int, -) -> None: - """Test activating the scene entities.""" - with patch( - "homeassistant.components.roborock.RoborockApiClient.execute_scene" - ) as mock_execute_scene: - await hass.services.async_call( - "scene", - SERVICE_TURN_ON, - blocking=True, - target={"entity_id": entity_id}, - ) - mock_execute_scene.assert_called_once_with(ANY, scene_id) - assert hass.states.get(entity_id).state == "2023-10-30T08:50:00+00:00" - - -@pytest.mark.parametrize( - ("entity_id", "scene_id"), - [ - ("scene.roborock_s7_maxv_sc1", 12), - ], -) -@pytest.mark.freeze_time("2023-10-30 08:50:00") -@pytest.mark.usefixtures("entity_registry_enabled_by_default") -async def test_execute_failure( - hass: HomeAssistant, - bypass_api_fixture, - setup_entry: MockConfigEntry, - entity_id: str, - scene_id: int, -) -> None: - """Test failure while activating the scene entity.""" - with ( - patch( - "homeassistant.components.roborock.RoborockApiClient.execute_scene", - side_effect=RoborockException, - ) as mock_execute_scene, - pytest.raises(HomeAssistantError, match="Error while calling execute_scene"), - ): - await hass.services.async_call( - "scene", - SERVICE_TURN_ON, - blocking=True, - target={"entity_id": entity_id}, - ) - mock_execute_scene.assert_called_once_with(ANY, scene_id) - assert hass.states.get(entity_id).state == "2023-10-30T08:50:00+00:00"