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

View File

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

View File

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