2023-04-20 14:02:58 +00:00
|
|
|
"""Support for Roborock device base class."""
|
2024-03-08 14:05:07 +00:00
|
|
|
|
2023-04-20 14:02:58 +00:00
|
|
|
from typing import Any
|
|
|
|
|
2024-06-26 13:40:19 +00:00
|
|
|
from roborock.api import RoborockClient
|
2023-06-29 17:13:37 +00:00
|
|
|
from roborock.command_cache import CacheableAttribute
|
2023-11-20 00:24:43 +00:00
|
|
|
from roborock.containers import Consumable, Status
|
2023-05-19 03:55:39 +00:00
|
|
|
from roborock.exceptions import RoborockException
|
2024-02-12 08:37:37 +00:00
|
|
|
from roborock.roborock_message import RoborockDataProtocol
|
2023-05-19 03:55:39 +00:00
|
|
|
from roborock.roborock_typing import RoborockCommand
|
2024-04-10 00:50:46 +00:00
|
|
|
from roborock.version_1_apis.roborock_client_v1 import AttributeCache, RoborockClientV1
|
|
|
|
from roborock.version_1_apis.roborock_mqtt_client_v1 import RoborockMqttClientV1
|
2024-06-26 13:40:19 +00:00
|
|
|
from roborock.version_a01_apis import RoborockClientA01
|
2023-04-20 14:02:58 +00:00
|
|
|
|
2023-05-19 03:55:39 +00:00
|
|
|
from homeassistant.exceptions import HomeAssistantError
|
2023-08-11 02:04:26 +00:00
|
|
|
from homeassistant.helpers.device_registry import DeviceInfo
|
|
|
|
from homeassistant.helpers.entity import Entity
|
2023-04-20 14:02:58 +00:00
|
|
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
|
|
|
|
2024-01-16 20:00:20 +00:00
|
|
|
from .const import DOMAIN
|
2024-06-26 13:40:19 +00:00
|
|
|
from .coordinator import RoborockDataUpdateCoordinator, RoborockDataUpdateCoordinatorA01
|
2023-04-20 14:02:58 +00:00
|
|
|
|
|
|
|
|
2023-05-31 02:58:27 +00:00
|
|
|
class RoborockEntity(Entity):
|
|
|
|
"""Representation of a base Roborock Entity."""
|
|
|
|
|
|
|
|
_attr_has_entity_name = True
|
|
|
|
|
|
|
|
def __init__(
|
2024-02-12 08:37:37 +00:00
|
|
|
self,
|
|
|
|
unique_id: str,
|
|
|
|
device_info: DeviceInfo,
|
2024-06-26 13:40:19 +00:00
|
|
|
api: RoborockClient,
|
2023-05-31 02:58:27 +00:00
|
|
|
) -> None:
|
2024-06-26 13:40:19 +00:00
|
|
|
"""Initialize the Roborock Device."""
|
2023-05-31 02:58:27 +00:00
|
|
|
self._attr_unique_id = unique_id
|
|
|
|
self._attr_device_info = device_info
|
|
|
|
self._api = api
|
|
|
|
|
2024-06-26 13:40:19 +00:00
|
|
|
|
|
|
|
class RoborockEntityV1(RoborockEntity):
|
|
|
|
"""Representation of a base Roborock V1 Entity."""
|
|
|
|
|
|
|
|
_api: RoborockClientV1
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self, unique_id: str, device_info: DeviceInfo, api: RoborockClientV1
|
|
|
|
) -> None:
|
|
|
|
"""Initialize the Roborock Device."""
|
|
|
|
super().__init__(unique_id, device_info, api)
|
2023-06-29 17:13:37 +00:00
|
|
|
|
|
|
|
def get_cache(self, attribute: CacheableAttribute) -> AttributeCache:
|
|
|
|
"""Get an item from the api cache."""
|
2023-11-08 11:48:05 +00:00
|
|
|
return self._api.cache[attribute]
|
2023-06-29 17:13:37 +00:00
|
|
|
|
2023-05-31 02:58:27 +00:00
|
|
|
async def send(
|
2023-07-23 17:02:16 +00:00
|
|
|
self,
|
2023-09-19 14:35:23 +00:00
|
|
|
command: RoborockCommand | str,
|
2023-07-23 17:02:16 +00:00
|
|
|
params: dict[str, Any] | list[Any] | int | None = None,
|
2023-05-31 02:58:27 +00:00
|
|
|
) -> dict:
|
|
|
|
"""Send a command to a vacuum cleaner."""
|
|
|
|
try:
|
2023-11-08 11:48:05 +00:00
|
|
|
response: dict = await self._api.send_command(command, params)
|
2023-05-31 02:58:27 +00:00
|
|
|
except RoborockException as err:
|
2024-01-16 20:00:20 +00:00
|
|
|
if isinstance(command, RoborockCommand):
|
|
|
|
command_name = command.name
|
|
|
|
else:
|
|
|
|
command_name = command
|
2023-05-31 02:58:27 +00:00
|
|
|
raise HomeAssistantError(
|
2024-01-16 20:00:20 +00:00
|
|
|
translation_domain=DOMAIN,
|
|
|
|
translation_key="command_failed",
|
|
|
|
translation_placeholders={
|
|
|
|
"command": command_name,
|
|
|
|
},
|
2023-05-31 02:58:27 +00:00
|
|
|
) from err
|
|
|
|
return response
|
|
|
|
|
2024-06-26 13:40:19 +00:00
|
|
|
@property
|
|
|
|
def api(self) -> RoborockClientV1:
|
|
|
|
"""Returns the api."""
|
|
|
|
return self._api
|
|
|
|
|
|
|
|
|
|
|
|
class RoborockEntityA01(RoborockEntity):
|
|
|
|
"""Representation of a base Roborock Entity for A01 devices."""
|
|
|
|
|
|
|
|
_api: RoborockClientA01
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self, unique_id: str, device_info: DeviceInfo, api: RoborockClientA01
|
|
|
|
) -> None:
|
|
|
|
"""Initialize the Roborock Device."""
|
|
|
|
super().__init__(unique_id, device_info, api)
|
|
|
|
|
2023-05-31 02:58:27 +00:00
|
|
|
|
2024-06-26 13:40:19 +00:00
|
|
|
class RoborockCoordinatedEntityV1(
|
|
|
|
RoborockEntityV1, CoordinatorEntity[RoborockDataUpdateCoordinator]
|
2023-05-31 02:58:27 +00:00
|
|
|
):
|
2023-04-20 14:02:58 +00:00
|
|
|
"""Representation of a base a coordinated Roborock Entity."""
|
|
|
|
|
|
|
|
_attr_has_entity_name = True
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
unique_id: str,
|
|
|
|
coordinator: RoborockDataUpdateCoordinator,
|
2024-02-12 08:37:37 +00:00
|
|
|
listener_request: list[RoborockDataProtocol]
|
|
|
|
| RoborockDataProtocol
|
|
|
|
| None = None,
|
2023-04-20 14:02:58 +00:00
|
|
|
) -> None:
|
|
|
|
"""Initialize the coordinated Roborock Device."""
|
2024-06-26 13:40:19 +00:00
|
|
|
RoborockEntityV1.__init__(
|
2023-05-31 02:58:27 +00:00
|
|
|
self,
|
|
|
|
unique_id=unique_id,
|
2023-05-31 03:33:18 +00:00
|
|
|
device_info=coordinator.device_info,
|
2023-05-31 02:58:27 +00:00
|
|
|
api=coordinator.api,
|
|
|
|
)
|
|
|
|
CoordinatorEntity.__init__(self, coordinator=coordinator)
|
2023-04-20 14:02:58 +00:00
|
|
|
self._attr_unique_id = unique_id
|
2024-02-12 08:37:37 +00:00
|
|
|
if isinstance(listener_request, RoborockDataProtocol):
|
|
|
|
listener_request = [listener_request]
|
|
|
|
self.listener_requests = listener_request or []
|
|
|
|
|
|
|
|
async def async_added_to_hass(self) -> None:
|
|
|
|
"""Add listeners when the device is added to hass."""
|
|
|
|
await super().async_added_to_hass()
|
|
|
|
for listener_request in self.listener_requests:
|
|
|
|
self.api.add_listener(
|
|
|
|
listener_request, self._update_from_listener, cache=self.api.cache
|
|
|
|
)
|
|
|
|
|
|
|
|
async def async_will_remove_from_hass(self) -> None:
|
|
|
|
"""Remove listeners when the device is removed from hass."""
|
|
|
|
for listener_request in self.listener_requests:
|
|
|
|
self.api.remove_listener(listener_request, self._update_from_listener)
|
|
|
|
await super().async_will_remove_from_hass()
|
2023-04-20 14:02:58 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def _device_status(self) -> Status:
|
|
|
|
"""Return the status of the device."""
|
|
|
|
data = self.coordinator.data
|
2023-11-08 11:48:05 +00:00
|
|
|
return data.status
|
2023-06-12 18:30:15 +00:00
|
|
|
|
2023-11-18 20:22:30 +00:00
|
|
|
@property
|
2024-04-10 00:50:46 +00:00
|
|
|
def cloud_api(self) -> RoborockMqttClientV1:
|
2023-11-18 20:22:30 +00:00
|
|
|
"""Return the cloud api."""
|
|
|
|
return self.coordinator.cloud_api
|
|
|
|
|
2023-06-12 18:30:15 +00:00
|
|
|
async def send(
|
|
|
|
self,
|
2023-11-08 11:48:05 +00:00
|
|
|
command: RoborockCommand | str,
|
2023-07-23 17:02:16 +00:00
|
|
|
params: dict[str, Any] | list[Any] | int | None = None,
|
2023-06-12 18:30:15 +00:00
|
|
|
) -> dict:
|
|
|
|
"""Overloads normal send command but refreshes coordinator."""
|
|
|
|
res = await super().send(command, params)
|
|
|
|
await self.coordinator.async_refresh()
|
|
|
|
return res
|
2023-11-20 00:24:43 +00:00
|
|
|
|
2024-02-12 08:37:37 +00:00
|
|
|
def _update_from_listener(self, value: Status | Consumable) -> None:
|
2023-11-20 00:24:43 +00:00
|
|
|
"""Update the status or consumable data from a listener and then write the new entity state."""
|
|
|
|
if isinstance(value, Status):
|
|
|
|
self.coordinator.roborock_device_info.props.status = value
|
|
|
|
else:
|
|
|
|
self.coordinator.roborock_device_info.props.consumable = value
|
|
|
|
self.coordinator.data = self.coordinator.roborock_device_info.props
|
2024-04-25 18:26:11 +00:00
|
|
|
self.schedule_update_ha_state()
|
2024-06-26 13:40:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
class RoborockCoordinatedEntityA01(
|
|
|
|
RoborockEntityA01, CoordinatorEntity[RoborockDataUpdateCoordinatorA01]
|
|
|
|
):
|
|
|
|
"""Representation of a base a coordinated Roborock Entity."""
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
unique_id: str,
|
|
|
|
coordinator: RoborockDataUpdateCoordinatorA01,
|
|
|
|
) -> None:
|
|
|
|
"""Initialize the coordinated Roborock Device."""
|
|
|
|
RoborockEntityA01.__init__(
|
|
|
|
self,
|
|
|
|
unique_id=unique_id,
|
|
|
|
device_info=coordinator.device_info,
|
|
|
|
api=coordinator.api,
|
|
|
|
)
|
|
|
|
CoordinatorEntity.__init__(self, coordinator=coordinator)
|
|
|
|
self._attr_unique_id = unique_id
|