341 lines
14 KiB
Python
341 lines
14 KiB
Python
"""Support for Dreame Vacuum sensors."""
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from datetime import datetime
|
|
|
|
from homeassistant.components.sensor import (
|
|
SensorDeviceClass,
|
|
SensorEntity,
|
|
SensorEntityDescription,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntry
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity import EntityCategory
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
|
|
from .const import DOMAIN, UNIT_MINUTES, UNIT_HOURS, UNIT_PERCENT, UNIT_AREA, UNIT_TIMES, UNIT_DAYS
|
|
from .dreame import (
|
|
DreameVacuumProperty,
|
|
DreameVacuumRelocationStatus,
|
|
)
|
|
|
|
from .coordinator import DreameVacuumDataUpdateCoordinator
|
|
from .entity import DreameVacuumEntity, DreameVacuumEntityDescription
|
|
|
|
|
|
@dataclass
|
|
class DreameVacuumSensorEntityDescription(
|
|
DreameVacuumEntityDescription, SensorEntityDescription
|
|
):
|
|
"""Describes DreameVacuum sensor entity."""
|
|
|
|
|
|
SENSORS: tuple[DreameVacuumSensorEntityDescription, ...] = (
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.CLEANING_TIME,
|
|
icon="mdi:timer-sand",
|
|
native_unit_of_measurement=UNIT_MINUTES,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.CLEANING_TIME,
|
|
name="Mapping Time",
|
|
key="mapping_time",
|
|
icon="mdi:map-clock",
|
|
native_unit_of_measurement=UNIT_MINUTES,
|
|
available_fn=lambda device: device.status.fast_mapping,
|
|
exists_fn=lambda description, device: device.status.lidar_navigation,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.CLEANED_AREA,
|
|
icon="mdi:ruler-square",
|
|
native_unit_of_measurement=UNIT_AREA,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.STATE,
|
|
device_class=f"{DOMAIN}__state",
|
|
icon="mdi:robot-vacuum",
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.STATUS,
|
|
device_class=f"{DOMAIN}__status",
|
|
icon="mdi:vacuum",
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.RELOCATION_STATUS,
|
|
device_class=f"{DOMAIN}__relocation_status",
|
|
icon_fn=lambda value, device: "mdi:map-marker-distance"
|
|
if device.status.relocation_status is DreameVacuumRelocationStatus.LOCATING
|
|
else "mdi:map-marker-alert"
|
|
if device.status.relocation_status is DreameVacuumRelocationStatus.FAILED
|
|
else "mdi:map-marker-check"
|
|
if device.status.relocation_status is DreameVacuumRelocationStatus.SUCCESS
|
|
else "mdi:map-marker-radius",
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.TASK_STATUS,
|
|
device_class=f"{DOMAIN}__task_status",
|
|
icon="mdi:file-tree",
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.WATER_TANK,
|
|
device_class=f"{DOMAIN}__water_tank_and_mop",
|
|
icon_fn=lambda value, device: "mdi:water-pump-off"
|
|
if not device.status.water_tank_or_mop_installed
|
|
else "mdi:water-pump",
|
|
exists_fn=lambda description, device: not device.status.self_wash_base_available and DreameVacuumEntityDescription().exists_fn(description, device),
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
key="mop_pad",
|
|
device_class=f"{DOMAIN}__water_tank_and_mop",
|
|
icon="mdi:google-circles-communities",
|
|
value_fn=lambda value, device: device.status.water_tank_name,
|
|
exists_fn=lambda description, device: device.status.self_wash_base_available,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.DUST_COLLECTION,
|
|
device_class=f"{DOMAIN}__dust_collection",
|
|
icon_fn=lambda value, device: "mdi:delete-off"
|
|
if not device.status.dust_collection
|
|
else "mdi:delete-sweep",
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.AUTO_EMPTY_STATUS,
|
|
device_class=f"{DOMAIN}__auto_empty_status",
|
|
icon_fn=lambda value, device: "mdi:delete-clock"
|
|
if device.status.auto_emptying_not_performed
|
|
else "mdi:delete-restore"
|
|
if device.status.auto_emptying
|
|
else "mdi:delete",
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.SELF_WASH_BASE_STATUS,
|
|
device_class=f"{DOMAIN}__self_wash_base_status",
|
|
icon="mdi:dishwasher",
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.ERROR,
|
|
device_class=f"{DOMAIN}__error",
|
|
icon_fn=lambda value, device: "mdi:alert-circle-outline"
|
|
if device.status.has_error
|
|
else "mdi:alert-outline"
|
|
if device.status.has_warning
|
|
else "mdi:check-circle-outline",
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.CHARGING_STATUS,
|
|
device_class=f"{DOMAIN}__charging_status",
|
|
icon="mdi:home-lightning-bolt",
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.BATTERY_LEVEL,
|
|
device_class=SensorDeviceClass.BATTERY,
|
|
native_unit_of_measurement=UNIT_PERCENT,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.MAIN_BRUSH_LEFT,
|
|
icon="mdi:car-turbocharger",
|
|
native_unit_of_measurement=UNIT_PERCENT,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.MAIN_BRUSH_TIME_LEFT,
|
|
icon="mdi:car-turbocharger",
|
|
native_unit_of_measurement=UNIT_HOURS,
|
|
#device_class=SensorDeviceClass.DURATION,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.SIDE_BRUSH_LEFT,
|
|
icon="mdi:pinwheel-outline",
|
|
native_unit_of_measurement=UNIT_PERCENT,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.SIDE_BRUSH_TIME_LEFT,
|
|
icon="mdi:pinwheel-outline",
|
|
native_unit_of_measurement=UNIT_HOURS,
|
|
#device_class=SensorDeviceClass.DURATION,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.FILTER_LEFT,
|
|
icon="mdi:air-filter",
|
|
native_unit_of_measurement=UNIT_PERCENT,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.FILTER_TIME_LEFT,
|
|
icon="mdi:air-filter",
|
|
native_unit_of_measurement=UNIT_HOURS,
|
|
#device_class=SensorDeviceClass.DURATION,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.SENSOR_DIRTY_LEFT,
|
|
icon="mdi:radar",
|
|
native_unit_of_measurement=UNIT_PERCENT,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.SENSOR_DIRTY_TIME_LEFT,
|
|
icon="mdi:radar",
|
|
native_unit_of_measurement=UNIT_HOURS,
|
|
#device_class=SensorDeviceClass.DURATION,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.SECONDARY_FILTER_LEFT,
|
|
icon="mdi:air-filter",
|
|
native_unit_of_measurement=UNIT_PERCENT,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.SECONDARY_FILTER_TIME_LEFT,
|
|
icon="mdi:air-filter",
|
|
native_unit_of_measurement=UNIT_HOURS,
|
|
#device_class=SensorDeviceClass.DURATION,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.MOP_PAD_LEFT,
|
|
icon="mdi:hydro-power",
|
|
native_unit_of_measurement=UNIT_PERCENT,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.MOP_PAD_TIME_LEFT,
|
|
icon="mdi:hydro-power",
|
|
native_unit_of_measurement=UNIT_HOURS,
|
|
#device_class=SensorDeviceClass.DURATION,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.SILVER_ION_LEFT,
|
|
icon="mdi:shimmer",
|
|
native_unit_of_measurement=UNIT_PERCENT,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.SILVER_ION_TIME_LEFT,
|
|
icon="mdi:shimmer",
|
|
native_unit_of_measurement=UNIT_DAYS,
|
|
#device_class=SensorDeviceClass.DURATION,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.DETERGENT_LEFT,
|
|
icon="mdi:water-opacity",
|
|
native_unit_of_measurement=UNIT_PERCENT,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.DETERGENT_TIME_LEFT,
|
|
icon="mdi:water-opacity",
|
|
native_unit_of_measurement=UNIT_DAYS,
|
|
#device_class=SensorDeviceClass.DURATION,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.FIRST_CLEANING_DATE,
|
|
icon="mdi:calendar-start",
|
|
device_class=SensorDeviceClass.TIMESTAMP,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
value_fn=lambda value, device: datetime.fromtimestamp(value).replace(tzinfo=datetime.now().astimezone().tzinfo),
|
|
entity_registry_enabled_default=False,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.TOTAL_CLEANING_TIME,
|
|
icon="mdi:timer-outline",
|
|
native_unit_of_measurement=UNIT_MINUTES,
|
|
device_class=SensorDeviceClass.DURATION,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.CLEANING_COUNT,
|
|
icon="mdi:counter",
|
|
native_unit_of_measurement=UNIT_TIMES,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
property_key=DreameVacuumProperty.TOTAL_CLEANED_AREA,
|
|
icon="mdi:set-square",
|
|
native_unit_of_measurement=UNIT_AREA,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
name="Current Room",
|
|
key="current_room",
|
|
icon="mdi:home-map-marker",
|
|
value_fn=lambda value, device: device.status.current_room.name,
|
|
exists_fn=lambda description, device: device.status.map_available and device.status.lidar_navigation,
|
|
available_fn=lambda device: bool(
|
|
device.status.current_room is not None and not device.status.fast_mapping
|
|
),
|
|
attrs_fn=lambda device: {
|
|
"room_id": device.status.current_room.segment_id,
|
|
"room_icon": device.status.current_room.icon,
|
|
},
|
|
),
|
|
DreameVacuumSensorEntityDescription(
|
|
name="Cleaning History",
|
|
key="cleaning_history",
|
|
icon="mdi:clipboard-text-clock",
|
|
device_class=SensorDeviceClass.TIMESTAMP,
|
|
value_fn=lambda value, device: device.status.last_cleaning_time,
|
|
exists_fn=lambda description, device: device.status.map_available,
|
|
available_fn=lambda device: bool(device.status.last_cleaning_time is not None),
|
|
attrs_fn=lambda device: device.status.cleaning_history,
|
|
entity_category=EntityCategory.DIAGNOSTIC,
|
|
),
|
|
)
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: ConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Set up Dreame Vacuum sensor based on a config entry."""
|
|
coordinator: DreameVacuumDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
|
async_add_entities(
|
|
DreameVacuumSensorEntity(coordinator, description)
|
|
for description in SENSORS
|
|
if description.exists_fn(description, coordinator.device)
|
|
)
|
|
|
|
|
|
class DreameVacuumSensorEntity(DreameVacuumEntity, SensorEntity):
|
|
"""Defines a Dreame Vacuum sensor entity."""
|
|
|
|
def __init__(
|
|
self,
|
|
coordinator: DreameVacuumDataUpdateCoordinator,
|
|
description: DreameVacuumSensorEntityDescription,
|
|
) -> None:
|
|
"""Initialize a Dreame Vacuum sensor entity."""
|
|
super().__init__(coordinator, description)
|
|
|
|
if description.property_key is not None and description.value_fn is None:
|
|
prop = f'{description.property_key.name.lower()}_name'
|
|
if hasattr(coordinator.device.status, prop):
|
|
description.value_fn = lambda value, device: getattr(
|
|
device.status, prop)
|