Trigger Alexa routines from toggles and buttons (#67889)
parent
4bdec1589d
commit
9392f59913
|
@ -4,9 +4,11 @@ from __future__ import annotations
|
|||
import logging
|
||||
|
||||
from homeassistant.components import (
|
||||
button,
|
||||
cover,
|
||||
fan,
|
||||
image_processing,
|
||||
input_button,
|
||||
input_number,
|
||||
light,
|
||||
timer,
|
||||
|
@ -1891,7 +1893,10 @@ class AlexaEventDetectionSensor(AlexaCapability):
|
|||
if self.entity.domain == image_processing.DOMAIN:
|
||||
if int(state):
|
||||
human_presence = "DETECTED"
|
||||
elif state == STATE_ON:
|
||||
elif state == STATE_ON or self.entity.domain in [
|
||||
input_button.DOMAIN,
|
||||
button.DOMAIN,
|
||||
]:
|
||||
human_presence = "DETECTED"
|
||||
|
||||
return {"value": human_presence}
|
||||
|
@ -1903,7 +1908,8 @@ class AlexaEventDetectionSensor(AlexaCapability):
|
|||
"detectionModes": {
|
||||
"humanPresence": {
|
||||
"featureAvailability": "ENABLED",
|
||||
"supportsNotDetected": True,
|
||||
"supportsNotDetected": self.entity.domain
|
||||
not in [input_button.DOMAIN, button.DOMAIN],
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -382,7 +382,6 @@ def async_get_entities(hass, config) -> list[AlexaEntity]:
|
|||
@ENTITY_ADAPTERS.register(alert.DOMAIN)
|
||||
@ENTITY_ADAPTERS.register(automation.DOMAIN)
|
||||
@ENTITY_ADAPTERS.register(group.DOMAIN)
|
||||
@ENTITY_ADAPTERS.register(input_boolean.DOMAIN)
|
||||
class GenericCapabilities(AlexaEntity):
|
||||
"""A generic, on/off device.
|
||||
|
||||
|
@ -405,12 +404,16 @@ class GenericCapabilities(AlexaEntity):
|
|||
]
|
||||
|
||||
|
||||
@ENTITY_ADAPTERS.register(input_boolean.DOMAIN)
|
||||
@ENTITY_ADAPTERS.register(switch.DOMAIN)
|
||||
class SwitchCapabilities(AlexaEntity):
|
||||
"""Class to represent Switch capabilities."""
|
||||
|
||||
def default_display_categories(self):
|
||||
"""Return the display categories for this entity."""
|
||||
if self.entity.domain == input_boolean.DOMAIN:
|
||||
return [DisplayCategory.OTHER]
|
||||
|
||||
device_class = self.entity.attributes.get(ATTR_DEVICE_CLASS)
|
||||
if device_class == switch.SwitchDeviceClass.OUTLET:
|
||||
return [DisplayCategory.SMARTPLUG]
|
||||
|
@ -421,6 +424,7 @@ class SwitchCapabilities(AlexaEntity):
|
|||
"""Yield the supported interfaces."""
|
||||
return [
|
||||
AlexaPowerController(self.entity),
|
||||
AlexaContactSensor(self.hass, self.entity),
|
||||
AlexaEndpointHealth(self.hass, self.entity),
|
||||
Alexa(self.hass),
|
||||
]
|
||||
|
@ -439,6 +443,8 @@ class ButtonCapabilities(AlexaEntity):
|
|||
"""Yield the supported interfaces."""
|
||||
return [
|
||||
AlexaSceneController(self.entity, supports_deactivation=False),
|
||||
AlexaEventDetectionSensor(self.hass, self.entity),
|
||||
AlexaEndpointHealth(self.hass, self.entity),
|
||||
Alexa(self.hass),
|
||||
]
|
||||
|
||||
|
|
|
@ -846,6 +846,57 @@ async def test_report_image_processing(hass):
|
|||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("domain", ["button", "input_button"])
|
||||
async def test_report_button_pressed(hass, domain):
|
||||
"""Test button presses report human presence detection events to trigger routines."""
|
||||
hass.states.async_set(
|
||||
f"{domain}.test_button", "now", {"friendly_name": "Test button"}
|
||||
)
|
||||
|
||||
properties = await reported_properties(hass, f"{domain}#test_button")
|
||||
properties.assert_equal(
|
||||
"Alexa.EventDetectionSensor",
|
||||
"humanPresenceDetectionState",
|
||||
{"value": "DETECTED"},
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("domain", ["switch", "input_boolean"])
|
||||
async def test_toggle_entities_report_contact_events(hass, domain):
|
||||
"""Test toggles and switches report contact sensor events to trigger routines."""
|
||||
hass.states.async_set(
|
||||
f"{domain}.test_toggle", "on", {"friendly_name": "Test toggle"}
|
||||
)
|
||||
|
||||
properties = await reported_properties(hass, f"{domain}#test_toggle")
|
||||
properties.assert_equal(
|
||||
"Alexa.PowerController",
|
||||
"powerState",
|
||||
"ON",
|
||||
)
|
||||
properties.assert_equal(
|
||||
"Alexa.ContactSensor",
|
||||
"detectionState",
|
||||
"DETECTED",
|
||||
)
|
||||
|
||||
hass.states.async_set(
|
||||
f"{domain}.test_toggle", "off", {"friendly_name": "Test toggle"}
|
||||
)
|
||||
|
||||
properties = await reported_properties(hass, f"{domain}#test_toggle")
|
||||
properties.assert_equal(
|
||||
"Alexa.PowerController",
|
||||
"powerState",
|
||||
"OFF",
|
||||
)
|
||||
properties.assert_equal(
|
||||
"Alexa.ContactSensor",
|
||||
"detectionState",
|
||||
"NOT_DETECTED",
|
||||
)
|
||||
|
||||
|
||||
async def test_get_property_blowup(hass, caplog):
|
||||
"""Test we handle a property blowing up."""
|
||||
hass.states.async_set(
|
||||
|
|
|
@ -182,8 +182,12 @@ async def test_switch(hass, events):
|
|||
assert appliance["endpointId"] == "switch#test"
|
||||
assert appliance["displayCategories"][0] == "SWITCH"
|
||||
assert appliance["friendlyName"] == "Test switch"
|
||||
assert_endpoint_capabilities(
|
||||
appliance, "Alexa.PowerController", "Alexa.EndpointHealth", "Alexa"
|
||||
capabilities = assert_endpoint_capabilities(
|
||||
appliance,
|
||||
"Alexa.PowerController",
|
||||
"Alexa.ContactSensor",
|
||||
"Alexa.EndpointHealth",
|
||||
"Alexa",
|
||||
)
|
||||
|
||||
await assert_power_controller_works(
|
||||
|
@ -192,6 +196,14 @@ async def test_switch(hass, events):
|
|||
|
||||
properties = await reported_properties(hass, "switch#test")
|
||||
properties.assert_equal("Alexa.PowerController", "powerState", "ON")
|
||||
properties.assert_equal("Alexa.ContactSensor", "detectionState", "DETECTED")
|
||||
properties.assert_equal("Alexa.EndpointHealth", "connectivity", {"value": "OK"})
|
||||
|
||||
contact_sensor_capability = get_capability(capabilities, "Alexa.ContactSensor")
|
||||
assert contact_sensor_capability is not None
|
||||
properties = contact_sensor_capability["properties"]
|
||||
assert properties["retrievable"] is True
|
||||
assert {"name": "detectionState"} in properties["supported"]
|
||||
|
||||
|
||||
async def test_outlet(hass, events):
|
||||
|
@ -207,7 +219,11 @@ async def test_outlet(hass, events):
|
|||
assert appliance["displayCategories"][0] == "SMARTPLUG"
|
||||
assert appliance["friendlyName"] == "Test switch"
|
||||
assert_endpoint_capabilities(
|
||||
appliance, "Alexa", "Alexa.PowerController", "Alexa.EndpointHealth"
|
||||
appliance,
|
||||
"Alexa",
|
||||
"Alexa.PowerController",
|
||||
"Alexa.EndpointHealth",
|
||||
"Alexa.ContactSensor",
|
||||
)
|
||||
|
||||
|
||||
|
@ -335,8 +351,12 @@ async def test_input_boolean(hass):
|
|||
assert appliance["endpointId"] == "input_boolean#test"
|
||||
assert appliance["displayCategories"][0] == "OTHER"
|
||||
assert appliance["friendlyName"] == "Test input boolean"
|
||||
assert_endpoint_capabilities(
|
||||
appliance, "Alexa.PowerController", "Alexa.EndpointHealth", "Alexa"
|
||||
capabilities = assert_endpoint_capabilities(
|
||||
appliance,
|
||||
"Alexa.PowerController",
|
||||
"Alexa.ContactSensor",
|
||||
"Alexa.EndpointHealth",
|
||||
"Alexa",
|
||||
)
|
||||
|
||||
await assert_power_controller_works(
|
||||
|
@ -347,6 +367,17 @@ async def test_input_boolean(hass):
|
|||
"2022-04-19T07:53:05Z",
|
||||
)
|
||||
|
||||
properties = await reported_properties(hass, "input_boolean#test")
|
||||
properties.assert_equal("Alexa.PowerController", "powerState", "OFF")
|
||||
properties.assert_equal("Alexa.ContactSensor", "detectionState", "NOT_DETECTED")
|
||||
properties.assert_equal("Alexa.EndpointHealth", "connectivity", {"value": "OK"})
|
||||
|
||||
contact_sensor_capability = get_capability(capabilities, "Alexa.ContactSensor")
|
||||
assert contact_sensor_capability is not None
|
||||
properties = contact_sensor_capability["properties"]
|
||||
assert properties["retrievable"] is True
|
||||
assert {"name": "detectionState"} in properties["supported"]
|
||||
|
||||
|
||||
@freeze_time("2022-04-19 07:53:05")
|
||||
async def test_scene(hass):
|
||||
|
@ -4003,7 +4034,11 @@ async def test_button(hass, domain):
|
|||
assert appliance["friendlyName"] == "Ring Doorbell"
|
||||
|
||||
capabilities = assert_endpoint_capabilities(
|
||||
appliance, "Alexa.SceneController", "Alexa"
|
||||
appliance,
|
||||
"Alexa.SceneController",
|
||||
"Alexa.EventDetectionSensor",
|
||||
"Alexa.EndpointHealth",
|
||||
"Alexa",
|
||||
)
|
||||
scene_capability = get_capability(capabilities, "Alexa.SceneController")
|
||||
assert scene_capability["supportsDeactivation"] is False
|
||||
|
@ -4016,6 +4051,21 @@ async def test_button(hass, domain):
|
|||
"2022-04-19T07:53:05Z",
|
||||
)
|
||||
|
||||
event_detection_capability = get_capability(
|
||||
capabilities, "Alexa.EventDetectionSensor"
|
||||
)
|
||||
assert event_detection_capability is not None
|
||||
properties = event_detection_capability["properties"]
|
||||
assert properties["proactivelyReported"] is True
|
||||
assert not properties["retrievable"]
|
||||
assert {"name": "humanPresenceDetectionState"} in properties["supported"]
|
||||
assert (
|
||||
event_detection_capability["configuration"]["detectionModes"]["humanPresence"][
|
||||
"supportsNotDetected"
|
||||
]
|
||||
is False
|
||||
)
|
||||
|
||||
|
||||
async def test_api_message_sets_authorized(hass):
|
||||
"""Test an incoming API messages sets the authorized flag."""
|
||||
|
|
Loading…
Reference in New Issue