mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
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
@ -1665,3 +1665,29 @@ class AlexaEqualizerController(AlexaCapability):
|
|||||||
configurations = {"modes": {"supported": supported_sound_modes}}
|
configurations = {"modes": {"supported": supported_sound_modes}}
|
||||||
|
|
||||||
return configurations
|
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,
|
script,
|
||||||
sensor,
|
sensor,
|
||||||
switch,
|
switch,
|
||||||
|
timer,
|
||||||
)
|
)
|
||||||
from homeassistant.components.climate import const as climate
|
from homeassistant.components.climate import const as climate
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -61,6 +62,7 @@ from .capabilities import (
|
|||||||
AlexaStepSpeaker,
|
AlexaStepSpeaker,
|
||||||
AlexaTemperatureSensor,
|
AlexaTemperatureSensor,
|
||||||
AlexaThermostatController,
|
AlexaThermostatController,
|
||||||
|
AlexaTimeHoldController,
|
||||||
AlexaToggleController,
|
AlexaToggleController,
|
||||||
)
|
)
|
||||||
from .const import CONF_DESCRIPTION, CONF_DISPLAY_CATEGORIES
|
from .const import CONF_DESCRIPTION, CONF_DISPLAY_CATEGORIES
|
||||||
@ -708,3 +710,17 @@ class InputNumberCapabilities(AlexaEntity):
|
|||||||
)
|
)
|
||||||
yield AlexaEndpointHealth(self.hass, self.entity)
|
yield AlexaEndpointHealth(self.hass, self.entity)
|
||||||
yield Alexa(self.hass)
|
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,
|
input_number,
|
||||||
light,
|
light,
|
||||||
media_player,
|
media_player,
|
||||||
|
timer,
|
||||||
)
|
)
|
||||||
from homeassistant.components.climate import const as climate
|
from homeassistant.components.climate import const as climate
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@ -1396,3 +1397,29 @@ async def async_api_bands_directive(hass, config, directive, context):
|
|||||||
# Currently bands directives are not supported.
|
# Currently bands directives are not supported.
|
||||||
msg = "Entity does not support directive"
|
msg = "Entity does not support directive"
|
||||||
raise AlexaInvalidDirectiveError(msg)
|
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"]["name"] == "ErrorResponse"
|
||||||
assert msg["header"]["namespace"] == "Alexa"
|
assert msg["header"]["namespace"] == "Alexa"
|
||||||
assert msg["payload"]["type"] == "INVALID_DIRECTIVE"
|
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…
x
Reference in New Issue
Block a user