Add number platform support to Alexa (#86553)

Co-authored-by: Mike Degatano <michael.degatano@gmail.com>
This commit is contained in:
Jan Bouwhuis
2023-01-25 13:34:53 +01:00
committed by GitHub
parent 23c9580a4a
commit f182e314e5
5 changed files with 216 additions and 37 deletions

View File

@@ -14,6 +14,7 @@ from homeassistant.components import (
input_number,
light,
media_player,
number,
timer,
vacuum,
)
@@ -26,6 +27,7 @@ from homeassistant.const import (
ATTR_SUPPORTED_FEATURES,
ATTR_TEMPERATURE,
ATTR_UNIT_OF_MEASUREMENT,
PERCENTAGE,
STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_CUSTOM_BYPASS,
STATE_ALARM_ARMED_HOME,
@@ -41,6 +43,10 @@ from homeassistant.const import (
STATE_UNKNOWN,
STATE_UNLOCKED,
STATE_UNLOCKING,
UnitOfLength,
UnitOfMass,
UnitOfTemperature,
UnitOfVolume,
)
from homeassistant.core import State
import homeassistant.util.color as color_util
@@ -65,6 +71,34 @@ from .resources import (
_LOGGER = logging.getLogger(__name__)
UNIT_TO_CATALOG_TAG = {
UnitOfTemperature.CELSIUS: AlexaGlobalCatalog.UNIT_TEMPERATURE_CELSIUS,
UnitOfTemperature.FAHRENHEIT: AlexaGlobalCatalog.UNIT_TEMPERATURE_FAHRENHEIT,
UnitOfTemperature.KELVIN: AlexaGlobalCatalog.UNIT_TEMPERATURE_KELVIN,
UnitOfLength.METERS: AlexaGlobalCatalog.UNIT_DISTANCE_METERS,
UnitOfLength.KILOMETERS: AlexaGlobalCatalog.UNIT_DISTANCE_KILOMETERS,
UnitOfLength.INCHES: AlexaGlobalCatalog.UNIT_DISTANCE_INCHES,
UnitOfLength.FEET: AlexaGlobalCatalog.UNIT_DISTANCE_FEET,
UnitOfLength.YARDS: AlexaGlobalCatalog.UNIT_DISTANCE_YARDS,
UnitOfLength.MILES: AlexaGlobalCatalog.UNIT_DISTANCE_MILES,
UnitOfMass.GRAMS: AlexaGlobalCatalog.UNIT_MASS_GRAMS,
UnitOfMass.KILOGRAMS: AlexaGlobalCatalog.UNIT_MASS_KILOGRAMS,
UnitOfMass.POUNDS: AlexaGlobalCatalog.UNIT_WEIGHT_POUNDS,
UnitOfMass.OUNCES: AlexaGlobalCatalog.UNIT_WEIGHT_OUNCES,
UnitOfVolume.LITERS: AlexaGlobalCatalog.UNIT_VOLUME_LITERS,
UnitOfVolume.CUBIC_FEET: AlexaGlobalCatalog.UNIT_VOLUME_CUBIC_FEET,
UnitOfVolume.CUBIC_METERS: AlexaGlobalCatalog.UNIT_VOLUME_CUBIC_METERS,
UnitOfVolume.GALLONS: AlexaGlobalCatalog.UNIT_VOLUME_GALLONS,
PERCENTAGE: AlexaGlobalCatalog.UNIT_PERCENT,
"preset": AlexaGlobalCatalog.SETTING_PRESET,
}
def get_resource_by_unit_of_measurement(entity: State) -> str:
"""Translate the unit of measurement to an Alexa Global Catalog keyword."""
unit: str = entity.attributes.get("unit_of_measurement", "preset")
return UNIT_TO_CATALOG_TAG.get(unit, AlexaGlobalCatalog.SETTING_PRESET)
class AlexaCapability:
"""Base class for Alexa capability interfaces.
@@ -78,10 +112,16 @@ class AlexaCapability:
supported_locales = {"en-US"}
def __init__(self, entity: State, instance: str | None = None) -> None:
def __init__(
self,
entity: State,
instance: str | None = None,
non_controllable_properties: bool | None = None,
) -> None:
"""Initialize an Alexa capability."""
self.entity = entity
self.instance = instance
self._non_controllable_properties = non_controllable_properties
def name(self) -> str:
"""Return the Alexa API name of this interface."""
@@ -101,7 +141,7 @@ class AlexaCapability:
def properties_non_controllable(self) -> bool | None:
"""Return True if non controllable."""
return None
return self._non_controllable_properties
def get_property(self, name):
"""Read and return a property.
@@ -1310,10 +1350,9 @@ class AlexaModeController(AlexaCapability):
def __init__(self, entity, instance, non_controllable=False):
"""Initialize the entity."""
super().__init__(entity, instance)
AlexaCapability.__init__(self, entity, instance, non_controllable)
self._resource = None
self._semantics = None
self.properties_non_controllable = lambda: non_controllable
def name(self):
"""Return the Alexa API name of this interface."""
@@ -1520,12 +1559,13 @@ class AlexaRangeController(AlexaCapability):
"pt-BR",
}
def __init__(self, entity, instance, non_controllable=False):
def __init__(
self, entity: State, instance: str | None, non_controllable: bool = False
) -> None:
"""Initialize the entity."""
super().__init__(entity, instance)
AlexaCapability.__init__(self, entity, instance, non_controllable)
self._resource = None
self._semantics = None
self.properties_non_controllable = lambda: non_controllable
def name(self):
"""Return the Alexa API name of this interface."""
@@ -1579,6 +1619,10 @@ class AlexaRangeController(AlexaCapability):
if self.instance == f"{input_number.DOMAIN}.{input_number.ATTR_VALUE}":
return float(self.entity.state)
# Number Value
if self.instance == f"{number.DOMAIN}.{number.ATTR_VALUE}":
return float(self.entity.state)
# Vacuum Fan Speed
if self.instance == f"{vacuum.DOMAIN}.{vacuum.ATTR_FAN_SPEED}":
speed_list = self.entity.attributes.get(vacuum.ATTR_FAN_SPEED_LIST)
@@ -1656,7 +1700,29 @@ class AlexaRangeController(AlexaCapability):
unit = self.entity.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
self._resource = AlexaPresetResource(
["Value", AlexaGlobalCatalog.SETTING_PRESET],
["Value", get_resource_by_unit_of_measurement(self.entity)],
min_value=min_value,
max_value=max_value,
precision=precision,
unit=unit,
)
self._resource.add_preset(
value=min_value, labels=[AlexaGlobalCatalog.VALUE_MINIMUM]
)
self._resource.add_preset(
value=max_value, labels=[AlexaGlobalCatalog.VALUE_MAXIMUM]
)
return self._resource.serialize_capability_resources()
# Number Value
if self.instance == f"{number.DOMAIN}.{number.ATTR_VALUE}":
min_value = float(self.entity.attributes[number.ATTR_MIN])
max_value = float(self.entity.attributes[number.ATTR_MAX])
precision = float(self.entity.attributes.get(number.ATTR_STEP, 1))
unit = self.entity.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
self._resource = AlexaPresetResource(
["Value", get_resource_by_unit_of_measurement(self.entity)],
min_value=min_value,
max_value=max_value,
precision=precision,
@@ -1807,10 +1873,9 @@ class AlexaToggleController(AlexaCapability):
def __init__(self, entity, instance, non_controllable=False):
"""Initialize the entity."""
super().__init__(entity, instance)
AlexaCapability.__init__(self, entity, instance, non_controllable)
self._resource = None
self._semantics = None
self.properties_non_controllable = lambda: non_controllable
def name(self):
"""Return the Alexa API name of this interface."""