mirror of
https://github.com/home-assistant/core.git
synced 2025-07-30 16:57:19 +00:00
Move battery properties from legacy Ecovacs vacuum entity to separate entities (#149084)
This commit is contained in:
parent
5af4290b77
commit
b1dd742a57
@ -4,10 +4,12 @@ from collections.abc import Callable
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from deebot_client.capabilities import CapabilityEvent
|
from deebot_client.capabilities import CapabilityEvent
|
||||||
from deebot_client.events.base import Event
|
from deebot_client.events import Event
|
||||||
from deebot_client.events.water_info import MopAttachedEvent
|
from deebot_client.events.water_info import MopAttachedEvent
|
||||||
|
from sucks import VacBot
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import (
|
from homeassistant.components.binary_sensor import (
|
||||||
|
BinarySensorDeviceClass,
|
||||||
BinarySensorEntity,
|
BinarySensorEntity,
|
||||||
BinarySensorEntityDescription,
|
BinarySensorEntityDescription,
|
||||||
)
|
)
|
||||||
@ -16,7 +18,11 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||||
|
|
||||||
from . import EcovacsConfigEntry
|
from . import EcovacsConfigEntry
|
||||||
from .entity import EcovacsCapabilityEntityDescription, EcovacsDescriptionEntity
|
from .entity import (
|
||||||
|
EcovacsCapabilityEntityDescription,
|
||||||
|
EcovacsDescriptionEntity,
|
||||||
|
EcovacsLegacyEntity,
|
||||||
|
)
|
||||||
from .util import get_supported_entities
|
from .util import get_supported_entities
|
||||||
|
|
||||||
|
|
||||||
@ -47,12 +53,23 @@ async def async_setup_entry(
|
|||||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Add entities for passed config_entry in HA."""
|
"""Add entities for passed config_entry in HA."""
|
||||||
|
controller = config_entry.runtime_data
|
||||||
|
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
get_supported_entities(
|
get_supported_entities(
|
||||||
config_entry.runtime_data, EcovacsBinarySensor, ENTITY_DESCRIPTIONS
|
config_entry.runtime_data, EcovacsBinarySensor, ENTITY_DESCRIPTIONS
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
legacy_entities = []
|
||||||
|
for device in controller.legacy_devices:
|
||||||
|
if not controller.legacy_entity_is_added(device, "battery_charging"):
|
||||||
|
controller.add_legacy_entity(device, "battery_charging")
|
||||||
|
legacy_entities.append(EcovacsLegacyBatteryChargingSensor(device))
|
||||||
|
|
||||||
|
if legacy_entities:
|
||||||
|
async_add_entities(legacy_entities)
|
||||||
|
|
||||||
|
|
||||||
class EcovacsBinarySensor[EventT: Event](
|
class EcovacsBinarySensor[EventT: Event](
|
||||||
EcovacsDescriptionEntity[CapabilityEvent[EventT]],
|
EcovacsDescriptionEntity[CapabilityEvent[EventT]],
|
||||||
@ -71,3 +88,33 @@ class EcovacsBinarySensor[EventT: Event](
|
|||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
self._subscribe(self._capability.event, on_event)
|
self._subscribe(self._capability.event, on_event)
|
||||||
|
|
||||||
|
|
||||||
|
class EcovacsLegacyBatteryChargingSensor(EcovacsLegacyEntity, BinarySensorEntity):
|
||||||
|
"""Legacy battery charging sensor."""
|
||||||
|
|
||||||
|
_attr_device_class = BinarySensorDeviceClass.BATTERY_CHARGING
|
||||||
|
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
device: VacBot,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the entity."""
|
||||||
|
super().__init__(device)
|
||||||
|
self._attr_unique_id = f"{device.vacuum['did']}_battery_charging"
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""Set up the event listeners now that hass is ready."""
|
||||||
|
self._event_listeners.append(
|
||||||
|
self.device.statusEvents.subscribe(
|
||||||
|
lambda _: self.schedule_update_ha_state()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self) -> bool | None:
|
||||||
|
"""Return true if the binary sensor is on."""
|
||||||
|
if self.device.charge_status is None:
|
||||||
|
return None
|
||||||
|
return bool(self.device.is_charging)
|
||||||
|
@ -37,6 +37,7 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||||
|
from homeassistant.helpers.icon import icon_for_battery_level
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import StateType
|
||||||
|
|
||||||
from . import EcovacsConfigEntry
|
from . import EcovacsConfigEntry
|
||||||
@ -225,7 +226,7 @@ async def async_setup_entry(
|
|||||||
|
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
async def _add_legacy_entities() -> None:
|
async def _add_legacy_lifespan_entities() -> None:
|
||||||
entities = []
|
entities = []
|
||||||
for device in controller.legacy_devices:
|
for device in controller.legacy_devices:
|
||||||
for description in LEGACY_LIFESPAN_SENSORS:
|
for description in LEGACY_LIFESPAN_SENSORS:
|
||||||
@ -242,14 +243,21 @@ async def async_setup_entry(
|
|||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
def _fire_ecovacs_legacy_lifespan_event(_: Any) -> None:
|
def _fire_ecovacs_legacy_lifespan_event(_: Any) -> None:
|
||||||
hass.create_task(_add_legacy_entities())
|
hass.create_task(_add_legacy_lifespan_entities())
|
||||||
|
|
||||||
|
legacy_entities = []
|
||||||
for device in controller.legacy_devices:
|
for device in controller.legacy_devices:
|
||||||
config_entry.async_on_unload(
|
config_entry.async_on_unload(
|
||||||
device.lifespanEvents.subscribe(
|
device.lifespanEvents.subscribe(
|
||||||
_fire_ecovacs_legacy_lifespan_event
|
_fire_ecovacs_legacy_lifespan_event
|
||||||
).unsubscribe
|
).unsubscribe
|
||||||
)
|
)
|
||||||
|
if not controller.legacy_entity_is_added(device, "battery_status"):
|
||||||
|
controller.add_legacy_entity(device, "battery_status")
|
||||||
|
legacy_entities.append(EcovacsLegacyBatterySensor(device))
|
||||||
|
|
||||||
|
if legacy_entities:
|
||||||
|
async_add_entities(legacy_entities)
|
||||||
|
|
||||||
|
|
||||||
class EcovacsSensor(
|
class EcovacsSensor(
|
||||||
@ -344,6 +352,44 @@ class EcovacsErrorSensor(
|
|||||||
self._subscribe(self._capability.event, on_event)
|
self._subscribe(self._capability.event, on_event)
|
||||||
|
|
||||||
|
|
||||||
|
class EcovacsLegacyBatterySensor(EcovacsLegacyEntity, SensorEntity):
|
||||||
|
"""Legacy battery sensor."""
|
||||||
|
|
||||||
|
_attr_native_unit_of_measurement = PERCENTAGE
|
||||||
|
_attr_device_class = SensorDeviceClass.BATTERY
|
||||||
|
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
device: VacBot,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the entity."""
|
||||||
|
super().__init__(device)
|
||||||
|
self._attr_unique_id = f"{device.vacuum['did']}_battery_status"
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""Set up the event listeners now that hass is ready."""
|
||||||
|
self._event_listeners.append(
|
||||||
|
self.device.batteryEvents.subscribe(
|
||||||
|
lambda _: self.schedule_update_ha_state()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_value(self) -> StateType:
|
||||||
|
"""Return the value reported by the sensor."""
|
||||||
|
if (status := self.device.battery_status) is not None:
|
||||||
|
return status * 100 # type: ignore[no-any-return]
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self) -> str | None:
|
||||||
|
"""Return the icon to use in the frontend, if any."""
|
||||||
|
return icon_for_battery_level(
|
||||||
|
battery_level=self.native_value, charging=self.device.is_charging
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class EcovacsLegacyLifespanSensor(EcovacsLegacyEntity, SensorEntity):
|
class EcovacsLegacyLifespanSensor(EcovacsLegacyEntity, SensorEntity):
|
||||||
"""Legacy Lifespan sensor."""
|
"""Legacy Lifespan sensor."""
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ from homeassistant.core import HomeAssistant, SupportsResponse
|
|||||||
from homeassistant.exceptions import ServiceValidationError
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import entity_platform
|
from homeassistant.helpers import entity_platform
|
||||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||||
from homeassistant.helpers.icon import icon_for_battery_level
|
|
||||||
from homeassistant.util import slugify
|
from homeassistant.util import slugify
|
||||||
|
|
||||||
from . import EcovacsConfigEntry
|
from . import EcovacsConfigEntry
|
||||||
@ -71,8 +70,7 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity):
|
|||||||
|
|
||||||
_attr_fan_speed_list = [sucks.FAN_SPEED_NORMAL, sucks.FAN_SPEED_HIGH]
|
_attr_fan_speed_list = [sucks.FAN_SPEED_NORMAL, sucks.FAN_SPEED_HIGH]
|
||||||
_attr_supported_features = (
|
_attr_supported_features = (
|
||||||
VacuumEntityFeature.BATTERY
|
VacuumEntityFeature.RETURN_HOME
|
||||||
| VacuumEntityFeature.RETURN_HOME
|
|
||||||
| VacuumEntityFeature.CLEAN_SPOT
|
| VacuumEntityFeature.CLEAN_SPOT
|
||||||
| VacuumEntityFeature.STOP
|
| VacuumEntityFeature.STOP
|
||||||
| VacuumEntityFeature.START
|
| VacuumEntityFeature.START
|
||||||
@ -89,11 +87,6 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity):
|
|||||||
lambda _: self.schedule_update_ha_state()
|
lambda _: self.schedule_update_ha_state()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self._event_listeners.append(
|
|
||||||
self.device.batteryEvents.subscribe(
|
|
||||||
lambda _: self.schedule_update_ha_state()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
self._event_listeners.append(
|
self._event_listeners.append(
|
||||||
self.device.lifespanEvents.subscribe(
|
self.device.lifespanEvents.subscribe(
|
||||||
lambda _: self.schedule_update_ha_state()
|
lambda _: self.schedule_update_ha_state()
|
||||||
@ -137,21 +130,6 @@ class EcovacsLegacyVacuum(EcovacsLegacyEntity, StateVacuumEntity):
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
|
||||||
def battery_level(self) -> int | None:
|
|
||||||
"""Return the battery level of the vacuum cleaner."""
|
|
||||||
if self.device.battery_status is not None:
|
|
||||||
return self.device.battery_status * 100 # type: ignore[no-any-return]
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
|
||||||
def battery_icon(self) -> str:
|
|
||||||
"""Return the battery icon for the vacuum cleaner."""
|
|
||||||
return icon_for_battery_level(
|
|
||||||
battery_level=self.battery_level, charging=self.device.is_charging
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fan_speed(self) -> str | None:
|
def fan_speed(self) -> str | None:
|
||||||
"""Return the fan speed of the vacuum cleaner."""
|
"""Return the fan speed of the vacuum cleaner."""
|
||||||
|
@ -1,4 +1,55 @@
|
|||||||
# serializer version: 1
|
# serializer version: 1
|
||||||
|
# name: test_legacy_sensors[123][sensor.e1234567890000000003_battery:entity-registry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'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.e1234567890000000003_battery',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.BATTERY: 'battery'>,
|
||||||
|
'original_icon': 'mdi:battery-unknown',
|
||||||
|
'original_name': 'Battery',
|
||||||
|
'platform': 'ecovacs',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'suggested_object_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': None,
|
||||||
|
'unique_id': 'E1234567890000000003_battery_status',
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_legacy_sensors[123][sensor.e1234567890000000003_battery:state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'battery',
|
||||||
|
'friendly_name': 'E1234567890000000003 Battery',
|
||||||
|
'icon': 'mdi:battery-unknown',
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.e1234567890000000003_battery',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'unavailable',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_legacy_sensors[123][sensor.e1234567890000000003_filter_lifespan:entity-registry]
|
# name: test_legacy_sensors[123][sensor.e1234567890000000003_filter_lifespan:entity-registry]
|
||||||
EntityRegistryEntrySnapshot({
|
EntityRegistryEntrySnapshot({
|
||||||
'aliases': set({
|
'aliases': set({
|
||||||
@ -148,6 +199,7 @@
|
|||||||
# ---
|
# ---
|
||||||
# name: test_legacy_sensors[123][states]
|
# name: test_legacy_sensors[123][states]
|
||||||
list([
|
list([
|
||||||
|
'sensor.e1234567890000000003_battery',
|
||||||
'sensor.e1234567890000000003_main_brush_lifespan',
|
'sensor.e1234567890000000003_main_brush_lifespan',
|
||||||
'sensor.e1234567890000000003_side_brush_lifespan',
|
'sensor.e1234567890000000003_side_brush_lifespan',
|
||||||
'sensor.e1234567890000000003_filter_lifespan',
|
'sensor.e1234567890000000003_filter_lifespan',
|
||||||
|
@ -107,7 +107,7 @@ async def test_devices_in_dr(
|
|||||||
[
|
[
|
||||||
("yna5x1", 26),
|
("yna5x1", 26),
|
||||||
("5xu9h3", 25),
|
("5xu9h3", 25),
|
||||||
("123", 1),
|
("123", 2),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_all_entities_loaded(
|
async def test_all_entities_loaded(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user