mirror of
https://github.com/home-assistant/core.git
synced 2025-08-02 12:15:08 +02:00
Updated the CapabilityResource to support labels with the corresponding locale. This local is read from the users config.
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
|
@@ -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})
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user