mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Add run_id to automation logbook event (#47980)
This commit is contained in:
parent
a4075d9e11
commit
f1c274b3dd
@ -281,6 +281,8 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
|
|||||||
}
|
}
|
||||||
if self.action_script.supports_max:
|
if self.action_script.supports_max:
|
||||||
attrs[ATTR_MAX] = self.action_script.max_runs
|
attrs[ATTR_MAX] = self.action_script.max_runs
|
||||||
|
if self._id is not None:
|
||||||
|
attrs[CONF_ID] = self._id
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -534,14 +536,6 @@ class AutomationEntity(ToggleEntity, RestoreEntity):
|
|||||||
variables,
|
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(
|
async def _async_process_config(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
@ -1,26 +1,29 @@
|
|||||||
"""Describe logbook events."""
|
"""Describe logbook events."""
|
||||||
|
from homeassistant.components.logbook import LazyEventPartialState
|
||||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_NAME
|
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
|
from . import ATTR_SOURCE, DOMAIN, EVENT_AUTOMATION_TRIGGERED
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@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."""
|
"""Describe logbook events."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_describe_logbook_event(event): # type: ignore
|
def async_describe_logbook_event(event: LazyEventPartialState): # type: ignore
|
||||||
"""Describe a logbook event."""
|
"""Describe a logbook event."""
|
||||||
data = event.data
|
data = event.data
|
||||||
message = "has been triggered"
|
message = "has been triggered"
|
||||||
if ATTR_SOURCE in data:
|
if ATTR_SOURCE in data:
|
||||||
message = f"{message} by {data[ATTR_SOURCE]}"
|
message = f"{message} by {data[ATTR_SOURCE]}"
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"name": data.get(ATTR_NAME),
|
"name": data.get(ATTR_NAME),
|
||||||
"message": message,
|
"message": message,
|
||||||
"source": data.get(ATTR_SOURCE),
|
"source": data.get(ATTR_SOURCE),
|
||||||
"entity_id": data.get(ATTR_ENTITY_ID),
|
"entity_id": data.get(ATTR_ENTITY_ID),
|
||||||
|
"context_id": event.context_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
async_describe_event(
|
async_describe_event(
|
||||||
|
@ -38,7 +38,7 @@ class AutomationTrace:
|
|||||||
self._action_trace: Optional[Dict[str, Deque[TraceElement]]] = None
|
self._action_trace: Optional[Dict[str, Deque[TraceElement]]] = None
|
||||||
self._condition_trace: Optional[Dict[str, Deque[TraceElement]]] = None
|
self._condition_trace: Optional[Dict[str, Deque[TraceElement]]] = None
|
||||||
self._config: Dict[str, Any] = config
|
self._config: Dict[str, Any] = config
|
||||||
self._context: Context = context
|
self.context: Context = context
|
||||||
self._error: Optional[Exception] = None
|
self._error: Optional[Exception] = None
|
||||||
self._state: str = "running"
|
self._state: str = "running"
|
||||||
self.run_id: str = str(next(self._run_ids))
|
self.run_id: str = str(next(self._run_ids))
|
||||||
@ -88,7 +88,7 @@ class AutomationTrace:
|
|||||||
"action_trace": action_traces,
|
"action_trace": action_traces,
|
||||||
"condition_trace": condition_traces,
|
"condition_trace": condition_traces,
|
||||||
"config": self._config,
|
"config": self._config,
|
||||||
"context": self._context,
|
"context": self.context,
|
||||||
"variables": self._variables,
|
"variables": self._variables,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -24,6 +24,7 @@ from homeassistant.helpers.script import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from .trace import (
|
from .trace import (
|
||||||
|
DATA_AUTOMATION_TRACE,
|
||||||
TraceJSONEncoder,
|
TraceJSONEncoder,
|
||||||
get_debug_trace,
|
get_debug_trace,
|
||||||
get_debug_traces,
|
get_debug_traces,
|
||||||
@ -38,6 +39,7 @@ def async_setup(hass: HomeAssistant) -> None:
|
|||||||
"""Set up the websocket API."""
|
"""Set up the websocket API."""
|
||||||
websocket_api.async_register_command(hass, websocket_automation_trace_get)
|
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_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_clear)
|
||||||
websocket_api.async_register_command(hass, websocket_automation_breakpoint_list)
|
websocket_api.async_register_command(hass, websocket_automation_breakpoint_list)
|
||||||
websocket_api.async_register_command(hass, websocket_automation_breakpoint_set)
|
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)
|
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
|
@callback
|
||||||
@websocket_api.require_admin
|
@websocket_api.require_admin
|
||||||
@websocket_api.websocket_command(
|
@websocket_api.websocket_command(
|
||||||
|
54
tests/components/automation/test_logbook.py
Normal file
54
tests/components/automation/test_logbook.py
Normal 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"
|
@ -65,6 +65,7 @@ async def test_get_automation_trace(hass, hass_ws_client):
|
|||||||
await async_setup_component(hass, "config", {})
|
await async_setup_component(hass, "config", {})
|
||||||
|
|
||||||
client = await hass_ws_client()
|
client = await hass_ws_client()
|
||||||
|
contexts = {}
|
||||||
|
|
||||||
# Trigger "sun" automation
|
# Trigger "sun" automation
|
||||||
context = Context()
|
context = Context()
|
||||||
@ -102,6 +103,10 @@ async def test_get_automation_trace(hass, hass_ws_client):
|
|||||||
assert trace["trigger"] == "event 'test_event'"
|
assert trace["trigger"] == "event 'test_event'"
|
||||||
assert trace["unique_id"] == "sun"
|
assert trace["unique_id"] == "sun"
|
||||||
assert trace["variables"]
|
assert trace["variables"]
|
||||||
|
contexts[trace["context"]["id"]] = {
|
||||||
|
"run_id": trace["run_id"],
|
||||||
|
"automation_id": trace["automation_id"],
|
||||||
|
}
|
||||||
|
|
||||||
# Trigger "moon" automation, with passing condition
|
# Trigger "moon" automation, with passing condition
|
||||||
hass.bus.async_fire("test_event2")
|
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["trigger"] == "event 'test_event2'"
|
||||||
assert trace["unique_id"] == "moon"
|
assert trace["unique_id"] == "moon"
|
||||||
assert trace["variables"]
|
assert trace["variables"]
|
||||||
|
contexts[trace["context"]["id"]] = {
|
||||||
|
"run_id": trace["run_id"],
|
||||||
|
"automation_id": trace["automation_id"],
|
||||||
|
}
|
||||||
|
|
||||||
# Trigger "moon" automation, with failing condition
|
# Trigger "moon" automation, with failing condition
|
||||||
hass.bus.async_fire("test_event3")
|
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["trigger"] == "event 'test_event3'"
|
||||||
assert trace["unique_id"] == "moon"
|
assert trace["unique_id"] == "moon"
|
||||||
assert trace["variables"]
|
assert trace["variables"]
|
||||||
|
contexts[trace["context"]["id"]] = {
|
||||||
|
"run_id": trace["run_id"],
|
||||||
|
"automation_id": trace["automation_id"],
|
||||||
|
}
|
||||||
|
|
||||||
# Trigger "moon" automation, with passing condition
|
# Trigger "moon" automation, with passing condition
|
||||||
hass.bus.async_fire("test_event2")
|
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["trigger"] == "event 'test_event2'"
|
||||||
assert trace["unique_id"] == "moon"
|
assert trace["unique_id"] == "moon"
|
||||||
assert trace["variables"]
|
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):
|
async def test_automation_trace_overflow(hass, hass_ws_client):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user