Implement TimeHoldController Interface in Alexa (#30650)
* Implement Alexa.TimeHoldController Interface * Add test for timer resume directive.
This commit is contained in:
parent
e2f591e5bc
commit
74a198e37b
4 changed files with 110 additions and 0 deletions
|
@ -1665,3 +1665,29 @@ class AlexaEqualizerController(AlexaCapability):
|
|||
configurations = {"modes": {"supported": supported_sound_modes}}
|
||||
|
||||
return configurations
|
||||
|
||||
|
||||
class AlexaTimeHoldController(AlexaCapability):
|
||||
"""Implements Alexa.TimeHoldController.
|
||||
|
||||
https://developer.amazon.com/docs/device-apis/alexa-timeholdcontroller.html
|
||||
"""
|
||||
|
||||
supported_locales = {"en-US"}
|
||||
|
||||
def __init__(self, entity, allow_remote_resume=False):
|
||||
"""Initialize the entity."""
|
||||
super().__init__(entity)
|
||||
self._allow_remote_resume = allow_remote_resume
|
||||
|
||||
def name(self):
|
||||
"""Return the Alexa API name of this interface."""
|
||||
return "Alexa.TimeHoldController"
|
||||
|
||||
def configuration(self):
|
||||
"""Return configuration object.
|
||||
|
||||
Set allowRemoteResume to True if Alexa can restart the operation on the device.
|
||||
When false, Alexa does not send the Resume directive.
|
||||
"""
|
||||
return {"allowRemoteResume": self._allow_remote_resume}
|
||||
|
|
|
@ -19,6 +19,7 @@ from homeassistant.components import (
|
|||
script,
|
||||
sensor,
|
||||
switch,
|
||||
timer,
|
||||
)
|
||||
from homeassistant.components.climate import const as climate
|
||||
from homeassistant.const import (
|
||||
|
@ -61,6 +62,7 @@ from .capabilities import (
|
|||
AlexaStepSpeaker,
|
||||
AlexaTemperatureSensor,
|
||||
AlexaThermostatController,
|
||||
AlexaTimeHoldController,
|
||||
AlexaToggleController,
|
||||
)
|
||||
from .const import CONF_DESCRIPTION, CONF_DISPLAY_CATEGORIES
|
||||
|
@ -708,3 +710,17 @@ class InputNumberCapabilities(AlexaEntity):
|
|||
)
|
||||
yield AlexaEndpointHealth(self.hass, self.entity)
|
||||
yield Alexa(self.hass)
|
||||
|
||||
|
||||
@ENTITY_ADAPTERS.register(timer.DOMAIN)
|
||||
class TimerCapabilities(AlexaEntity):
|
||||
"""Class to represent Timer capabilities."""
|
||||
|
||||
def default_display_categories(self):
|
||||
"""Return the display categories for this entity."""
|
||||
return [DisplayCategory.OTHER]
|
||||
|
||||
def interfaces(self):
|
||||
"""Yield the supported interfaces."""
|
||||
yield AlexaTimeHoldController(self.entity, allow_remote_resume=True)
|
||||
yield Alexa(self.entity)
|
||||
|
|
|
@ -10,6 +10,7 @@ from homeassistant.components import (
|
|||
input_number,
|
||||
light,
|
||||
media_player,
|
||||
timer,
|
||||
)
|
||||
from homeassistant.components.climate import const as climate
|
||||
from homeassistant.const import (
|
||||
|
@ -1396,3 +1397,29 @@ async def async_api_bands_directive(hass, config, directive, context):
|
|||
# Currently bands directives are not supported.
|
||||
msg = "Entity does not support directive"
|
||||
raise AlexaInvalidDirectiveError(msg)
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.TimeHoldController", "Hold"))
|
||||
async def async_api_hold(hass, config, directive, context):
|
||||
"""Process a TimeHoldController Hold request."""
|
||||
entity = directive.entity
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
|
||||
await hass.services.async_call(
|
||||
entity.domain, timer.SERVICE_PAUSE, data, blocking=False, context=context
|
||||
)
|
||||
|
||||
return directive.response()
|
||||
|
||||
|
||||
@HANDLERS.register(("Alexa.TimeHoldController", "Resume"))
|
||||
async def async_api_resume(hass, config, directive, context):
|
||||
"""Process a TimeHoldController Resume request."""
|
||||
entity = directive.entity
|
||||
data = {ATTR_ENTITY_ID: entity.entity_id}
|
||||
|
||||
await hass.services.async_call(
|
||||
entity.domain, timer.SERVICE_START, data, blocking=False, context=context
|
||||
)
|
||||
|
||||
return directive.response()
|
||||
|
|
|
@ -3037,3 +3037,44 @@ async def test_media_player_eq_bands_not_supported(hass):
|
|||
assert msg["header"]["name"] == "ErrorResponse"
|
||||
assert msg["header"]["namespace"] == "Alexa"
|
||||
assert msg["payload"]["type"] == "INVALID_DIRECTIVE"
|
||||
|
||||
|
||||
async def test_timer_hold(hass):
|
||||
"""Test timer hold."""
|
||||
device = (
|
||||
"timer.laundry",
|
||||
"active",
|
||||
{"friendly_name": "Laundry", "duration": "00:01:00", "remaining": "00:50:00"},
|
||||
)
|
||||
appliance = await discovery_test(device, hass)
|
||||
|
||||
assert appliance["endpointId"] == "timer#laundry"
|
||||
assert appliance["displayCategories"][0] == "OTHER"
|
||||
assert appliance["friendlyName"] == "Laundry"
|
||||
|
||||
capabilities = assert_endpoint_capabilities(
|
||||
appliance, "Alexa", "Alexa.TimeHoldController"
|
||||
)
|
||||
|
||||
time_hold_capability = get_capability(capabilities, "Alexa.TimeHoldController")
|
||||
assert time_hold_capability is not None
|
||||
configuration = time_hold_capability["configuration"]
|
||||
assert configuration["allowRemoteResume"] is True
|
||||
|
||||
await assert_request_calls_service(
|
||||
"Alexa.TimeHoldController", "Hold", "timer#laundry", "timer.pause", hass
|
||||
)
|
||||
|
||||
|
||||
async def test_timer_resume(hass):
|
||||
"""Test timer resume."""
|
||||
device = (
|
||||
"timer.laundry",
|
||||
"paused",
|
||||
{"friendly_name": "Laundry", "duration": "00:01:00", "remaining": "00:50:00"},
|
||||
)
|
||||
await discovery_test(device, hass)
|
||||
|
||||
await assert_request_calls_service(
|
||||
"Alexa.TimeHoldController", "Resume", "timer#laundry", "timer.start", hass
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue