Add support for Google Assistant's LocatorTrait for vacuum cleaners (#55015)

* Support for LocatorTrait for vacuum cleaners

* Handle Locator request with `silence: True`

* Update homeassistant/components/google_assistant/trait.py

Co-authored-by: Joakim Plate <elupus@ecce.se>

* Black

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
Co-authored-by: Joakim Plate <elupus@ecce.se>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
pull/55133/head
Giuseppe Iannello 2021-08-24 05:16:50 +02:00 committed by GitHub
parent ff14a11254
commit 4d7de0fd4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 0 deletions

View File

@ -74,6 +74,7 @@ from .const import (
ERR_ALREADY_DISARMED,
ERR_ALREADY_STOPPED,
ERR_CHALLENGE_NOT_SETUP,
ERR_FUNCTION_NOT_SUPPORTED,
ERR_NO_AVAILABLE_CHANNEL,
ERR_NOT_SUPPORTED,
ERR_UNSUPPORTED_INPUT,
@ -104,6 +105,7 @@ TRAIT_HUMIDITY_SETTING = f"{PREFIX_TRAITS}HumiditySetting"
TRAIT_TRANSPORT_CONTROL = f"{PREFIX_TRAITS}TransportControl"
TRAIT_MEDIA_STATE = f"{PREFIX_TRAITS}MediaState"
TRAIT_CHANNEL = f"{PREFIX_TRAITS}Channel"
TRAIT_LOCATOR = f"{PREFIX_TRAITS}Locator"
PREFIX_COMMANDS = "action.devices.commands."
COMMAND_ONOFF = f"{PREFIX_COMMANDS}OnOff"
@ -145,6 +147,7 @@ COMMAND_MEDIA_STOP = f"{PREFIX_COMMANDS}mediaStop"
COMMAND_REVERSE = f"{PREFIX_COMMANDS}Reverse"
COMMAND_SET_HUMIDITY = f"{PREFIX_COMMANDS}SetHumidity"
COMMAND_SELECT_CHANNEL = f"{PREFIX_COMMANDS}selectChannel"
COMMAND_LOCATE = f"{PREFIX_COMMANDS}Locate"
TRAITS = []
@ -566,6 +569,46 @@ class DockTrait(_Trait):
)
@register_trait
class LocatorTrait(_Trait):
"""Trait to offer locate functionality.
https://developers.google.com/actions/smarthome/traits/locator
"""
name = TRAIT_LOCATOR
commands = [COMMAND_LOCATE]
@staticmethod
def supported(domain, features, device_class, _):
"""Test if state is supported."""
return domain == vacuum.DOMAIN and features & vacuum.SUPPORT_LOCATE
def sync_attributes(self):
"""Return locator attributes for a sync request."""
return {}
def query_attributes(self):
"""Return locator query attributes."""
return {}
async def execute(self, command, data, params, challenge):
"""Execute a locate command."""
if params.get("silence", False):
raise SmartHomeError(
ERR_FUNCTION_NOT_SUPPORTED,
"Silencing a Locate request is not yet supported",
)
await self.hass.services.async_call(
self.state.domain,
vacuum.SERVICE_LOCATE,
{ATTR_ENTITY_ID: self.state.entity_id},
blocking=True,
context=data.context,
)
@register_trait
class StartStopTrait(_Trait):
"""Trait to offer StartStop functionality.

View File

@ -356,6 +356,37 @@ async def test_dock_vacuum(hass):
assert calls[0].data == {ATTR_ENTITY_ID: "vacuum.bla"}
async def test_locate_vacuum(hass):
"""Test locate trait support for vacuum domain."""
assert helpers.get_google_type(vacuum.DOMAIN, None) is not None
assert trait.LocatorTrait.supported(
vacuum.DOMAIN, vacuum.SUPPORT_LOCATE, None, None
)
trt = trait.LocatorTrait(
hass,
State(
"vacuum.bla",
vacuum.STATE_IDLE,
{ATTR_SUPPORTED_FEATURES: vacuum.SUPPORT_LOCATE},
),
BASIC_CONFIG,
)
assert trt.sync_attributes() == {}
assert trt.query_attributes() == {}
calls = async_mock_service(hass, vacuum.DOMAIN, vacuum.SERVICE_LOCATE)
await trt.execute(trait.COMMAND_LOCATE, BASIC_DATA, {"silence": False}, {})
assert len(calls) == 1
assert calls[0].data == {ATTR_ENTITY_ID: "vacuum.bla"}
with pytest.raises(helpers.SmartHomeError) as err:
await trt.execute(trait.COMMAND_LOCATE, BASIC_DATA, {"silence": True}, {})
assert err.value.code == const.ERR_FUNCTION_NOT_SUPPORTED
async def test_startstop_vacuum(hass):
"""Test startStop trait support for vacuum domain."""
assert helpers.get_google_type(vacuum.DOMAIN, None) is not None