1
mirror of https://github.com/home-assistant/core synced 2024-10-07 10:13:38 +02:00

Add Roborock Consumable sensors (#91972)

* add sensors to roborock

* add value_fn typing

* fixed strings

* Update homeassistant/components/roborock/sensor.py

Co-authored-by: Franck Nijhof <frenck@frenck.nl>

* change to work time instead of time left

* added time left back

* fixed tests

* made diagnostic

---------

Co-authored-by: Franck Nijhof <frenck@frenck.nl>
This commit is contained in:
Luke 2023-05-24 14:31:02 -04:00 committed by GitHub
parent e80579e52f
commit 8dd9482bb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 172 additions and 2 deletions

View File

@ -6,4 +6,4 @@ CONF_ENTRY_CODE = "code"
CONF_BASE_URL = "base_url"
CONF_USER_DATA = "user_data"
PLATFORMS = [Platform.VACUUM, Platform.SELECT]
PLATFORMS = [Platform.VACUUM, Platform.SELECT, Platform.SENSOR]

View File

@ -0,0 +1,122 @@
"""Support for Roborock sensors."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from roborock.typing import DeviceProp
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory, UnitOfTime
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.util import slugify
from .const import DOMAIN
from .coordinator import RoborockDataUpdateCoordinator
from .device import RoborockCoordinatedEntity
from .models import RoborockHassDeviceInfo
@dataclass
class RoborockSensorDescriptionMixin:
"""A class that describes sensor entities."""
value_fn: Callable[[DeviceProp], int]
@dataclass
class RoborockSensorDescription(
SensorEntityDescription, RoborockSensorDescriptionMixin
):
"""A class that describes Roborock sensors."""
CONSUMABLE_SENSORS = [
RoborockSensorDescription(
native_unit_of_measurement=UnitOfTime.SECONDS,
key="main_brush_time_left",
icon="mdi:brush",
device_class=SensorDeviceClass.DURATION,
translation_key="main_brush_time_left",
value_fn=lambda data: data.consumable.main_brush_time_left,
entity_category=EntityCategory.DIAGNOSTIC,
),
RoborockSensorDescription(
native_unit_of_measurement=UnitOfTime.SECONDS,
key="side_brush_time_left",
icon="mdi:brush",
device_class=SensorDeviceClass.DURATION,
translation_key="side_brush_time_left",
value_fn=lambda data: data.consumable.side_brush_time_left,
entity_category=EntityCategory.DIAGNOSTIC,
),
RoborockSensorDescription(
native_unit_of_measurement=UnitOfTime.SECONDS,
key="filter_time_left",
icon="mdi:air-filter",
device_class=SensorDeviceClass.DURATION,
translation_key="filter_time_left",
value_fn=lambda data: data.consumable.filter_time_left,
entity_category=EntityCategory.DIAGNOSTIC,
),
RoborockSensorDescription(
native_unit_of_measurement=UnitOfTime.SECONDS,
key="sensor_time_left",
icon="mdi:eye-outline",
device_class=SensorDeviceClass.DURATION,
translation_key="sensor_time_left",
value_fn=lambda data: data.consumable.sensor_time_left,
entity_category=EntityCategory.DIAGNOSTIC,
),
]
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Roborock vacuum sensors."""
coordinator: RoborockDataUpdateCoordinator = hass.data[DOMAIN][
config_entry.entry_id
]
async_add_entities(
RoborockSensorEntity(
f"{description.key}_{slugify(device_id)}",
device_info,
coordinator,
description,
)
for device_id, device_info in coordinator.devices_info.items()
for description in CONSUMABLE_SENSORS
)
class RoborockSensorEntity(RoborockCoordinatedEntity, SensorEntity):
"""Representation of a Roborock sensor."""
entity_description: RoborockSensorDescription
def __init__(
self,
unique_id: str,
device_info: RoborockHassDeviceInfo,
coordinator: RoborockDataUpdateCoordinator,
description: RoborockSensorDescription,
) -> None:
"""Initialize the entity."""
super().__init__(unique_id, device_info, coordinator)
self.entity_description = description
@property
def native_value(self) -> StateType:
"""Return the value reported by the sensor."""
return self.entity_description.value_fn(self.coordinator.data[self._device_id])

View File

@ -27,6 +27,20 @@
}
},
"entity": {
"sensor": {
"main_brush_time_left": {
"name": "Main brush time left"
},
"side_brush_time_left": {
"name": "Side brush time left"
},
"filter_time_left": {
"name": "Filter time left"
},
"sensor_time_left": {
"name": "Sensor time left"
}
},
"select": {
"mop_mode": {
"name": "Mop mode",

View File

@ -53,7 +53,12 @@ async def setup_entry(
with patch(
"homeassistant.components.roborock.RoborockApiClient.get_home_data",
return_value=HOME_DATA,
), patch("homeassistant.components.roborock.RoborockMqttClient.get_networking"):
), patch(
"homeassistant.components.roborock.RoborockMqttClient.get_networking"
), patch(
"homeassistant.components.roborock.coordinator.RoborockLocalClient.get_prop",
return_value=PROP,
):
assert await async_setup_component(hass, DOMAIN, {})
await hass.async_block_till_done()
return mock_roborock_entry

View File

@ -0,0 +1,29 @@
"""Test Roborock Sensors."""
from roborock.const import (
FILTER_REPLACE_TIME,
MAIN_BRUSH_REPLACE_TIME,
SENSOR_DIRTY_REPLACE_TIME,
SIDE_BRUSH_REPLACE_TIME,
)
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry
async def test_sensors(hass: HomeAssistant, setup_entry: MockConfigEntry) -> None:
"""Test sensors and check test values are correctly set."""
assert len(hass.states.async_all("sensor")) == 4
assert hass.states.get("sensor.roborock_s7_maxv_main_brush_time_left").state == str(
MAIN_BRUSH_REPLACE_TIME - 74382
)
assert hass.states.get("sensor.roborock_s7_maxv_side_brush_time_left").state == str(
SIDE_BRUSH_REPLACE_TIME - 74382
)
assert hass.states.get("sensor.roborock_s7_maxv_filter_time_left").state == str(
FILTER_REPLACE_TIME - 74382
)
assert hass.states.get("sensor.roborock_s7_maxv_sensor_time_left").state == str(
SENSOR_DIRTY_REPLACE_TIME - 74382
)