Use translations for fan_speed in tplink vacuum entity (#136718)

This commit is contained in:
Steven B. 2025-01-29 09:55:19 +00:00 committed by GitHub
parent 60b6a11d4e
commit 6b4ec3f3f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 53 additions and 21 deletions

View File

@ -110,6 +110,9 @@ class TPLinkModuleEntityDescription(TPLinkEntityDescription):
unique_id_fn: Callable[[Device, TPLinkModuleEntityDescription], str] = (
lambda device, desc: f"{legacy_device_id(device)}-{desc.key}"
)
entity_name_fn: (
Callable[[Device, TPLinkModuleEntityDescription], str | None] | None
) = None
def async_refresh_after[_T: CoordinatedTPLinkEntity, **_P](
@ -550,7 +553,9 @@ class CoordinatedTPLinkModuleEntity(CoordinatedTPLinkEntity, ABC):
# the description should have a translation key.
# HA logic is to name entities based on the following logic:
# _attr_name > translation.name > description.name
if not description.translation_key:
if entity_name_fn := description.entity_name_fn:
self._attr_name = entity_name_fn(device, description)
elif not description.translation_key:
if parent is None or parent.device_type is Device.Type.Hub:
self._attr_name = None
else:

View File

@ -283,6 +283,21 @@
"clean_count": {
"name": "Clean count"
}
},
"vacuum": {
"vacuum": {
"state_attributes": {
"fan_speed": {
"state": {
"quiet": "Quiet",
"standard": "Standard",
"turbo": "Turbo",
"max": "Max",
"ultra": "Ultra"
}
}
}
}
}
},
"device": {

View File

@ -3,9 +3,9 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, cast
from typing import Any
from kasa import Device, Feature, Module
from kasa import Device, Module
from kasa.smart.modules.clean import Clean, Status
from homeassistant.components.vacuum import (
@ -52,7 +52,10 @@ class TPLinkVacuumEntityDescription(
VACUUM_DESCRIPTIONS: tuple[TPLinkVacuumEntityDescription, ...] = (
TPLinkVacuumEntityDescription(
key="vacuum", exists_fn=lambda dev, _: Module.Clean in dev.modules
key="vacuum",
translation_key="vacuum",
exists_fn=lambda dev, _: Module.Clean in dev.modules,
entity_name_fn=lambda _, __: None,
),
)
@ -97,7 +100,6 @@ class TPLinkVacuumEntity(CoordinatedTPLinkModuleEntity, StateVacuumEntity):
| VacuumEntityFeature.START
| VacuumEntityFeature.PAUSE
| VacuumEntityFeature.RETURN_HOME
| VacuumEntityFeature.FAN_SPEED
)
entity_description: TPLinkVacuumEntityDescription
@ -117,8 +119,11 @@ class TPLinkVacuumEntity(CoordinatedTPLinkModuleEntity, StateVacuumEntity):
self._speaker_module = speaker
self._attr_supported_features |= VacuumEntityFeature.LOCATE
# Needs to be initialized empty, as vacuumentity's capability_attributes accesses it
self._attr_fan_speed_list: list[str] = []
if (
fanspeed_feat := self._vacuum_module.get_feature("fan_speed_preset")
) and fanspeed_feat.choices:
self._attr_supported_features |= VacuumEntityFeature.FAN_SPEED
self._attr_fan_speed_list = [c.lower() for c in fanspeed_feat.choices]
@async_refresh_after
async def async_start(self) -> None:
@ -138,7 +143,7 @@ class TPLinkVacuumEntity(CoordinatedTPLinkModuleEntity, StateVacuumEntity):
@async_refresh_after
async def async_set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None:
"""Set fan speed."""
await self._vacuum_module.set_fan_speed_preset(fan_speed)
await self._vacuum_module.set_fan_speed_preset(fan_speed.capitalize())
async def async_locate(self, **kwargs: Any) -> None:
"""Locate the device."""
@ -152,7 +157,6 @@ class TPLinkVacuumEntity(CoordinatedTPLinkModuleEntity, StateVacuumEntity):
def _async_update_attrs(self) -> bool:
"""Update the entity's attributes."""
self._attr_activity = STATUS_TO_ACTIVITY.get(self._vacuum_module.status)
fanspeeds = cast(Feature, self._vacuum_module.get_feature("fan_speed_preset"))
self._attr_fan_speed_list = cast(list[str], fanspeeds.choices)
self._attr_fan_speed = self._vacuum_module.fan_speed_preset
if self._vacuum_module.has_feature("fan_speed_preset"):
self._attr_fan_speed = self._vacuum_module.fan_speed_preset.lower()
return True

View File

@ -106,7 +106,7 @@ async def snapshot_platform(
if entity_entry.translation_key:
key = f"component.{DOMAIN}.entity.{entity_entry.domain}.{entity_entry.translation_key}.name"
single_device_class_translation = False
if key not in translations and entity_entry.original_device_class:
if key not in translations: # No name translation
if entity_entry.original_device_class not in unique_device_classes:
single_device_class_translation = True
unique_device_classes.append(entity_entry.original_device_class)

View File

@ -42,8 +42,8 @@
'area_id': None,
'capabilities': dict({
'fan_speed_list': list([
'Quiet',
'Max',
'quiet',
'max',
]),
}),
'config_entry_id': <ANY>,
@ -68,7 +68,7 @@
'platform': 'tplink',
'previous_unique_id': None,
'supported_features': <VacuumEntityFeature: 12916>,
'translation_key': None,
'translation_key': 'vacuum',
'unique_id': '123456789ABCDEFGH-vacuum',
'unit_of_measurement': None,
})
@ -78,10 +78,10 @@
'attributes': ReadOnlyDict({
'battery_icon': 'mdi:battery-charging-100',
'battery_level': 100,
'fan_speed': 'Max',
'fan_speed': 'max',
'fan_speed_list': list([
'Quiet',
'Max',
'quiet',
'max',
]),
'friendly_name': 'my_vacuum',
'supported_features': <VacuumEntityFeature: 12916>,

View File

@ -19,7 +19,11 @@ from homeassistant.components.vacuum import (
)
from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers import (
device_registry as dr,
entity_registry as er,
translation,
)
from . import DEVICE_ID, _mocked_device, setup_platform_for_device, snapshot_platform
@ -59,8 +63,12 @@ async def test_vacuum(
state = hass.states.get(ENTITY_ID)
assert state.state == VacuumActivity.DOCKED
assert state.attributes[ATTR_FAN_SPEED] == "Max"
assert state.attributes[ATTR_FAN_SPEED] == "max"
assert state.attributes[ATTR_BATTERY_LEVEL] == 100
result = translation.async_translate_state(
hass, "max", "vacuum", "tplink", "vacuum.state_attributes.fan_speed", None
)
assert result == "Max"
async def test_states(
@ -90,7 +98,7 @@ async def test_states(
SERVICE_SET_FAN_SPEED,
Module.Clean,
"set_fan_speed_preset",
{ATTR_FAN_SPEED: "Quiet"},
{ATTR_FAN_SPEED: "quiet"},
),
(SERVICE_LOCATE, Module.Speaker, "locate", {}),
],