Implement supported locales for Alexa capabilities (#30285)

* Implement Alexa capability supported locales.

* Check config for supported locales.

* Removed unused import.

* Applied some potpourri to improve code smell.

* Change supported_locales to set.
This commit is contained in:
ochlocracy 2020-01-03 15:23:22 -05:00 committed by Paulus Schoutsen
parent 80701c8f2a
commit 6387a50697
8 changed files with 279 additions and 2 deletions

View File

@ -17,6 +17,8 @@ from .const import (
CONF_ENDPOINT,
CONF_ENTITY_CONFIG,
CONF_FILTER,
CONF_LOCALE,
CONF_SUPPORTED_LOCALES,
CONF_TEXT,
CONF_TITLE,
CONF_UID,
@ -27,6 +29,7 @@ _LOGGER = logging.getLogger(__name__)
CONF_FLASH_BRIEFINGS = "flash_briefings"
CONF_SMART_HOME = "smart_home"
DEFAULT_LOCALE = "en-US"
ALEXA_ENTITY_SCHEMA = vol.Schema(
{
@ -41,6 +44,9 @@ SMART_HOME_SCHEMA = vol.Schema(
vol.Optional(CONF_ENDPOINT): cv.string,
vol.Optional(CONF_CLIENT_ID): cv.string,
vol.Optional(CONF_CLIENT_SECRET): cv.string,
vol.Optional(CONF_LOCALE, default=DEFAULT_LOCALE): vol.In(
CONF_SUPPORTED_LOCALES
),
vol.Optional(CONF_FILTER, default={}): entityfilter.FILTER_SCHEMA,
vol.Optional(CONF_ENTITY_CONFIG): {cv.entity_id: ALEXA_ENTITY_SCHEMA},
}

View File

@ -56,6 +56,8 @@ class AlexaCapability:
https://developer.amazon.com/docs/device-apis/message-guide.html
"""
supported_locales = {"en-US"}
def __init__(self, entity, instance=None):
"""Initialize an Alexa capability."""
self.entity = entity
@ -239,6 +241,21 @@ class Alexa(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-interface.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"es-MX",
"fr-CA",
"fr-FR",
"it-IT",
"ja-JP",
}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa"
@ -250,6 +267,19 @@ class AlexaEndpointHealth(AlexaCapability):
https://developer.amazon.com/docs/smarthome/state-reporting-for-a-smart-home-skill.html#report-state-when-alexa-requests-it
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"fr-FR",
"it-IT",
"ja-JP",
}
def __init__(self, hass, entity):
"""Initialize the entity."""
super().__init__(entity)
@ -287,6 +317,19 @@ class AlexaPowerController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-powercontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"fr-FR",
"it-IT",
"ja-JP",
}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.PowerController"
@ -323,6 +366,17 @@ class AlexaLockController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-lockcontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-US",
"es-ES",
"it-IT",
"ja-JP",
}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.LockController"
@ -357,6 +411,17 @@ class AlexaSceneController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-scenecontroller.html
"""
supported_locales = {
"de-DE",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"fr-FR",
"it-IT",
}
def __init__(self, entity, supports_deactivation):
"""Initialize the entity."""
super().__init__(entity)
@ -373,6 +438,19 @@ class AlexaBrightnessController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-brightnesscontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"fr-FR",
"it-IT",
"ja-JP",
}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.BrightnessController"
@ -404,6 +482,19 @@ class AlexaColorController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-colorcontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"fr-FR",
"it-IT",
"ja-JP",
}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.ColorController"
@ -436,6 +527,19 @@ class AlexaColorTemperatureController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-colortemperaturecontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"fr-FR",
"it-IT",
"ja-JP",
}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.ColorTemperatureController"
@ -465,6 +569,19 @@ class AlexaPercentageController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-percentagecontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"fr-FR",
"it-IT",
"ja-JP",
}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.PercentageController"
@ -499,6 +616,8 @@ class AlexaSpeaker(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-speaker.html
"""
supported_locales = {"de-DE", "en-AU", "en-CA", "en-GB", "en-IN", "en-US"}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.Speaker"
@ -510,6 +629,8 @@ class AlexaStepSpeaker(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-stepspeaker.html
"""
supported_locales = {"de-DE", "en-AU", "en-CA", "en-GB", "en-IN", "en-US"}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.StepSpeaker"
@ -521,6 +642,8 @@ class AlexaPlaybackController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-playbackcontroller.html
"""
supported_locales = {"de-DE", "en-AU", "en-CA", "en-GB", "en-IN", "en-US", "fr-FR"}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.PlaybackController"
@ -554,6 +677,8 @@ class AlexaInputController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-inputcontroller.html
"""
supported_locales = {"de-DE", "en-AU", "en-CA", "en-GB", "en-IN", "en-US"}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.InputController"
@ -582,6 +707,19 @@ class AlexaTemperatureSensor(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-temperaturesensor.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"fr-FR",
"it-IT",
"ja-JP",
}
def __init__(self, hass, entity):
"""Initialize the entity."""
super().__init__(entity)
@ -637,6 +775,8 @@ class AlexaContactSensor(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-contactsensor.html
"""
supported_locales = {"en-CA", "en-US"}
def __init__(self, hass, entity):
"""Initialize the entity."""
super().__init__(entity)
@ -674,6 +814,8 @@ class AlexaMotionSensor(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-motionsensor.html
"""
supported_locales = {"en-CA", "en-US"}
def __init__(self, hass, entity):
"""Initialize the entity."""
super().__init__(entity)
@ -711,6 +853,19 @@ class AlexaThermostatController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-thermostatcontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"fr-FR",
"it-IT",
"ja-JP",
}
def __init__(self, hass, entity):
"""Initialize the entity."""
super().__init__(entity)
@ -819,6 +974,19 @@ class AlexaPowerLevelController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-powerlevelcontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"fr-FR",
"it-IT",
"ja-JP",
}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.PowerLevelController"
@ -854,6 +1022,8 @@ class AlexaSecurityPanelController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-securitypanelcontroller.html
"""
supported_locales = {"en-AU", "en-CA", "en-IN", "en-US"}
def __init__(self, hass, entity):
"""Initialize the entity."""
super().__init__(entity)
@ -906,6 +1076,21 @@ class AlexaModeController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-modecontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"es-MX",
"fr-CA",
"fr-FR",
"it-IT",
"ja-JP",
}
def __init__(self, entity, instance, non_controllable=False):
"""Initialize the entity."""
super().__init__(entity, instance)
@ -1031,6 +1216,21 @@ class AlexaRangeController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-rangecontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"es-MX",
"fr-CA",
"fr-FR",
"it-IT",
"ja-JP",
}
def __init__(self, entity, instance, non_controllable=False):
"""Initialize the entity."""
super().__init__(entity, instance)
@ -1198,6 +1398,21 @@ class AlexaToggleController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-togglecontroller.html
"""
supported_locales = {
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"es-MX",
"fr-CA",
"fr-FR",
"it-IT",
"ja-JP",
}
def __init__(self, entity, instance, non_controllable=False):
"""Initialize the entity."""
super().__init__(entity, instance)
@ -1252,6 +1467,8 @@ class AlexaChannelController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-channelcontroller.html
"""
supported_locales = {"de-DE", "en-AU", "en-CA", "en-GB", "en-IN", "en-US"}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.ChannelController"
@ -1263,6 +1480,8 @@ class AlexaDoorbellEventSource(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-doorbelleventsource.html
"""
supported_locales = {"en-US"}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.DoorbellEventSource"
@ -1278,6 +1497,8 @@ class AlexaPlaybackStateReporter(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-playbackstatereporter.html
"""
supported_locales = {"de-DE", "en-GB", "en-US", "fr-FR"}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.PlaybackStateReporter"
@ -1314,6 +1535,8 @@ class AlexaSeekController(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-seekcontroller.html
"""
supported_locales = {"de-DE", "en-GB", "en-US"}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.SeekController"
@ -1325,6 +1548,8 @@ class AlexaEventDetectionSensor(AlexaCapability):
https://developer.amazon.com/docs/device-apis/alexa-eventdetectionsensor.html
"""
supported_locales = {"en-US"}
def __init__(self, hass, entity):
"""Initialize the entity."""
super().__init__(entity)
@ -1382,6 +1607,8 @@ class AlexaEqualizerController(AlexaCapability):
https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-equalizercontroller.html
"""
supported_locales = {"en-US"}
def name(self):
"""Return the Alexa API name of this interface."""
return "Alexa.EqualizerController"

View File

@ -28,6 +28,11 @@ class AbstractConfig:
"""Endpoint for report state."""
return None
@property
def locale(self):
"""Return config locale."""
return None
@property
def entity_config(self):
"""Return entity config."""

View File

@ -19,6 +19,7 @@ CONF_ENTITY_CONFIG = "entity_config"
CONF_ENDPOINT = "endpoint"
CONF_CLIENT_ID = "client_id"
CONF_CLIENT_SECRET = "client_secret"
CONF_LOCALE = "locale"
ATTR_UID = "uid"
ATTR_UPDATE_DATE = "updateDate"
@ -42,6 +43,20 @@ API_CHANGE = "change"
CONF_DESCRIPTION = "description"
CONF_DISPLAY_CATEGORIES = "display_categories"
CONF_SUPPORTED_LOCALES = (
"de-DE",
"en-AU",
"en-CA",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"es-MX",
"fr-CA",
"fr-FR",
"it-IT",
"ja-JP",
)
API_TEMP_UNITS = {TEMP_FAHRENHEIT: "FAHRENHEIT", TEMP_CELSIUS: "CELSIUS"}

View File

@ -260,16 +260,24 @@ class AlexaEntity:
def serialize_discovery(self):
"""Serialize the entity for discovery."""
return {
result = {
"displayCategories": self.display_categories(),
"cookie": {},
"endpointId": self.alexa_id(),
"friendlyName": self.friendly_name(),
"description": self.description(),
"manufacturerName": "Home Assistant",
"capabilities": [i.serialize_discovery() for i in self.interfaces()],
}
locale = self.config.locale
capabilities = []
for i in self.interfaces():
if locale in i.supported_locales:
capabilities.append(i.serialize_discovery())
result["capabilities"] = capabilities
return result
@callback
def async_get_entities(hass, config) -> List[AlexaEntity]:

View File

@ -412,6 +412,10 @@ async def async_api_lock(hass, config, directive, context):
@HANDLERS.register(("Alexa.LockController", "Unlock"))
async def async_api_unlock(hass, config, directive, context):
"""Process an unlock request."""
if config.locale not in {"de-DE", "en-US", "ja-JP"}:
msg = f"The unlock directive is not supported for the following locales: {config.locale}"
raise AlexaInvalidDirectiveError(msg)
entity = directive.entity
await hass.services.async_call(
entity.domain,

View File

@ -12,6 +12,7 @@ from .const import (
CONF_ENDPOINT,
CONF_ENTITY_CONFIG,
CONF_FILTER,
CONF_LOCALE,
)
from .smart_home import async_handle_message
from .state_report import async_enable_proactive_mode
@ -53,6 +54,11 @@ class AlexaConfig(AbstractConfig):
"""Return entity config."""
return self._config.get(CONF_ENTITY_CONFIG) or {}
@property
def locale(self):
"""Return config locale."""
return self._config.get(CONF_LOCALE)
def should_expose(self, entity_id):
"""If an entity should be exposed."""
return self._config[CONF_FILTER](entity_id)

View File

@ -8,6 +8,7 @@ from tests.common import async_mock_service
TEST_URL = "https://api.amazonalexa.com/v3/events"
TEST_TOKEN_URL = "https://api.amazon.com/auth/o2/token"
TEST_LOCALE = "en-US"
class MockConfig(config.AbstractConfig):
@ -30,6 +31,11 @@ class MockConfig(config.AbstractConfig):
"""Endpoint for report state."""
return TEST_URL
@property
def locale(self):
"""Return config locale."""
return TEST_LOCALE
def should_expose(self, entity_id):
"""If an entity should be exposed."""
return True