Add Fallback to cloud api for Roborock (#96147)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>pull/97152/head^2
parent
6b980eb0a7
commit
2c42a319a2
|
@ -36,24 +36,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
}
|
||||
product_info = {product.id: product for product in home_data.products}
|
||||
# Create a mqtt_client, which is needed to get the networking information of the device for local connection and in the future, get the map.
|
||||
mqtt_clients = [
|
||||
RoborockMqttClient(
|
||||
mqtt_clients = {
|
||||
device.duid: RoborockMqttClient(
|
||||
user_data, DeviceData(device, product_info[device.product_id].model)
|
||||
)
|
||||
for device in device_map.values()
|
||||
]
|
||||
}
|
||||
network_results = await asyncio.gather(
|
||||
*(mqtt_client.get_networking() for mqtt_client in mqtt_clients)
|
||||
*(mqtt_client.get_networking() for mqtt_client in mqtt_clients.values())
|
||||
)
|
||||
network_info = {
|
||||
device.duid: result
|
||||
for device, result in zip(device_map.values(), network_results)
|
||||
if result is not None
|
||||
}
|
||||
await asyncio.gather(
|
||||
*(mqtt_client.async_disconnect() for mqtt_client in mqtt_clients),
|
||||
return_exceptions=True,
|
||||
)
|
||||
if not network_info:
|
||||
raise ConfigEntryNotReady(
|
||||
"Could not get network information about your devices"
|
||||
|
@ -65,7 +61,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
device,
|
||||
network_info[device_id],
|
||||
product_info[device.product_id],
|
||||
mqtt_clients[device.duid],
|
||||
)
|
||||
await asyncio.gather(
|
||||
*(coordinator.verify_api() for coordinator in coordinator_map.values())
|
||||
)
|
||||
# If one device update fails - we still want to set up other devices
|
||||
await asyncio.gather(
|
||||
*(
|
||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from roborock.cloud_api import RoborockMqttClient
|
||||
from roborock.containers import DeviceData, HomeDataDevice, HomeDataProduct, NetworkInfo
|
||||
from roborock.exceptions import RoborockException
|
||||
from roborock.local_api import RoborockLocalClient
|
||||
|
@ -30,6 +31,7 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]):
|
|||
device: HomeDataDevice,
|
||||
device_networking: NetworkInfo,
|
||||
product_info: HomeDataProduct,
|
||||
cloud_api: RoborockMqttClient | None = None,
|
||||
) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL)
|
||||
|
@ -41,6 +43,7 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]):
|
|||
)
|
||||
device_data = DeviceData(device, product_info.model, device_networking.ip)
|
||||
self.api = RoborockLocalClient(device_data)
|
||||
self.cloud_api = cloud_api
|
||||
self.device_info = DeviceInfo(
|
||||
name=self.roborock_device_info.device.name,
|
||||
identifiers={(DOMAIN, self.roborock_device_info.device.duid)},
|
||||
|
@ -49,6 +52,21 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]):
|
|||
sw_version=self.roborock_device_info.device.fv,
|
||||
)
|
||||
|
||||
async def verify_api(self) -> None:
|
||||
"""Verify that the api is reachable. If it is not, switch clients."""
|
||||
try:
|
||||
await self.api.ping()
|
||||
except RoborockException:
|
||||
if isinstance(self.api, RoborockLocalClient):
|
||||
_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.roborock_device_info.device.duid,
|
||||
)
|
||||
# We use the cloud api if the local api fails to connect.
|
||||
self.api = self.cloud_api
|
||||
# Right now this should never be called if the cloud api is the primary api,
|
||||
# but in the future if it is, a new else should be added.
|
||||
|
||||
async def release(self) -> None:
|
||||
"""Disconnect from API."""
|
||||
await self.api.async_disconnect()
|
||||
|
|
|
@ -2,11 +2,10 @@
|
|||
|
||||
from typing import Any
|
||||
|
||||
from roborock.api import AttributeCache
|
||||
from roborock.api import AttributeCache, RoborockClient
|
||||
from roborock.command_cache import CacheableAttribute
|
||||
from roborock.containers import Status
|
||||
from roborock.exceptions import RoborockException
|
||||
from roborock.local_api import RoborockLocalClient
|
||||
from roborock.roborock_typing import RoborockCommand
|
||||
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
@ -22,7 +21,7 @@ class RoborockEntity(Entity):
|
|||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self, unique_id: str, device_info: DeviceInfo, api: RoborockLocalClient
|
||||
self, unique_id: str, device_info: DeviceInfo, api: RoborockClient
|
||||
) -> None:
|
||||
"""Initialize the coordinated Roborock Device."""
|
||||
self._attr_unique_id = unique_id
|
||||
|
@ -30,8 +29,8 @@ class RoborockEntity(Entity):
|
|||
self._api = api
|
||||
|
||||
@property
|
||||
def api(self) -> RoborockLocalClient:
|
||||
"""Return the Api."""
|
||||
def api(self) -> RoborockClient:
|
||||
"""Returns the api."""
|
||||
return self._api
|
||||
|
||||
def get_cache(self, attribute: CacheableAttribute) -> AttributeCache:
|
||||
|
|
|
@ -9,13 +9,11 @@ from typing import Any
|
|||
|
||||
from roborock.api import AttributeCache
|
||||
from roborock.command_cache import CacheableAttribute
|
||||
from roborock.local_api import RoborockLocalClient
|
||||
|
||||
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import slugify
|
||||
|
||||
|
@ -121,9 +119,8 @@ async def async_setup_entry(
|
|||
valid_entities.append(
|
||||
RoborockSwitch(
|
||||
f"{description.key}_{slugify(coordinator.roborock_device_info.device.duid)}",
|
||||
coordinator.device_info,
|
||||
coordinator,
|
||||
description,
|
||||
coordinator.api,
|
||||
)
|
||||
)
|
||||
async_add_entities(valid_entities)
|
||||
|
@ -137,13 +134,12 @@ class RoborockSwitch(RoborockEntity, SwitchEntity):
|
|||
def __init__(
|
||||
self,
|
||||
unique_id: str,
|
||||
device_info: DeviceInfo,
|
||||
description: RoborockSwitchDescription,
|
||||
api: RoborockLocalClient,
|
||||
coordinator: RoborockDataUpdateCoordinator,
|
||||
entity_description: RoborockSwitchDescription,
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
super().__init__(unique_id, device_info, api)
|
||||
self.entity_description = description
|
||||
self.entity_description = entity_description
|
||||
super().__init__(unique_id, coordinator.device_info, coordinator.api)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off the switch."""
|
||||
|
|
Loading…
Reference in New Issue