Add entity translations to hunterdouglas powerview (#98232)

This commit is contained in:
Joost Lekkerkerker 2023-08-14 22:26:20 +02:00 committed by GitHub
parent 9713466817
commit 49a9d0e439
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 43 deletions

View file

@ -7,7 +7,11 @@ from typing import Any, Final
from aiopvapi.resources.shade import BaseShade, factory as PvShade
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.components.button import (
ButtonDeviceClass,
ButtonEntity,
ButtonEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
@ -36,21 +40,20 @@ class PowerviewButtonDescription(
BUTTONS: Final = [
PowerviewButtonDescription(
key="calibrate",
name="Calibrate",
translation_key="calibrate",
icon="mdi:swap-vertical-circle-outline",
entity_category=EntityCategory.DIAGNOSTIC,
press_action=lambda shade: shade.calibrate(),
),
PowerviewButtonDescription(
key="identify",
name="Identify",
icon="mdi:crosshairs-question",
device_class=ButtonDeviceClass.IDENTIFY,
entity_category=EntityCategory.DIAGNOSTIC,
press_action=lambda shade: shade.jog(),
),
PowerviewButtonDescription(
key="favorite",
name="Favorite",
translation_key="favorite",
icon="mdi:heart",
entity_category=EntityCategory.DIAGNOSTIC,
press_action=lambda shade: shade.favorite(),
@ -104,7 +107,6 @@ class PowerviewButton(ShadeEntity, ButtonEntity):
"""Initialize the button entity."""
super().__init__(coordinator, device_info, room_name, shade, name)
self.entity_description: PowerviewButtonDescription = description
self._attr_name = f"{self._shade_name} {description.name}"
self._attr_unique_id = f"{self._attr_unique_id}_{description.key}"
async def async_press(self) -> None:

View file

@ -118,7 +118,11 @@ class PowerViewShadeBase(ShadeEntity, CoverEntity):
"""Representation of a powerview shade."""
_attr_device_class = CoverDeviceClass.SHADE
_attr_supported_features = CoverEntityFeature(0)
_attr_supported_features = (
CoverEntityFeature.OPEN
| CoverEntityFeature.CLOSE
| CoverEntityFeature.SET_POSITION
)
def __init__(
self,
@ -131,7 +135,6 @@ class PowerViewShadeBase(ShadeEntity, CoverEntity):
"""Initialize the shade."""
super().__init__(coordinator, device_info, room_name, shade, name)
self._shade: BaseShade = shade
self._attr_name = self._shade_name
self._scheduled_transition_update: CALLBACK_TYPE | None = None
if self._device_info.model != LEGACY_DEVICE_MODEL:
self._attr_supported_features |= CoverEntityFeature.STOP
@ -346,26 +349,14 @@ class PowerViewShadeBase(ShadeEntity, CoverEntity):
class PowerViewShade(PowerViewShadeBase):
"""Represent a standard shade."""
def __init__(
self,
coordinator: PowerviewShadeUpdateCoordinator,
device_info: PowerviewDeviceInfo,
room_name: str,
shade: BaseShade,
name: str,
) -> None:
"""Initialize the shade."""
super().__init__(coordinator, device_info, room_name, shade, name)
self._attr_supported_features |= (
CoverEntityFeature.OPEN
| CoverEntityFeature.CLOSE
| CoverEntityFeature.SET_POSITION
)
_attr_name = None
class PowerViewShadeWithTiltBase(PowerViewShade):
class PowerViewShadeWithTiltBase(PowerViewShadeBase):
"""Representation for PowerView shades with tilt capabilities."""
_attr_name = None
def __init__(
self,
coordinator: PowerviewShadeUpdateCoordinator,
@ -453,9 +444,11 @@ class PowerViewShadeWithTiltOnClosed(PowerViewShadeWithTiltBase):
API Class: ShadeBottomUpTiltOnClosed + ShadeBottomUpTiltOnClosed90
Type 1 - Bottom Up w/ 90° Tilt
Shade 44 - a shade thought to have been a firmware issue (type 0 usually dont tilt)
Shade 44 - a shade thought to have been a firmware issue (type 0 usually don't tilt)
"""
_attr_name = None
@property
def open_position(self) -> PowerviewShadeMove:
"""Return the open position and required additional positions."""
@ -570,7 +563,7 @@ class PowerViewShadeTiltOnly(PowerViewShadeWithTiltBase):
self._max_tilt = self._shade.shade_limits.tilt_max
class PowerViewShadeTopDown(PowerViewShade):
class PowerViewShadeTopDown(PowerViewShadeBase):
"""Representation of a shade that lowers from the roof to the floor.
These shades are inverted where MAX_POSITION equates to closed and MIN_POSITION is open
@ -579,6 +572,8 @@ class PowerViewShadeTopDown(PowerViewShade):
Type 6 - Top Down
"""
_attr_name = None
@property
def current_cover_position(self) -> int:
"""Return the current position of cover."""
@ -594,7 +589,7 @@ class PowerViewShadeTopDown(PowerViewShade):
await self._async_set_cover_position(100 - kwargs[ATTR_POSITION])
class PowerViewShadeDualRailBase(PowerViewShade):
class PowerViewShadeDualRailBase(PowerViewShadeBase):
"""Representation of a shade with top/down bottom/up capabilities.
Base methods shared between the two shades created
@ -613,11 +608,13 @@ class PowerViewShadeDualRailBase(PowerViewShade):
class PowerViewShadeTDBUBottom(PowerViewShadeDualRailBase):
"""Representation of the bottom PowerViewShadeDualRailBase shade.
These shades have top/down bottom up functionality and two entiites.
These shades have top/down bottom up functionality and two entities.
Sibling Class: PowerViewShadeTDBUTop
API Class: ShadeTopDownBottomUp
"""
_attr_translation_key = "bottom"
def __init__(
self,
coordinator: PowerviewShadeUpdateCoordinator,
@ -629,7 +626,6 @@ class PowerViewShadeTDBUBottom(PowerViewShadeDualRailBase):
"""Initialize the shade."""
super().__init__(coordinator, device_info, room_name, shade, name)
self._attr_unique_id = f"{self._shade.id}_bottom"
self._attr_name = f"{self._shade_name} Bottom"
@callback
def _clamp_cover_limit(self, target_hass_position: int) -> int:
@ -655,11 +651,13 @@ class PowerViewShadeTDBUBottom(PowerViewShadeDualRailBase):
class PowerViewShadeTDBUTop(PowerViewShadeDualRailBase):
"""Representation of the top PowerViewShadeDualRailBase shade.
These shades have top/down bottom up functionality and two entiites.
These shades have top/down bottom up functionality and two entities.
Sibling Class: PowerViewShadeTDBUBottom
API Class: ShadeTopDownBottomUp
"""
_attr_translation_key = "top"
def __init__(
self,
coordinator: PowerviewShadeUpdateCoordinator,
@ -671,7 +669,6 @@ class PowerViewShadeTDBUTop(PowerViewShadeDualRailBase):
"""Initialize the shade."""
super().__init__(coordinator, device_info, room_name, shade, name)
self._attr_unique_id = f"{self._shade.id}_top"
self._attr_name = f"{self._shade_name} Top"
@property
def should_poll(self) -> bool:
@ -711,7 +708,7 @@ class PowerViewShadeTDBUTop(PowerViewShadeDualRailBase):
@callback
def _clamp_cover_limit(self, target_hass_position: int) -> int:
"""Dont allow a cover to go into an impossbile position."""
"""Don't allow a cover to go into an impossbile position."""
cover_bottom = hd_position_to_hass(self.positions.primary, MAX_POSITION)
return min(target_hass_position, (100 - cover_bottom))
@ -730,7 +727,7 @@ class PowerViewShadeTDBUTop(PowerViewShadeDualRailBase):
)
class PowerViewShadeDualOverlappedBase(PowerViewShade):
class PowerViewShadeDualOverlappedBase(PowerViewShadeBase):
"""Represent a shade that has a front sheer and rear opaque panel.
This equates to two shades being controlled by one motor
@ -783,6 +780,8 @@ class PowerViewShadeDualOverlappedCombined(PowerViewShadeDualOverlappedBase):
Type 8 - Duolite (front and rear shades)
"""
_attr_translation_key = "combined"
# type
def __init__(
self,
@ -795,7 +794,6 @@ class PowerViewShadeDualOverlappedCombined(PowerViewShadeDualOverlappedBase):
"""Initialize the shade."""
super().__init__(coordinator, device_info, room_name, shade, name)
self._attr_unique_id = f"{self._shade.id}_combined"
self._attr_name = f"{self._shade_name} Combined"
@property
def is_closed(self) -> bool:
@ -842,7 +840,7 @@ class PowerViewShadeDualOverlappedCombined(PowerViewShadeDualOverlappedBase):
class PowerViewShadeDualOverlappedFront(PowerViewShadeDualOverlappedBase):
"""Represent the shade front panel - These have a opaque panel too.
"""Represent the shade front panel - These have an opaque panel too.
This equates to two shades being controlled by one motor.
The front shade must be completely down before the rear shade will move.
@ -857,6 +855,8 @@ class PowerViewShadeDualOverlappedFront(PowerViewShadeDualOverlappedBase):
Type 10 - Duolite with 180° Tilt
"""
_attr_translation_key = "front"
def __init__(
self,
coordinator: PowerviewShadeUpdateCoordinator,
@ -868,7 +868,6 @@ class PowerViewShadeDualOverlappedFront(PowerViewShadeDualOverlappedBase):
"""Initialize the shade."""
super().__init__(coordinator, device_info, room_name, shade, name)
self._attr_unique_id = f"{self._shade.id}_front"
self._attr_name = f"{self._shade_name} Front"
@property
def should_poll(self) -> bool:
@ -906,7 +905,7 @@ class PowerViewShadeDualOverlappedFront(PowerViewShadeDualOverlappedBase):
class PowerViewShadeDualOverlappedRear(PowerViewShadeDualOverlappedBase):
"""Represent the shade front panel - These have a opaque panel too.
"""Represent the shade front panel - These have an opaque panel too.
This equates to two shades being controlled by one motor.
The front shade must be completely down before the rear shade will move.
@ -921,6 +920,8 @@ class PowerViewShadeDualOverlappedRear(PowerViewShadeDualOverlappedBase):
Type 10 - Duolite with 180° Tilt
"""
_attr_translation_key = "rear"
def __init__(
self,
coordinator: PowerviewShadeUpdateCoordinator,
@ -932,7 +933,6 @@ class PowerViewShadeDualOverlappedRear(PowerViewShadeDualOverlappedBase):
"""Initialize the shade."""
super().__init__(coordinator, device_info, room_name, shade, name)
self._attr_unique_id = f"{self._shade.id}_rear"
self._attr_name = f"{self._shade_name} Rear"
@property
def should_poll(self) -> bool:

View file

@ -25,6 +25,8 @@ from .shade_data import PowerviewShadeData, PowerviewShadePositions
class HDEntity(CoordinatorEntity[PowerviewShadeUpdateCoordinator]):
"""Base class for hunter douglas entities."""
_attr_has_entity_name = True
def __init__(
self,
coordinator: PowerviewShadeUpdateCoordinator,

View file

@ -47,7 +47,7 @@ class PowerviewSelectDescription(
DROPDOWNS: Final = [
PowerviewSelectDescription(
key="powersource",
name="Power Source",
translation_key="power_source",
icon="mdi:power-plug-outline",
current_fn=lambda shade: POWER_SUPPLY_TYPE_MAP.get(
shade.raw_data.get(ATTR_BATTERY_KIND), None
@ -106,7 +106,6 @@ class PowerViewSelect(ShadeEntity, SelectEntity):
"""Initialize the select entity."""
super().__init__(coordinator, device_info, room_name, shade, name)
self.entity_description: PowerviewSelectDescription = description
self._attr_name = f"{self._shade_name} {description.name}"
self._attr_unique_id = f"{self._attr_unique_id}_{description.key}"
@property

View file

@ -55,7 +55,6 @@ class PowerviewSensorDescription(
SENSORS: Final = [
PowerviewSensorDescription(
key="charge",
name="Battery",
device_class=SensorDeviceClass.BATTERY,
native_unit_of_measurement=PERCENTAGE,
native_value_fn=lambda shade: round(
@ -69,7 +68,7 @@ SENSORS: Final = [
),
PowerviewSensorDescription(
key="signal",
name="Signal",
translation_key="signal_strength",
icon="mdi:signal",
native_unit_of_measurement=PERCENTAGE,
native_value_fn=lambda shade: round(
@ -129,7 +128,6 @@ class PowerViewSensor(ShadeEntity, SensorEntity):
"""Initialize the select entity."""
super().__init__(coordinator, device_info, room_name, shade, name)
self.entity_description = description
self._attr_name = f"{self._shade_name} {description.name}"
self._attr_unique_id = f"{self._attr_unique_id}_{description.key}"
self._attr_native_unit_of_measurement = description.native_unit_of_measurement

View file

@ -20,5 +20,42 @@
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
}
},
"entity": {
"button": {
"calibrate": {
"name": "Calibrate"
},
"favorite": {
"name": "Favorite"
}
},
"cover": {
"bottom": {
"name": "Bottom"
},
"top": {
"name": "Top"
},
"combined": {
"name": "Combined"
},
"front": {
"name": "Front"
},
"rear": {
"name": "Rear"
}
},
"select": {
"power_source": {
"name": "Power source"
}
},
"sensor": {
"signal_strength": {
"name": "[%key:component::sensor::entity_component::signal_strength::name%]"
}
}
}
}