From 06216a8a45e2cae303eaf4303e22b72a4ed8ea24 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 31 Mar 2020 12:01:31 -0700 Subject: [PATCH] Google Assistant: parallize as many requests as possible (#33472) * Google Assistant: parallize as many requests as possible * Fix double comment --- .../components/google_assistant/smart_home.py | 55 ++++++++++++++----- .../google_assistant/test_smart_home.py | 3 + 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/google_assistant/smart_home.py b/homeassistant/components/google_assistant/smart_home.py index 97c872bdaf8..55e121e2fc7 100644 --- a/homeassistant/components/google_assistant/smart_home.py +++ b/homeassistant/components/google_assistant/smart_home.py @@ -131,6 +131,24 @@ async def async_devices_query(hass, data, payload): return {"devices": devices} +async def _entity_execute(entity, data, executions): + """Execute all commands for an entity. + + Returns a dict if a special result needs to be set. + """ + for execution in executions: + try: + await entity.execute(data, execution) + except SmartHomeError as err: + return { + "ids": [entity.entity_id], + "status": "ERROR", + **err.to_response(), + } + + return None + + @HANDLERS.register("action.devices.EXECUTE") async def handle_devices_execute(hass, data, payload): """Handle action.devices.EXECUTE request. @@ -138,6 +156,7 @@ async def handle_devices_execute(hass, data, payload): https://developers.google.com/assistant/smarthome/develop/process-intents#EXECUTE """ entities = {} + executions = {} results = {} for command in payload["commands"]: @@ -159,27 +178,33 @@ async def handle_devices_execute(hass, data, payload): if entity_id in results: continue - if entity_id not in entities: - state = hass.states.get(entity_id) + if entity_id in entities: + executions[entity_id].append(execution) + continue - if state is None: - results[entity_id] = { - "ids": [entity_id], - "status": "ERROR", - "errorCode": ERR_DEVICE_OFFLINE, - } - continue + state = hass.states.get(entity_id) - entities[entity_id] = GoogleEntity(hass, data.config, state) - - try: - await entities[entity_id].execute(data, execution) - except SmartHomeError as err: + if state is None: results[entity_id] = { "ids": [entity_id], "status": "ERROR", - **err.to_response(), + "errorCode": ERR_DEVICE_OFFLINE, } + continue + + entities[entity_id] = GoogleEntity(hass, data.config, state) + executions[entity_id] = [execution] + + execute_results = await asyncio.gather( + *[ + _entity_execute(entities[entity_id], data, executions[entity_id]) + for entity_id in executions + ] + ) + + for entity_id, result in zip(executions, execute_results): + if result is not None: + results[entity_id] = result final_results = list(results.values()) diff --git a/tests/components/google_assistant/test_smart_home.py b/tests/components/google_assistant/test_smart_home.py index c08c15a02f4..42002d62906 100644 --- a/tests/components/google_assistant/test_smart_home.py +++ b/tests/components/google_assistant/test_smart_home.py @@ -442,6 +442,9 @@ async def test_execute(hass): "source": "cloud", } + service_events = sorted( + service_events, key=lambda ev: ev.data["service_data"]["entity_id"] + ) assert len(service_events) == 4 assert service_events[0].data == { "domain": "light",