Updated the CapabilityResource to support labels with the corresponding locale. This local is read from the users config.

This commit is contained in:
tim
2024-06-23 22:01:44 +00:00
parent edc9009bca
commit fbdf37904a
3 changed files with 54 additions and 19 deletions

View File

@@ -3,7 +3,7 @@
from __future__ import annotations
import logging
from typing import Any
from typing import TYPE_CHECKING, Any
from typing_extensions import Generator
@@ -60,6 +60,9 @@ from homeassistant.core import HomeAssistant, State
import homeassistant.util.color as color_util
import homeassistant.util.dt as dt_util
if TYPE_CHECKING:
from .config import AbstractConfig
from .const import (
API_TEMP_UNITS,
API_THERMOSTAT_MODES,
@@ -126,11 +129,13 @@ class AlexaCapability:
self,
entity: State,
instance: str | None = None,
config: AbstractConfig | None = None,
non_controllable_properties: bool | None = None,
) -> None:
"""Initialize an Alexa capability."""
self.entity = entity
self.instance = instance
self.config = config
self._non_controllable_properties = non_controllable_properties
def name(self) -> str:
@@ -1390,10 +1395,14 @@ class AlexaModeController(AlexaCapability):
}
def __init__(
self, entity: State, instance: str, non_controllable: bool = False
self,
entity: State,
instance: str,
config: AbstractConfig,
non_controllable: bool = False,
) -> None:
"""Initialize the entity."""
AlexaCapability.__init__(self, entity, instance, non_controllable)
AlexaCapability.__init__(self, entity, instance, config, non_controllable)
self._resource = None
self._semantics = None
@@ -1562,10 +1571,13 @@ class AlexaModeController(AlexaCapability):
# Remote Resource
if self.instance == f"{remote.DOMAIN}.{remote.ATTR_ACTIVITY}":
self._resource = AlexaModeResource([AlexaGlobalCatalog.SETTING_MODE], False)
activities = self.entity.attributes.get(remote.ATTR_ACTIVITY_LIST) or []
activities: list[str] = (
self.entity.attributes.get(remote.ATTR_ACTIVITY_LIST) or []
)
locale = self.config.locale if self.config else ""
for activity in activities:
self._resource.add_mode(
f"{remote.ATTR_ACTIVITY}.{activity}", [activity]
self._resource.add_mode_with_locale(
f"{remote.ATTR_ACTIVITY}.{activity}", {activity: locale or ""}
)
# Remotes with a single preset_mode completely break Alexa discovery, add a
# fake preset (see issue #53832).
@@ -1729,7 +1741,7 @@ class AlexaRangeController(AlexaCapability):
self, entity: State, instance: str | None, non_controllable: bool = False
) -> None:
"""Initialize the entity."""
AlexaCapability.__init__(self, entity, instance, non_controllable)
AlexaCapability.__init__(self, entity, instance, None, non_controllable)
self._resource = None
self._semantics = None
@@ -2072,7 +2084,7 @@ class AlexaToggleController(AlexaCapability):
self, entity: State, instance: str, non_controllable: bool = False
) -> None:
"""Initialize the entity."""
AlexaCapability.__init__(self, entity, instance, non_controllable)
AlexaCapability.__init__(self, entity, instance, None, non_controllable)
self._resource = None
self._semantics = None

View File

@@ -504,6 +504,7 @@ class ClimateCapabilities(AlexaEntity):
yield AlexaModeController(
self.entity,
instance=f"{water_heater.DOMAIN}.{water_heater.ATTR_OPERATION_MODE}",
config=self.config,
)
yield AlexaEndpointHealth(self.hass, self.entity)
yield Alexa(self.entity)
@@ -553,7 +554,9 @@ class CoverCapabilities(AlexaEntity):
cover.CoverEntityFeature.CLOSE | cover.CoverEntityFeature.OPEN
):
yield AlexaModeController(
self.entity, instance=f"{cover.DOMAIN}.{cover.ATTR_POSITION}"
self.entity,
instance=f"{cover.DOMAIN}.{cover.ATTR_POSITION}",
config=self.config,
)
if supported & cover.CoverEntityFeature.SET_TILT_POSITION:
yield AlexaRangeController(self.entity, instance=f"{cover.DOMAIN}.tilt")
@@ -625,12 +628,16 @@ class FanCapabilities(AlexaEntity):
force_range_controller = False
if supported & fan.FanEntityFeature.PRESET_MODE:
yield AlexaModeController(
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_PRESET_MODE}"
self.entity,
instance=f"{fan.DOMAIN}.{fan.ATTR_PRESET_MODE}",
config=self.config,
)
force_range_controller = False
if supported & fan.FanEntityFeature.DIRECTION:
yield AlexaModeController(
self.entity, instance=f"{fan.DOMAIN}.{fan.ATTR_DIRECTION}"
self.entity,
instance=f"{fan.DOMAIN}.{fan.ATTR_DIRECTION}",
config=self.config,
)
force_range_controller = False
@@ -660,7 +667,9 @@ class RemoteCapabilities(AlexaEntity):
"""Yield the supported interfaces."""
yield AlexaPowerController(self.entity)
yield AlexaModeController(
self.entity, instance=f"{remote.DOMAIN}.{remote.ATTR_ACTIVITY}"
self.entity,
instance=f"{remote.DOMAIN}.{remote.ATTR_ACTIVITY}",
config=self.config,
)
yield AlexaEndpointHealth(self.hass, self.entity)
yield Alexa(self.entity)
@@ -680,7 +689,9 @@ class HumidifierCapabilities(AlexaEntity):
supported = self.entity.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if supported & humidifier.HumidifierEntityFeature.MODES:
yield AlexaModeController(
self.entity, instance=f"{humidifier.DOMAIN}.{humidifier.ATTR_MODE}"
self.entity,
instance=f"{humidifier.DOMAIN}.{humidifier.ATTR_MODE}",
config=self.config,
)
yield AlexaRangeController(
self.entity, instance=f"{humidifier.DOMAIN}.{humidifier.ATTR_HUMIDITY}"
@@ -1012,7 +1023,9 @@ class ValveCapabilities(AlexaEntity):
elif supported & (
valve.ValveEntityFeature.CLOSE | valve.ValveEntityFeature.OPEN
):
yield AlexaModeController(self.entity, instance=f"{valve.DOMAIN}.state")
yield AlexaModeController(
self.entity, instance=f"{valve.DOMAIN}.state", config=self.config
)
if supported & valve.ValveEntityFeature.STOP:
yield AlexaToggleController(self.entity, instance=f"{valve.DOMAIN}.stop")
yield AlexaEndpointHealth(self.hass, self.entity)

View File

@@ -211,9 +211,9 @@ class AlexaCapabilityResource:
def __init__(self, labels: list[str]) -> None:
"""Initialize an Alexa resource."""
self._resource_labels = []
self._resource_labels: dict[str, str] = {}
for label in labels:
self._resource_labels.append(label)
self._resource_labels.update({label: ""})
def serialize_capability_resources(self) -> dict[str, list[dict[str, Any]]]:
"""Return capabilityResources object serialized for an API response."""
@@ -226,20 +226,22 @@ class AlexaCapabilityResource:
"""
raise NotImplementedError
def serialize_labels(self, resources: list[str]) -> dict[str, list[dict[str, Any]]]:
def serialize_labels(
self, resources: dict[str, str]
) -> dict[str, list[dict[str, Any]]]:
"""Return serialized labels for an API response.
Returns resource label objects for friendlyNames serialized.
"""
labels: list[dict[str, Any]] = []
label_dict: dict[str, Any]
for label in resources:
for label, locale in resources.items():
if label in AlexaGlobalCatalog.__dict__.values():
label_dict = {"@type": "asset", "value": {"assetId": label}}
else:
label_dict = {
"@type": "text",
"value": {"text": label, "locale": "en-US"},
"value": {"text": label, "locale": locale or "en-US"},
}
labels.append(label_dict)
@@ -260,6 +262,10 @@ class AlexaModeResource(AlexaCapabilityResource):
self._mode_ordered: bool = ordered
def add_mode(self, value: str, labels: list[str]) -> None:
"""Add mode to the supportedModes object."""
self.add_mode_with_locale(value, {label: "" for label in labels})
def add_mode_with_locale(self, value: str, labels: dict[str, str]) -> None:
"""Add mode to the supportedModes object."""
self._supported_modes.append({"value": value, "labels": labels})
@@ -307,6 +313,10 @@ class AlexaPresetResource(AlexaCapabilityResource):
self._unit_of_measure = unit
def add_preset(self, value: float, labels: list[str]) -> None:
"""Add preset to configuration presets array."""
self.add_preset_with_locale(value, {label: "" for label in labels})
def add_preset_with_locale(self, value: float, labels: dict[str, str]) -> None:
"""Add preset to configuration presets array."""
self._presets.append({"value": value, "labels": labels})