Send only a single event per incoming Google command (#49449)

pull/49494/head
Paulus Schoutsen 2021-04-20 09:21:52 -07:00 committed by GitHub
parent 410f0e3604
commit 7e7267f822
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 85 additions and 133 deletions

View File

@ -1,8 +1,7 @@
"""Describe logbook events.""" """Describe logbook events."""
from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.core import callback from homeassistant.core import callback
from .const import DOMAIN, EVENT_COMMAND_RECEIVED from .const import DOMAIN, EVENT_COMMAND_RECEIVED, SOURCE_CLOUD
COMMON_COMMAND_PREFIX = "action.devices.commands." COMMON_COMMAND_PREFIX = "action.devices.commands."
@ -14,16 +13,18 @@ def async_describe_events(hass, async_describe_event):
@callback @callback
def async_describe_logbook_event(event): def async_describe_logbook_event(event):
"""Describe a logbook event.""" """Describe a logbook event."""
entity_id = event.data[ATTR_ENTITY_ID] commands = []
state = hass.states.get(entity_id)
name = state.name if state else entity_id
command = event.data["execution"]["command"] for command_payload in event.data["execution"]:
if command.startswith(COMMON_COMMAND_PREFIX): command = command_payload["command"]
command = command[len(COMMON_COMMAND_PREFIX) :] if command.startswith(COMMON_COMMAND_PREFIX):
command = command[len(COMMON_COMMAND_PREFIX) :]
commands.append(command)
message = f"sent command {command} for {name} (via {event.data['source']})" message = f"sent command {', '.join(commands)}"
if event.data["source"] != SOURCE_CLOUD:
message += f" (via {event.data['source']})"
return {"name": "Google Assistant", "message": message, "entity_id": entity_id} return {"name": "Google Assistant", "message": message}
async_describe_event(DOMAIN, EVENT_COMMAND_RECEIVED, async_describe_logbook_event) async_describe_event(DOMAIN, EVENT_COMMAND_RECEIVED, async_describe_logbook_event)

View File

@ -116,21 +116,23 @@ async def async_devices_query(hass, data, payload):
https://developers.google.com/assistant/smarthome/develop/process-intents#QUERY https://developers.google.com/assistant/smarthome/develop/process-intents#QUERY
""" """
payload_devices = payload.get("devices", [])
hass.bus.async_fire(
EVENT_QUERY_RECEIVED,
{
"request_id": data.request_id,
ATTR_ENTITY_ID: [device["id"] for device in payload_devices],
"source": data.source,
},
context=data.context,
)
devices = {} devices = {}
for device in payload.get("devices", []): for device in payload_devices:
devid = device["id"] devid = device["id"]
state = hass.states.get(devid) state = hass.states.get(devid)
hass.bus.async_fire(
EVENT_QUERY_RECEIVED,
{
"request_id": data.request_id,
ATTR_ENTITY_ID: devid,
"source": data.source,
},
context=data.context,
)
if not state: if not state:
# If we can't find a state, the device is offline # If we can't find a state, the device is offline
devices[devid] = {"online": False} devices[devid] = {"online": False}
@ -175,20 +177,20 @@ async def handle_devices_execute(hass, data, payload):
results = {} results = {}
for command in payload["commands"]: for command in payload["commands"]:
hass.bus.async_fire(
EVENT_COMMAND_RECEIVED,
{
"request_id": data.request_id,
ATTR_ENTITY_ID: [device["id"] for device in command["devices"]],
"execution": command["execution"],
"source": data.source,
},
context=data.context,
)
for device, execution in product(command["devices"], command["execution"]): for device, execution in product(command["devices"], command["execution"]):
entity_id = device["id"] entity_id = device["id"]
hass.bus.async_fire(
EVENT_COMMAND_RECEIVED,
{
"request_id": data.request_id,
ATTR_ENTITY_ID: entity_id,
"execution": execution,
"source": data.source,
},
context=data.context,
)
# Happens if error occurred. Skip entity for further processing # Happens if error occurred. Skip entity for further processing
if entity_id in results: if entity_id in results:
continue continue

View File

@ -32,11 +32,13 @@ async def test_humanify_command_received(hass):
EVENT_COMMAND_RECEIVED, EVENT_COMMAND_RECEIVED,
{ {
"request_id": "abcd", "request_id": "abcd",
ATTR_ENTITY_ID: "light.kitchen", ATTR_ENTITY_ID: ["light.kitchen"],
"execution": { "execution": [
"command": "action.devices.commands.OnOff", {
"params": {"on": True}, "command": "action.devices.commands.OnOff",
}, "params": {"on": True},
}
],
"source": SOURCE_LOCAL, "source": SOURCE_LOCAL,
}, },
), ),
@ -44,11 +46,13 @@ async def test_humanify_command_received(hass):
EVENT_COMMAND_RECEIVED, EVENT_COMMAND_RECEIVED,
{ {
"request_id": "abcd", "request_id": "abcd",
ATTR_ENTITY_ID: "light.non_existing", ATTR_ENTITY_ID: ["light.non_existing"],
"execution": { "execution": [
"command": "action.devices.commands.OnOff", {
"params": {"on": False}, "command": "action.devices.commands.OnOff",
}, "params": {"on": False},
}
],
"source": SOURCE_CLOUD, "source": SOURCE_CLOUD,
}, },
), ),
@ -63,10 +67,8 @@ async def test_humanify_command_received(hass):
assert event1["name"] == "Google Assistant" assert event1["name"] == "Google Assistant"
assert event1["domain"] == DOMAIN assert event1["domain"] == DOMAIN
assert event1["message"] == "sent command OnOff for The Kitchen Lights (via local)" assert event1["message"] == "sent command OnOff (via local)"
assert event1["entity_id"] == "light.kitchen"
assert event2["name"] == "Google Assistant" assert event2["name"] == "Google Assistant"
assert event2["domain"] == DOMAIN assert event2["domain"] == DOMAIN
assert event2["message"] == "sent command OnOff for light.non_existing (via cloud)" assert event2["message"] == "sent command OnOff"
assert event2["entity_id"] == "light.non_existing"

View File

@ -353,29 +353,16 @@ async def test_query_message(hass):
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(events) == 4 assert len(events) == 1
assert events[0].event_type == EVENT_QUERY_RECEIVED assert events[0].event_type == EVENT_QUERY_RECEIVED
assert events[0].data == { assert events[0].data == {
"request_id": REQ_ID, "request_id": REQ_ID,
"entity_id": "light.demo_light", "entity_id": [
"source": "cloud", "light.demo_light",
} "light.another_light",
assert events[1].event_type == EVENT_QUERY_RECEIVED "light.color_temp_light",
assert events[1].data == { "light.non_existing",
"request_id": REQ_ID, ],
"entity_id": "light.another_light",
"source": "cloud",
}
assert events[2].event_type == EVENT_QUERY_RECEIVED
assert events[2].data == {
"request_id": REQ_ID,
"entity_id": "light.color_temp_light",
"source": "cloud",
}
assert events[3].event_type == EVENT_QUERY_RECEIVED
assert events[3].data == {
"request_id": REQ_ID,
"entity_id": "light.non_existing",
"source": "cloud", "source": "cloud",
} }
@ -467,65 +454,25 @@ async def test_execute(hass):
}, },
} }
assert len(events) == 6 assert len(events) == 1
assert events[0].event_type == EVENT_COMMAND_RECEIVED assert events[0].event_type == EVENT_COMMAND_RECEIVED
assert events[0].data == { assert events[0].data == {
"request_id": REQ_ID, "request_id": REQ_ID,
"entity_id": "light.non_existing", "entity_id": [
"execution": { "light.non_existing",
"command": "action.devices.commands.OnOff", "light.ceiling_lights",
"params": {"on": True}, "light.kitchen_lights",
}, ],
"source": "cloud", "execution": [
} {
assert events[1].event_type == EVENT_COMMAND_RECEIVED "command": "action.devices.commands.OnOff",
assert events[1].data == { "params": {"on": True},
"request_id": REQ_ID, },
"entity_id": "light.non_existing", {
"execution": { "command": "action.devices.commands.BrightnessAbsolute",
"command": "action.devices.commands.BrightnessAbsolute", "params": {"brightness": 20},
"params": {"brightness": 20}, },
}, ],
"source": "cloud",
}
assert events[2].event_type == EVENT_COMMAND_RECEIVED
assert events[2].data == {
"request_id": REQ_ID,
"entity_id": "light.ceiling_lights",
"execution": {
"command": "action.devices.commands.OnOff",
"params": {"on": True},
},
"source": "cloud",
}
assert events[3].event_type == EVENT_COMMAND_RECEIVED
assert events[3].data == {
"request_id": REQ_ID,
"entity_id": "light.ceiling_lights",
"execution": {
"command": "action.devices.commands.BrightnessAbsolute",
"params": {"brightness": 20},
},
"source": "cloud",
}
assert events[4].event_type == EVENT_COMMAND_RECEIVED
assert events[4].data == {
"request_id": REQ_ID,
"entity_id": "light.kitchen_lights",
"execution": {
"command": "action.devices.commands.OnOff",
"params": {"on": True},
},
"source": "cloud",
}
assert events[5].event_type == EVENT_COMMAND_RECEIVED
assert events[5].data == {
"request_id": REQ_ID,
"entity_id": "light.kitchen_lights",
"execution": {
"command": "action.devices.commands.BrightnessAbsolute",
"params": {"brightness": 20},
},
"source": "cloud", "source": "cloud",
} }
@ -543,9 +490,8 @@ async def test_execute(hass):
"service": "turn_on", "service": "turn_on",
"service_data": {"brightness_pct": 20, "entity_id": "light.ceiling_lights"}, "service_data": {"brightness_pct": 20, "entity_id": "light.ceiling_lights"},
} }
assert service_events[0].context == events[2].context assert service_events[0].context == events[0].context
assert service_events[1].context == events[2].context assert service_events[1].context == events[0].context
assert service_events[1].context == events[3].context
assert service_events[2].data == { assert service_events[2].data == {
"domain": "light", "domain": "light",
"service": "turn_on", "service": "turn_on",
@ -556,9 +502,8 @@ async def test_execute(hass):
"service": "turn_on", "service": "turn_on",
"service_data": {"brightness_pct": 20, "entity_id": "light.kitchen_lights"}, "service_data": {"brightness_pct": 20, "entity_id": "light.kitchen_lights"},
} }
assert service_events[2].context == events[4].context assert service_events[2].context == events[0].context
assert service_events[3].context == events[4].context assert service_events[3].context == events[0].context
assert service_events[3].context == events[5].context
async def test_raising_error_trait(hass): async def test_raising_error_trait(hass):
@ -618,11 +563,13 @@ async def test_raising_error_trait(hass):
assert events[0].event_type == EVENT_COMMAND_RECEIVED assert events[0].event_type == EVENT_COMMAND_RECEIVED
assert events[0].data == { assert events[0].data == {
"request_id": REQ_ID, "request_id": REQ_ID,
"entity_id": "climate.bla", "entity_id": ["climate.bla"],
"execution": { "execution": [
"command": "action.devices.commands.ThermostatTemperatureSetpoint", {
"params": {"thermostatTemperatureSetpoint": 10}, "command": "action.devices.commands.ThermostatTemperatureSetpoint",
}, "params": {"thermostatTemperatureSetpoint": 10},
}
],
"source": "cloud", "source": "cloud",
} }