Skip to content

Commit

Permalink
Use translations for fan_speed in tplink vacuum entity (#136718)
Browse files Browse the repository at this point in the history
  • Loading branch information
sdb9696 authored Jan 29, 2025
1 parent 60b6a11 commit 6b4ec3f
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 21 deletions.
7 changes: 6 additions & 1 deletion homeassistant/components/tplink/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -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](
Expand Down Expand Up @@ -550,7 +553,9 @@ def __init__(
# 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:
Expand Down
15 changes: 15 additions & 0 deletions homeassistant/components/tplink/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
24 changes: 14 additions & 10 deletions homeassistant/components/tplink/vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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,
),
)

Expand Down Expand Up @@ -97,7 +100,6 @@ class TPLinkVacuumEntity(CoordinatedTPLinkModuleEntity, StateVacuumEntity):
| VacuumEntityFeature.START
| VacuumEntityFeature.PAUSE
| VacuumEntityFeature.RETURN_HOME
| VacuumEntityFeature.FAN_SPEED
)

entity_description: TPLinkVacuumEntityDescription
Expand All @@ -117,8 +119,11 @@ def __init__(
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:
Expand All @@ -138,7 +143,7 @@ async def async_return_to_base(self, **kwargs: Any) -> None:
@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."""
Expand All @@ -152,7 +157,6 @@ def battery_level(self) -> int | None:
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
2 changes: 1 addition & 1 deletion tests/components/tplink/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 6 additions & 6 deletions tests/components/tplink/snapshots/test_vacuum.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
'area_id': None,
'capabilities': dict({
'fan_speed_list': list([
'Quiet',
'Max',
'quiet',
'max',
]),
}),
'config_entry_id': <ANY>,
Expand All @@ -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,
})
Expand All @@ -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>,
Expand Down
14 changes: 11 additions & 3 deletions tests/components/tplink/test_vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@
)
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

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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", {}),
],
Expand Down

0 comments on commit 6b4ec3f

Please sign in to comment.