Add run_id to automation logbook event (#47980)

This commit is contained in:
Paulus Schoutsen 2021-03-16 14:37:26 -07:00 committed by GitHub
parent a4075d9e11
commit f1c274b3dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 13 deletions

View File

@ -281,6 +281,8 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
}
if self.action_script.supports_max:
attrs[ATTR_MAX] = self.action_script.max_runs
if self._id is not None:
attrs[CONF_ID] = self._id
return attrs
@property
@ -534,14 +536,6 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
variables,
)
@property
def extra_state_attributes(self):
"""Return automation attributes."""
if self._id is None:
return None
return {CONF_ID: self._id}
async def _async_process_config(
hass: HomeAssistant,

View File

@ -1,26 +1,29 @@
"""Describe logbook events."""
from homeassistant.components.logbook import LazyEventPartialState
from homeassistant.const import ATTR_ENTITY_ID, ATTR_NAME
from homeassistant.core import callback
from homeassistant.core import HomeAssistant, callback
from . import ATTR_SOURCE, DOMAIN, EVENT_AUTOMATION_TRIGGERED
@callback
def async_describe_events(hass, async_describe_event): # type: ignore
def async_describe_events(hass: HomeAssistant, async_describe_event): # type: ignore
"""Describe logbook events."""
@callback
def async_describe_logbook_event(event): # type: ignore
def async_describe_logbook_event(event: LazyEventPartialState): # type: ignore
"""Describe a logbook event."""
data = event.data
message = "has been triggered"
if ATTR_SOURCE in data:
message = f"{message} by {data[ATTR_SOURCE]}"
return {
"name": data.get(ATTR_NAME),
"message": message,
"source": data.get(ATTR_SOURCE),
"entity_id": data.get(ATTR_ENTITY_ID),
"context_id": event.context_id,
}
async_describe_event(

View File

@ -38,7 +38,7 @@ class AutomationTrace:
self._action_trace: Optional[Dict[str, Deque[TraceElement]]] = None
self._condition_trace: Optional[Dict[str, Deque[TraceElement]]] = None
self._config: Dict[str, Any] = config
self._context: Context = context
self.context: Context = context
self._error: Optional[Exception] = None
self._state: str = "running"
self.run_id: str = str(next(self._run_ids))
@ -88,7 +88,7 @@ class AutomationTrace:
"action_trace": action_traces,
"condition_trace": condition_traces,
"config": self._config,
"context": self._context,
"context": self.context,
"variables": self._variables,
}
)

View File

@ -24,6 +24,7 @@ from homeassistant.helpers.script import (
)
from .trace import (
DATA_AUTOMATION_TRACE,
TraceJSONEncoder,
get_debug_trace,
get_debug_traces,
@ -38,6 +39,7 @@ def async_setup(hass: HomeAssistant) -> None:
"""Set up the websocket API."""
websocket_api.async_register_command(hass, websocket_automation_trace_get)
websocket_api.async_register_command(hass, websocket_automation_trace_list)
websocket_api.async_register_command(hass, websocket_automation_trace_contexts)
websocket_api.async_register_command(hass, websocket_automation_breakpoint_clear)
websocket_api.async_register_command(hass, websocket_automation_breakpoint_list)
websocket_api.async_register_command(hass, websocket_automation_breakpoint_set)
@ -86,6 +88,34 @@ def websocket_automation_trace_list(hass, connection, msg):
connection.send_result(msg["id"], automation_traces)
@callback
@websocket_api.require_admin
@websocket_api.websocket_command(
{
vol.Required("type"): "automation/trace/contexts",
vol.Optional("automation_id"): str,
}
)
def websocket_automation_trace_contexts(hass, connection, msg):
"""Retrieve contexts we have traces for."""
automation_id = msg.get("automation_id")
if automation_id is not None:
values = {
automation_id: hass.data[DATA_AUTOMATION_TRACE].get(automation_id, {})
}
else:
values = hass.data[DATA_AUTOMATION_TRACE]
contexts = {
trace.context.id: {"run_id": trace.run_id, "automation_id": automation_id}
for automation_id, traces in values.items()
for trace in traces.values()
}
connection.send_result(msg["id"], contexts)
@callback
@websocket_api.require_admin
@websocket_api.websocket_command(

View File

@ -0,0 +1,54 @@
"""Test automation logbook."""
from homeassistant.components import automation, logbook
from homeassistant.core import Context
from homeassistant.setup import async_setup_component
from tests.components.logbook.test_init import MockLazyEventPartialState
async def test_humanify_automation_trigger_event(hass):
"""Test humanifying Shelly click event."""
hass.config.components.add("recorder")
assert await async_setup_component(hass, "automation", {})
assert await async_setup_component(hass, "logbook", {})
entity_attr_cache = logbook.EntityAttributeCache(hass)
context = Context()
event1, event2 = list(
logbook.humanify(
hass,
[
MockLazyEventPartialState(
automation.EVENT_AUTOMATION_TRIGGERED,
{
"name": "Bla",
"entity_id": "automation.bla",
"source": "state change of input_boolean.yo",
},
context=context,
),
MockLazyEventPartialState(
automation.EVENT_AUTOMATION_TRIGGERED,
{
"name": "Bla",
"entity_id": "automation.bla",
},
context=context,
),
],
entity_attr_cache,
{},
)
)
assert event1["name"] == "Bla"
assert event1["message"] == "has been triggered by state change of input_boolean.yo"
assert event1["source"] == "state change of input_boolean.yo"
assert event1["context_id"] == context.id
assert event1["entity_id"] == "automation.bla"
assert event2["name"] == "Bla"
assert event2["message"] == "has been triggered"
assert event2["source"] is None
assert event2["context_id"] == context.id
assert event2["entity_id"] == "automation.bla"

View File

@ -65,6 +65,7 @@ async def test_get_automation_trace(hass, hass_ws_client):
await async_setup_component(hass, "config", {})
client = await hass_ws_client()
contexts = {}
# Trigger "sun" automation
context = Context()
@ -102,6 +103,10 @@ async def test_get_automation_trace(hass, hass_ws_client):
assert trace["trigger"] == "event 'test_event'"
assert trace["unique_id"] == "sun"
assert trace["variables"]
contexts[trace["context"]["id"]] = {
"run_id": trace["run_id"],
"automation_id": trace["automation_id"],
}
# Trigger "moon" automation, with passing condition
hass.bus.async_fire("test_event2")
@ -139,6 +144,10 @@ async def test_get_automation_trace(hass, hass_ws_client):
assert trace["trigger"] == "event 'test_event2'"
assert trace["unique_id"] == "moon"
assert trace["variables"]
contexts[trace["context"]["id"]] = {
"run_id": trace["run_id"],
"automation_id": trace["automation_id"],
}
# Trigger "moon" automation, with failing condition
hass.bus.async_fire("test_event3")
@ -173,6 +182,10 @@ async def test_get_automation_trace(hass, hass_ws_client):
assert trace["trigger"] == "event 'test_event3'"
assert trace["unique_id"] == "moon"
assert trace["variables"]
contexts[trace["context"]["id"]] = {
"run_id": trace["run_id"],
"automation_id": trace["automation_id"],
}
# Trigger "moon" automation, with passing condition
hass.bus.async_fire("test_event2")
@ -210,6 +223,16 @@ async def test_get_automation_trace(hass, hass_ws_client):
assert trace["trigger"] == "event 'test_event2'"
assert trace["unique_id"] == "moon"
assert trace["variables"]
contexts[trace["context"]["id"]] = {
"run_id": trace["run_id"],
"automation_id": trace["automation_id"],
}
# Check contexts
await client.send_json({"id": next_id(), "type": "automation/trace/contexts"})
response = await client.receive_json()
assert response["success"]
assert response["result"] == contexts
async def test_automation_trace_overflow(hass, hass_ws_client):