mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 17:04:04 -04:00
Fix Roborock dock cleaning brush entity support (#180709)
This commit is contained in:
@@ -10,9 +10,10 @@ from roborock.exceptions import RoborockException
|
||||
from roborock.roborock_message import RoborockZeoProtocol
|
||||
|
||||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||
from homeassistant.const import EntityCategory
|
||||
from homeassistant.const import EntityCategory, Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
@@ -94,7 +95,7 @@ CONSUMABLE_BUTTON_DESCRIPTIONS = [
|
||||
entity_registry_enabled_default=False,
|
||||
is_dock_entity=True,
|
||||
is_supported=lambda coordinator: (
|
||||
coordinator.properties_api.wash_towel_mode is not None
|
||||
coordinator.properties_api.device_features.dock_features.is_cleaning_brush_supported
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -141,6 +142,7 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up Roborock button platform."""
|
||||
coordinators = config_entry.runtime_data
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
@callback
|
||||
def async_add_coordinator_entities(
|
||||
@@ -149,11 +151,18 @@ async def async_setup_entry(
|
||||
"""Add entities for a specific coordinator."""
|
||||
entities: list[ButtonEntity] = []
|
||||
if isinstance(coordinator, RoborockDataUpdateCoordinator):
|
||||
entities.extend(
|
||||
RoborockButtonEntity(coordinator, description)
|
||||
for description in CONSUMABLE_BUTTON_DESCRIPTIONS
|
||||
if description.is_supported(coordinator)
|
||||
)
|
||||
for description in CONSUMABLE_BUTTON_DESCRIPTIONS:
|
||||
unique_id = f"{description.key}_{coordinator.duid_slug}"
|
||||
if description.is_supported(coordinator):
|
||||
entities.append(
|
||||
RoborockButtonEntity(unique_id, coordinator, description)
|
||||
)
|
||||
elif entity_id := entity_registry.async_get_entity_id(
|
||||
Platform.BUTTON,
|
||||
DOMAIN,
|
||||
unique_id,
|
||||
):
|
||||
entity_registry.async_remove(entity_id)
|
||||
|
||||
async def async_add_routine_buttons() -> None:
|
||||
try:
|
||||
@@ -213,6 +222,7 @@ class RoborockButtonEntity(RoborockEntityV1, ButtonEntity):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
unique_id: str,
|
||||
coordinator: RoborockDataUpdateCoordinator,
|
||||
entity_description: RoborockButtonDescription,
|
||||
) -> None:
|
||||
@@ -223,7 +233,7 @@ class RoborockButtonEntity(RoborockEntityV1, ButtonEntity):
|
||||
else coordinator.device_info
|
||||
)
|
||||
super().__init__(
|
||||
f"{entity_description.key}_{coordinator.duid_slug}",
|
||||
unique_id,
|
||||
device_info,
|
||||
api=coordinator.properties_api.command,
|
||||
)
|
||||
|
||||
@@ -30,12 +30,20 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfArea, UnitOfTime
|
||||
from homeassistant.const import (
|
||||
PERCENTAGE,
|
||||
EntityCategory,
|
||||
Platform,
|
||||
UnitOfArea,
|
||||
UnitOfTime,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import (
|
||||
RoborockB01Q7UpdateCoordinator,
|
||||
RoborockB01Q10UpdateCoordinator,
|
||||
@@ -139,7 +147,9 @@ SENSOR_DESCRIPTIONS = [
|
||||
value_fn=lambda data: data.consumable.cleaning_brush_time_left,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
is_dock_entity=True,
|
||||
support_fn=lambda api: api.wash_towel_mode is not None,
|
||||
support_fn=lambda api: (
|
||||
api.device_features.dock_features.is_cleaning_brush_supported
|
||||
),
|
||||
),
|
||||
RoborockSensorDescription(
|
||||
native_unit_of_measurement=UnitOfTime.HOURS,
|
||||
@@ -541,6 +551,7 @@ async def async_setup_entry(
|
||||
) -> None:
|
||||
"""Set up the Roborock vacuum sensors."""
|
||||
coordinators = config_entry.runtime_data
|
||||
entity_registry = er.async_get(hass)
|
||||
|
||||
@callback
|
||||
def async_add_coordinator_entities(
|
||||
@@ -549,11 +560,18 @@ async def async_setup_entry(
|
||||
"""Add entities for a specific coordinator."""
|
||||
entities: list[RoborockEntity] = []
|
||||
if isinstance(coordinator, RoborockDataUpdateCoordinator):
|
||||
entities.extend(
|
||||
RoborockSensorEntity(coordinator, description)
|
||||
for description in SENSOR_DESCRIPTIONS
|
||||
if description.support_fn(coordinator.properties_api)
|
||||
)
|
||||
for description in SENSOR_DESCRIPTIONS:
|
||||
unique_id = f"{description.key}_{coordinator.duid_slug}"
|
||||
if description.support_fn(coordinator.properties_api):
|
||||
entities.append(
|
||||
RoborockSensorEntity(unique_id, coordinator, description)
|
||||
)
|
||||
elif entity_id := entity_registry.async_get_entity_id(
|
||||
Platform.SENSOR,
|
||||
DOMAIN,
|
||||
unique_id,
|
||||
):
|
||||
entity_registry.async_remove(entity_id)
|
||||
entities.append(RoborockCurrentRoom(coordinator))
|
||||
elif isinstance(coordinator, RoborockWetDryVacUpdateCoordinator):
|
||||
entities.extend(
|
||||
@@ -598,13 +616,14 @@ class RoborockSensorEntity(RoborockCoordinatedEntityV1, SensorEntity):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
unique_id: str,
|
||||
coordinator: RoborockDataUpdateCoordinator,
|
||||
description: RoborockSensorDescription,
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
self.entity_description = description
|
||||
super().__init__(
|
||||
f"{description.key}_{coordinator.duid_slug}",
|
||||
unique_id,
|
||||
coordinator,
|
||||
is_dock_entity=description.is_dock_entity,
|
||||
)
|
||||
|
||||
@@ -49,56 +49,6 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_buttons[button.roborock_s7_2_dock_reset_cleaning_brush_consumable-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'button.roborock_s7_2_dock_reset_cleaning_brush_consumable',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Reset cleaning brush consumable',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Reset cleaning brush consumable',
|
||||
'platform': 'roborock',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'reset_dock_cleaning_brush_consumable',
|
||||
'unique_id': 'reset_dock_cleaning_brush_consumable_device_2',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_buttons[button.roborock_s7_2_dock_reset_cleaning_brush_consumable-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Roborock S7 2 Dock Reset cleaning brush consumable',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.roborock_s7_2_dock_reset_cleaning_brush_consumable',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_buttons[button.roborock_s7_2_dock_reset_strainer_consumable-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
@@ -449,56 +399,6 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_buttons[button.roborock_s7_maxv_dock_reset_cleaning_brush_consumable-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||
'entity_id': 'button.roborock_s7_maxv_dock_reset_cleaning_brush_consumable',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Reset cleaning brush consumable',
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Reset cleaning brush consumable',
|
||||
'platform': 'roborock',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'reset_dock_cleaning_brush_consumable',
|
||||
'unique_id': 'reset_dock_cleaning_brush_consumable_abc123',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_buttons[button.roborock_s7_maxv_dock_reset_cleaning_brush_consumable-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Roborock S7 MaxV Dock Reset cleaning brush consumable',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.roborock_s7_maxv_dock_reset_cleaning_brush_consumable',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_buttons[button.roborock_s7_maxv_dock_reset_strainer_consumable-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
|
||||
@@ -1875,61 +1875,6 @@
|
||||
'state': 'ok',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.roborock_s7_2_dock_maintenance_brush_time_left-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.roborock_s7_2_dock_maintenance_brush_time_left',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Maintenance brush time left',
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Maintenance brush time left',
|
||||
'platform': 'roborock',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'cleaning_brush_time_left',
|
||||
'unique_id': 'cleaning_brush_time_left_device_2',
|
||||
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.roborock_s7_2_dock_maintenance_brush_time_left-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'duration',
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Roborock S7 2 Dock Maintenance brush time left',
|
||||
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: <UnitOfTime.HOURS: 'h'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.roborock_s7_2_dock_maintenance_brush_time_left',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '235',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.roborock_s7_2_dock_mop_drying_remaining_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
@@ -3191,61 +3136,6 @@
|
||||
'state': 'ok',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.roborock_s7_maxv_dock_maintenance_brush_time_left-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
None,
|
||||
]),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.roborock_s7_maxv_dock_maintenance_brush_time_left',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'object_id_base': 'Maintenance brush time left',
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
'suggested_display_precision': 2,
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.DURATION: 'duration'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Maintenance brush time left',
|
||||
'platform': 'roborock',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'cleaning_brush_time_left',
|
||||
'unique_id': 'cleaning_brush_time_left_abc123',
|
||||
'unit_of_measurement': <UnitOfTime.HOURS: 'h'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.roborock_s7_maxv_dock_maintenance_brush_time_left-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
<EntityStateAttribute.DEVICE_CLASS: 'device_class'>: 'duration',
|
||||
<EntityStateAttribute.FRIENDLY_NAME: 'friendly_name'>: 'Roborock S7 MaxV Dock Maintenance brush time left',
|
||||
<EntityStateAttribute.UNIT_OF_MEASUREMENT: 'unit_of_measurement'>: <UnitOfTime.HOURS: 'h'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.roborock_s7_maxv_dock_maintenance_brush_time_left',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '235',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.roborock_s7_maxv_dock_mop_drying_remaining_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': list([
|
||||
|
||||
@@ -4,6 +4,8 @@ from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
from roborock import RoborockException
|
||||
from roborock.data.v1 import RoborockDockTypeCode
|
||||
from roborock.device_features import RoborockDockFeatures
|
||||
from roborock.devices.traits.v1.consumeable import ConsumableAttribute
|
||||
from roborock.exceptions import RoborockTimeout
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
@@ -45,8 +47,11 @@ async def test_buttons(
|
||||
|
||||
@pytest.fixture
|
||||
def non_wash_n_fill_dock(fake_vacuum: FakeDevice) -> None:
|
||||
"""Disable wash towel mode to indicate this device has no wash functions."""
|
||||
"""Disable wash towel mode and cleaning brush to indicate this device has no wash functions."""
|
||||
fake_vacuum.v1_properties.wash_towel_mode = None
|
||||
fake_vacuum.v1_properties.device_features.dock_features = (
|
||||
RoborockDockFeatures.from_dock_type(RoborockDockTypeCode.o1_dock)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
@@ -109,10 +114,6 @@ def consumeables_trait_fixture(fake_vacuum: FakeDevice) -> Mock:
|
||||
"button.roborock_s7_maxv_dock_reset_strainer_consumable",
|
||||
ConsumableAttribute.STRAINER_WORK_TIME,
|
||||
),
|
||||
(
|
||||
"button.roborock_s7_maxv_dock_reset_cleaning_brush_consumable",
|
||||
ConsumableAttribute.CLEANING_BRUSH_WORK_TIME,
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.freeze_time("2023-10-30 08:50:00")
|
||||
@@ -382,4 +383,79 @@ async def test_press_q10_empty_dustbin_button_failure(
|
||||
)
|
||||
|
||||
fake_q10_vacuum.b01_q10_properties.vacuum.empty_dustbin.assert_called_once()
|
||||
|
||||
|
||||
async def test_dock_cleaning_brush_button_not_created_and_cleaned_up(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_roborock_entry: MockConfigEntry,
|
||||
fake_vacuum: FakeDevice,
|
||||
) -> None:
|
||||
"""Test cleaning brush button is not created and removed if it was in the registry."""
|
||||
fake_vacuum.v1_properties.device_features.dock_features = (
|
||||
RoborockDockFeatures.from_dock_type(RoborockDockTypeCode.pearl_dock)
|
||||
)
|
||||
entity_registry.async_get_or_create(
|
||||
domain=Platform.BUTTON,
|
||||
platform=DOMAIN,
|
||||
unique_id="reset_dock_cleaning_brush_consumable_abc123",
|
||||
config_entry=mock_roborock_entry,
|
||||
)
|
||||
assert (
|
||||
entity_registry.async_get_entity_id(
|
||||
Platform.BUTTON, DOMAIN, "reset_dock_cleaning_brush_consumable_abc123"
|
||||
)
|
||||
is not None
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(mock_roborock_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Cleaning brush button must be removed from the entity registry
|
||||
assert (
|
||||
entity_registry.async_get_entity_id(
|
||||
Platform.BUTTON, DOMAIN, "reset_dock_cleaning_brush_consumable_abc123"
|
||||
)
|
||||
is None
|
||||
)
|
||||
assert (
|
||||
hass.states.get("button.roborock_s7_maxv_dock_reset_cleaning_brush_consumable")
|
||||
is None
|
||||
)
|
||||
# Washable dock strainer button must still exist
|
||||
assert (
|
||||
entity_registry.async_get_entity_id(
|
||||
Platform.BUTTON, DOMAIN, "reset_dock_strainer_consumable_abc123"
|
||||
)
|
||||
is not None
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.freeze_time("2023-10-30 08:50:00")
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_dock_cleaning_brush_button_press(
|
||||
hass: HomeAssistant,
|
||||
bypass_api_client_fixture: None,
|
||||
mock_roborock_entry: MockConfigEntry,
|
||||
fake_vacuum: FakeDevice,
|
||||
consumeables_trait: Mock,
|
||||
) -> None:
|
||||
"""Test pressing the cleaning brush button on a dock that supports it."""
|
||||
fake_vacuum.v1_properties.device_features.dock_features = (
|
||||
RoborockDockFeatures.from_dock_type(RoborockDockTypeCode.o3_plus_dock)
|
||||
)
|
||||
await hass.config_entries.async_setup(mock_roborock_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
entity_id = "button.roborock_s7_maxv_dock_reset_cleaning_brush_consumable"
|
||||
assert hass.states.get(entity_id).state == "unknown"
|
||||
await hass.services.async_call(
|
||||
"button",
|
||||
SERVICE_PRESS,
|
||||
blocking=True,
|
||||
target={"entity_id": entity_id},
|
||||
)
|
||||
consumeables_trait.reset_consumable.assert_called_once_with(
|
||||
ConsumableAttribute.CLEANING_BRUSH_WORK_TIME
|
||||
)
|
||||
assert hass.states.get(entity_id).state == "2023-10-30T08:50:00+00:00"
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from roborock.data.v1 import RoborockDockTypeCode
|
||||
from roborock.device_features import RoborockDockFeatures
|
||||
from roborock.exceptions import RoborockException
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.roborock.const import DOMAIN
|
||||
from homeassistant.const import STATE_UNAVAILABLE, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
@@ -90,3 +93,66 @@ async def test_sensors_coordinator_state(
|
||||
state = hass.states.get("sensor.roborock_q10_s5_battery")
|
||||
assert state is not None
|
||||
assert state.state == expected_state
|
||||
|
||||
|
||||
async def test_dock_cleaning_brush_sensor_not_created_and_cleaned_up(
|
||||
hass: HomeAssistant,
|
||||
bypass_api_client_fixture: None,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_roborock_entry: MockConfigEntry,
|
||||
fake_vacuum: FakeDevice,
|
||||
) -> None:
|
||||
"""Test cleaning brush sensor is not created and removed if it was in the registry."""
|
||||
fake_vacuum.v1_properties.device_features.dock_features = (
|
||||
RoborockDockFeatures.from_dock_type(RoborockDockTypeCode.pearl_dock)
|
||||
)
|
||||
entity_registry.async_get_or_create(
|
||||
domain=Platform.SENSOR,
|
||||
platform=DOMAIN,
|
||||
unique_id="cleaning_brush_time_left_abc123",
|
||||
config_entry=mock_roborock_entry,
|
||||
)
|
||||
assert (
|
||||
entity_registry.async_get_entity_id(
|
||||
Platform.SENSOR, DOMAIN, "cleaning_brush_time_left_abc123"
|
||||
)
|
||||
is not None
|
||||
)
|
||||
|
||||
await hass.config_entries.async_setup(mock_roborock_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Cleaning brush sensor must be removed from the entity registry
|
||||
assert (
|
||||
entity_registry.async_get_entity_id(
|
||||
Platform.SENSOR, DOMAIN, "cleaning_brush_time_left_abc123"
|
||||
)
|
||||
is None
|
||||
)
|
||||
assert (
|
||||
hass.states.get("sensor.roborock_s7_maxv_dock_maintenance_brush_time_left")
|
||||
is None
|
||||
)
|
||||
# Washable dock strainer sensor must still exist
|
||||
assert (
|
||||
hass.states.get("sensor.roborock_s7_maxv_dock_strainer_time_left") is not None
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_dock_cleaning_brush_sensor_created_when_supported(
|
||||
hass: HomeAssistant,
|
||||
bypass_api_client_fixture: None,
|
||||
mock_roborock_entry: MockConfigEntry,
|
||||
fake_vacuum: FakeDevice,
|
||||
) -> None:
|
||||
"""Test cleaning brush sensor is created on a dock that supports it."""
|
||||
fake_vacuum.v1_properties.device_features.dock_features = (
|
||||
RoborockDockFeatures.from_dock_type(RoborockDockTypeCode.o3_plus_dock)
|
||||
)
|
||||
await hass.config_entries.async_setup(mock_roborock_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("sensor.roborock_s7_maxv_dock_maintenance_brush_time_left")
|
||||
assert state is not None
|
||||
assert state.state == "235"
|
||||
|
||||
Reference in New Issue
Block a user