mirror of
https://github.com/home-assistant/core.git
synced 2025-07-07 21:37:07 +00:00
Separate Roborock entities to a new dock device (#140612)
* Seperate entities to a new dock device * update entity names * Update homeassistant/components/roborock/coordinator.py --------- Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
ed2ef04b98
commit
baafcf48dc
@ -26,6 +26,8 @@ class RoborockBinarySensorDescription(BinarySensorEntityDescription):
|
|||||||
"""A class that describes Roborock binary sensors."""
|
"""A class that describes Roborock binary sensors."""
|
||||||
|
|
||||||
value_fn: Callable[[DeviceProp], bool | int | None]
|
value_fn: Callable[[DeviceProp], bool | int | None]
|
||||||
|
# If it is a dock entity
|
||||||
|
is_dock_entity: bool = False
|
||||||
|
|
||||||
|
|
||||||
BINARY_SENSOR_DESCRIPTIONS = [
|
BINARY_SENSOR_DESCRIPTIONS = [
|
||||||
@ -35,6 +37,7 @@ BINARY_SENSOR_DESCRIPTIONS = [
|
|||||||
device_class=BinarySensorDeviceClass.RUNNING,
|
device_class=BinarySensorDeviceClass.RUNNING,
|
||||||
entity_category=EntityCategory.DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
value_fn=lambda data: data.status.dry_status,
|
value_fn=lambda data: data.status.dry_status,
|
||||||
|
is_dock_entity=True,
|
||||||
),
|
),
|
||||||
RoborockBinarySensorDescription(
|
RoborockBinarySensorDescription(
|
||||||
key="water_box_carriage_status",
|
key="water_box_carriage_status",
|
||||||
@ -105,6 +108,7 @@ class RoborockBinarySensorEntity(RoborockCoordinatedEntityV1, BinarySensorEntity
|
|||||||
super().__init__(
|
super().__init__(
|
||||||
f"{description.key}_{coordinator.duid_slug}",
|
f"{description.key}_{coordinator.duid_slug}",
|
||||||
coordinator,
|
coordinator,
|
||||||
|
is_dock_entity=description.is_dock_entity,
|
||||||
)
|
)
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
|
|
||||||
|
@ -128,6 +128,23 @@ class RoborockDataUpdateCoordinator(DataUpdateCoordinator[DeviceProp]):
|
|||||||
self._api_client = api_client
|
self._api_client = api_client
|
||||||
self._is_cloud_api = False
|
self._is_cloud_api = False
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def dock_device_info(self) -> DeviceInfo:
|
||||||
|
"""Gets the device info for the dock.
|
||||||
|
|
||||||
|
This must happen after the coordinator does the first update.
|
||||||
|
Which will be the case when this is called.
|
||||||
|
"""
|
||||||
|
dock_type = self.roborock_device_info.props.status.dock_type
|
||||||
|
return DeviceInfo(
|
||||||
|
name=f"{self.roborock_device_info.device.name} Dock",
|
||||||
|
identifiers={(DOMAIN, f"{self.duid}_dock")},
|
||||||
|
manufacturer="Roborock",
|
||||||
|
model=f"{self.roborock_device_info.product.model} Dock",
|
||||||
|
model_id=str(dock_type.value) if dock_type is not None else "Unknown",
|
||||||
|
sw_version=self.roborock_device_info.device.fv,
|
||||||
|
)
|
||||||
|
|
||||||
async def _async_setup(self) -> None:
|
async def _async_setup(self) -> None:
|
||||||
"""Set up the coordinator."""
|
"""Set up the coordinator."""
|
||||||
# Verify we can communicate locally - if we can't, switch to cloud api
|
# Verify we can communicate locally - if we can't, switch to cloud api
|
||||||
|
@ -121,12 +121,15 @@ class RoborockCoordinatedEntityV1(
|
|||||||
listener_request: list[RoborockDataProtocol]
|
listener_request: list[RoborockDataProtocol]
|
||||||
| RoborockDataProtocol
|
| RoborockDataProtocol
|
||||||
| None = None,
|
| None = None,
|
||||||
|
is_dock_entity: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the coordinated Roborock Device."""
|
"""Initialize the coordinated Roborock Device."""
|
||||||
RoborockEntityV1.__init__(
|
RoborockEntityV1.__init__(
|
||||||
self,
|
self,
|
||||||
unique_id=unique_id,
|
unique_id=unique_id,
|
||||||
device_info=coordinator.device_info,
|
device_info=coordinator.device_info
|
||||||
|
if not is_dock_entity
|
||||||
|
else coordinator.dock_device_info,
|
||||||
api=coordinator.api,
|
api=coordinator.api,
|
||||||
)
|
)
|
||||||
CoordinatorEntity.__init__(self, coordinator=coordinator)
|
CoordinatorEntity.__init__(self, coordinator=coordinator)
|
||||||
|
@ -32,6 +32,8 @@ class RoborockSelectDescription(SelectEntityDescription):
|
|||||||
parameter_lambda: Callable[[str, DeviceProp], list[int]]
|
parameter_lambda: Callable[[str, DeviceProp], list[int]]
|
||||||
|
|
||||||
protocol_listener: RoborockDataProtocol | None = None
|
protocol_listener: RoborockDataProtocol | None = None
|
||||||
|
# If it is a dock entity
|
||||||
|
is_dock_entity: bool = False
|
||||||
|
|
||||||
|
|
||||||
SELECT_DESCRIPTIONS: list[RoborockSelectDescription] = [
|
SELECT_DESCRIPTIONS: list[RoborockSelectDescription] = [
|
||||||
@ -70,6 +72,7 @@ SELECT_DESCRIPTIONS: list[RoborockSelectDescription] = [
|
|||||||
parameter_lambda=lambda key, _: [
|
parameter_lambda=lambda key, _: [
|
||||||
RoborockDockDustCollectionModeCode.as_dict().get(key)
|
RoborockDockDustCollectionModeCode.as_dict().get(key)
|
||||||
],
|
],
|
||||||
|
is_dock_entity=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -117,6 +120,7 @@ class RoborockSelectEntity(RoborockCoordinatedEntityV1, SelectEntity):
|
|||||||
f"{entity_description.key}_{coordinator.duid_slug}",
|
f"{entity_description.key}_{coordinator.duid_slug}",
|
||||||
coordinator,
|
coordinator,
|
||||||
entity_description.protocol_listener,
|
entity_description.protocol_listener,
|
||||||
|
is_dock_entity=entity_description.is_dock_entity,
|
||||||
)
|
)
|
||||||
self._attr_options = options
|
self._attr_options = options
|
||||||
|
|
||||||
|
@ -47,6 +47,9 @@ class RoborockSensorDescription(SensorEntityDescription):
|
|||||||
|
|
||||||
protocol_listener: RoborockDataProtocol | None = None
|
protocol_listener: RoborockDataProtocol | None = None
|
||||||
|
|
||||||
|
# If it is a dock entity
|
||||||
|
is_dock_entity: bool = False
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, kw_only=True)
|
@dataclass(frozen=True, kw_only=True)
|
||||||
class RoborockSensorDescriptionA01(SensorEntityDescription):
|
class RoborockSensorDescriptionA01(SensorEntityDescription):
|
||||||
@ -197,6 +200,7 @@ SENSOR_DESCRIPTIONS = [
|
|||||||
entity_category=EntityCategory.DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
options=RoborockDockErrorCode.keys(),
|
options=RoborockDockErrorCode.keys(),
|
||||||
|
is_dock_entity=True,
|
||||||
),
|
),
|
||||||
RoborockSensorDescription(
|
RoborockSensorDescription(
|
||||||
key="mop_clean_remaining",
|
key="mop_clean_remaining",
|
||||||
@ -205,6 +209,7 @@ SENSOR_DESCRIPTIONS = [
|
|||||||
value_fn=lambda data: data.status.rdt,
|
value_fn=lambda data: data.status.rdt,
|
||||||
translation_key="mop_drying_remaining_time",
|
translation_key="mop_drying_remaining_time",
|
||||||
entity_category=EntityCategory.DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
is_dock_entity=True,
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -335,6 +340,7 @@ class RoborockSensorEntity(RoborockCoordinatedEntityV1, SensorEntity):
|
|||||||
f"{description.key}_{coordinator.duid_slug}",
|
f"{description.key}_{coordinator.duid_slug}",
|
||||||
coordinator,
|
coordinator,
|
||||||
description.protocol_listener,
|
description.protocol_listener,
|
||||||
|
is_dock_entity=description.is_dock_entity,
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -35,6 +35,8 @@ class RoborockSwitchDescription(SwitchEntityDescription):
|
|||||||
update_value: Callable[[AttributeCache, bool], Coroutine[Any, Any, None]]
|
update_value: Callable[[AttributeCache, bool], Coroutine[Any, Any, None]]
|
||||||
# Attribute from cache
|
# Attribute from cache
|
||||||
attribute: str
|
attribute: str
|
||||||
|
# If it is a dock entity
|
||||||
|
is_dock_entity: bool = False
|
||||||
|
|
||||||
|
|
||||||
SWITCH_DESCRIPTIONS: list[RoborockSwitchDescription] = [
|
SWITCH_DESCRIPTIONS: list[RoborockSwitchDescription] = [
|
||||||
@ -47,6 +49,7 @@ SWITCH_DESCRIPTIONS: list[RoborockSwitchDescription] = [
|
|||||||
key="child_lock",
|
key="child_lock",
|
||||||
translation_key="child_lock",
|
translation_key="child_lock",
|
||||||
entity_category=EntityCategory.CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
is_dock_entity=True,
|
||||||
),
|
),
|
||||||
RoborockSwitchDescription(
|
RoborockSwitchDescription(
|
||||||
cache_key=CacheableAttribute.flow_led_status,
|
cache_key=CacheableAttribute.flow_led_status,
|
||||||
@ -57,6 +60,7 @@ SWITCH_DESCRIPTIONS: list[RoborockSwitchDescription] = [
|
|||||||
key="status_indicator",
|
key="status_indicator",
|
||||||
translation_key="status_indicator",
|
translation_key="status_indicator",
|
||||||
entity_category=EntityCategory.CONFIG,
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
is_dock_entity=True,
|
||||||
),
|
),
|
||||||
RoborockSwitchDescription(
|
RoborockSwitchDescription(
|
||||||
cache_key=CacheableAttribute.dnd_timer,
|
cache_key=CacheableAttribute.dnd_timer,
|
||||||
@ -147,7 +151,13 @@ class RoborockSwitch(RoborockEntityV1, SwitchEntity):
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the entity."""
|
"""Initialize the entity."""
|
||||||
self.entity_description = entity_description
|
self.entity_description = entity_description
|
||||||
super().__init__(unique_id, coordinator.device_info, coordinator.api)
|
super().__init__(
|
||||||
|
unique_id,
|
||||||
|
coordinator.device_info
|
||||||
|
if not entity_description.is_dock_entity
|
||||||
|
else coordinator.dock_device_info,
|
||||||
|
coordinator.api,
|
||||||
|
)
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
"""Turn off the switch."""
|
"""Turn off the switch."""
|
||||||
|
@ -53,7 +53,7 @@ async def test_sensors(hass: HomeAssistant, setup_entry: MockConfigEntry) -> Non
|
|||||||
assert hass.states.get("sensor.roborock_s7_maxv_cleaning_area").state == "21.0"
|
assert hass.states.get("sensor.roborock_s7_maxv_cleaning_area").state == "21.0"
|
||||||
assert hass.states.get("sensor.roborock_s7_maxv_vacuum_error").state == "none"
|
assert hass.states.get("sensor.roborock_s7_maxv_vacuum_error").state == "none"
|
||||||
assert hass.states.get("sensor.roborock_s7_maxv_battery").state == "100"
|
assert hass.states.get("sensor.roborock_s7_maxv_battery").state == "100"
|
||||||
assert hass.states.get("sensor.roborock_s7_maxv_dock_error").state == "ok"
|
assert hass.states.get("sensor.roborock_s7_maxv_dock_dock_error").state == "ok"
|
||||||
assert hass.states.get("sensor.roborock_s7_maxv_total_cleaning_count").state == "31"
|
assert hass.states.get("sensor.roborock_s7_maxv_total_cleaning_count").state == "31"
|
||||||
assert (
|
assert (
|
||||||
hass.states.get("sensor.roborock_s7_maxv_last_clean_begin").state
|
hass.states.get("sensor.roborock_s7_maxv_last_clean_begin").state
|
||||||
|
@ -22,8 +22,8 @@ def platforms() -> list[Platform]:
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("entity_id"),
|
("entity_id"),
|
||||||
[
|
[
|
||||||
("switch.roborock_s7_maxv_child_lock"),
|
("switch.roborock_s7_maxv_dock_child_lock"),
|
||||||
("switch.roborock_s7_maxv_status_indicator_light"),
|
("switch.roborock_s7_maxv_dock_status_indicator_light"),
|
||||||
("switch.roborock_s7_maxv_do_not_disturb"),
|
("switch.roborock_s7_maxv_do_not_disturb"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -59,8 +59,8 @@ async def test_update_success(
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("entity_id", "service"),
|
("entity_id", "service"),
|
||||||
[
|
[
|
||||||
("switch.roborock_s7_maxv_status_indicator_light", SERVICE_TURN_ON),
|
("switch.roborock_s7_maxv_dock_status_indicator_light", SERVICE_TURN_ON),
|
||||||
("switch.roborock_s7_maxv_status_indicator_light", SERVICE_TURN_OFF),
|
("switch.roborock_s7_maxv_dock_status_indicator_light", SERVICE_TURN_OFF),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user