Add additional context data to logbook events (#71721)
This commit is contained in:
parent
1d9fb4bca8
commit
24a0007785
12 changed files with 254 additions and 124 deletions
|
@ -15,7 +15,7 @@ def async_describe_events(hass: HomeAssistant, async_describe_event): # type: i
|
|||
def async_describe_logbook_event(event: LazyEventPartialState): # type: ignore[no-untyped-def]
|
||||
"""Describe a logbook event."""
|
||||
data = event.data
|
||||
message = "has been triggered"
|
||||
message = "triggered"
|
||||
if ATTR_SOURCE in data:
|
||||
message = f"{message} by {data[ATTR_SOURCE]}"
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ def async_describe_events(
|
|||
|
||||
return {
|
||||
"name": f"{deconz_alarm_event.device.name}",
|
||||
"message": f"fired event '{data}'.",
|
||||
"message": f"fired event '{data}'",
|
||||
}
|
||||
|
||||
@callback
|
||||
|
@ -158,26 +158,26 @@ def async_describe_events(
|
|||
if not data:
|
||||
return {
|
||||
"name": f"{deconz_event.device.name}",
|
||||
"message": "fired an unknown event.",
|
||||
"message": "fired an unknown event",
|
||||
}
|
||||
|
||||
# No device event match
|
||||
if not action:
|
||||
return {
|
||||
"name": f"{deconz_event.device.name}",
|
||||
"message": f"fired event '{data}'.",
|
||||
"message": f"fired event '{data}'",
|
||||
}
|
||||
|
||||
# Gesture event
|
||||
if not interface:
|
||||
return {
|
||||
"name": f"{deconz_event.device.name}",
|
||||
"message": f"fired event '{ACTIONS[action]}'.",
|
||||
"message": f"fired event '{ACTIONS[action]}'",
|
||||
}
|
||||
|
||||
return {
|
||||
"name": f"{deconz_event.device.name}",
|
||||
"message": f"'{ACTIONS[action]}' event for '{INTERFACES[interface]}' was fired.",
|
||||
"message": f"'{ACTIONS[action]}' event for '{INTERFACES[interface]}' was fired",
|
||||
}
|
||||
|
||||
async_describe_event(
|
||||
|
|
|
@ -17,7 +17,7 @@ def async_describe_events(hass, async_describe_event):
|
|||
|
||||
return {
|
||||
"name": "Doorbird",
|
||||
"message": f"Event {event.event_type} was fired.",
|
||||
"message": f"Event {event.event_type} was fired",
|
||||
"entity_id": hass.data[DOMAIN][DOOR_STATION_EVENT_ENTITY_IDS].get(
|
||||
doorbird_event, event.data.get(ATTR_ENTITY_ID)
|
||||
),
|
||||
|
|
39
homeassistant/components/homeassistant/logbook.py
Normal file
39
homeassistant/components/homeassistant/logbook.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
"""Describe homeassistant logbook events."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
|
||||
from homeassistant.components.logbook import (
|
||||
LOGBOOK_ENTRY_ICON,
|
||||
LOGBOOK_ENTRY_MESSAGE,
|
||||
LOGBOOK_ENTRY_NAME,
|
||||
)
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import Event, HomeAssistant, callback
|
||||
|
||||
from . import DOMAIN
|
||||
|
||||
EVENT_TO_NAME = {
|
||||
EVENT_HOMEASSISTANT_STOP: "stopped",
|
||||
EVENT_HOMEASSISTANT_START: "started",
|
||||
}
|
||||
|
||||
|
||||
@callback
|
||||
def async_describe_events(
|
||||
hass: HomeAssistant,
|
||||
async_describe_event: Callable[[str, str, Callable[[Event], dict[str, str]]], None],
|
||||
) -> None:
|
||||
"""Describe logbook events."""
|
||||
|
||||
@callback
|
||||
def async_describe_hass_event(event: Event) -> dict[str, str]:
|
||||
"""Describe homeassisant logbook event."""
|
||||
return {
|
||||
LOGBOOK_ENTRY_NAME: "Home Assistant",
|
||||
LOGBOOK_ENTRY_MESSAGE: EVENT_TO_NAME[event.event_type],
|
||||
LOGBOOK_ENTRY_ICON: "mdi:home-assistant",
|
||||
}
|
||||
|
||||
async_describe_event(DOMAIN, EVENT_HOMEASSISTANT_STOP, async_describe_hass_event)
|
||||
async_describe_event(DOMAIN, EVENT_HOMEASSISTANT_START, async_describe_hass_event)
|
|
@ -37,13 +37,10 @@ from homeassistant.const import (
|
|||
ATTR_NAME,
|
||||
ATTR_SERVICE,
|
||||
EVENT_CALL_SERVICE,
|
||||
EVENT_HOMEASSISTANT_START,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
EVENT_LOGBOOK_ENTRY,
|
||||
EVENT_STATE_CHANGED,
|
||||
)
|
||||
from homeassistant.core import (
|
||||
DOMAIN as HA_DOMAIN,
|
||||
Context,
|
||||
Event,
|
||||
HomeAssistant,
|
||||
|
@ -70,7 +67,6 @@ from .queries import statement_for_request
|
|||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
FRIENDLY_NAME_JSON_EXTRACT = re.compile('"friendly_name": ?"([^"]+)"')
|
||||
ENTITY_ID_JSON_EXTRACT = re.compile('"entity_id": ?"([^"]+)"')
|
||||
DOMAIN_JSON_EXTRACT = re.compile('"domain": ?"([^"]+)"')
|
||||
|
@ -79,19 +75,28 @@ ATTR_MESSAGE = "message"
|
|||
|
||||
DOMAIN = "logbook"
|
||||
|
||||
HA_DOMAIN_ENTITY_ID = f"{HA_DOMAIN}._"
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{DOMAIN: INCLUDE_EXCLUDE_BASE_FILTER_SCHEMA}, extra=vol.ALLOW_EXTRA
|
||||
)
|
||||
|
||||
HOMEASSISTANT_EVENTS = {EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP}
|
||||
CONTEXT_USER_ID = "context_user_id"
|
||||
CONTEXT_ENTITY_ID = "context_entity_id"
|
||||
CONTEXT_ENTITY_ID_NAME = "context_entity_id_name"
|
||||
CONTEXT_EVENT_TYPE = "context_event_type"
|
||||
CONTEXT_DOMAIN = "context_domain"
|
||||
CONTEXT_SERVICE = "context_service"
|
||||
CONTEXT_NAME = "context_name"
|
||||
CONTEXT_MESSAGE = "context_message"
|
||||
|
||||
ALL_EVENT_TYPES_EXCEPT_STATE_CHANGED = (
|
||||
EVENT_LOGBOOK_ENTRY,
|
||||
EVENT_CALL_SERVICE,
|
||||
*HOMEASSISTANT_EVENTS,
|
||||
)
|
||||
LOGBOOK_ENTRY_DOMAIN = "domain"
|
||||
LOGBOOK_ENTRY_ENTITY_ID = "entity_id"
|
||||
LOGBOOK_ENTRY_ICON = "icon"
|
||||
LOGBOOK_ENTRY_MESSAGE = "message"
|
||||
LOGBOOK_ENTRY_NAME = "name"
|
||||
LOGBOOK_ENTRY_STATE = "state"
|
||||
LOGBOOK_ENTRY_WHEN = "when"
|
||||
|
||||
ALL_EVENT_TYPES_EXCEPT_STATE_CHANGED = {EVENT_LOGBOOK_ENTRY, EVENT_CALL_SERVICE}
|
||||
|
||||
SCRIPT_AUTOMATION_EVENTS = {EVENT_AUTOMATION_TRIGGERED, EVENT_SCRIPT_STARTED}
|
||||
|
||||
|
@ -133,12 +138,12 @@ def async_log_entry(
|
|||
context: Context | None = None,
|
||||
) -> None:
|
||||
"""Add an entry to the logbook."""
|
||||
data = {ATTR_NAME: name, ATTR_MESSAGE: message}
|
||||
data = {LOGBOOK_ENTRY_NAME: name, LOGBOOK_ENTRY_MESSAGE: message}
|
||||
|
||||
if domain is not None:
|
||||
data[ATTR_DOMAIN] = domain
|
||||
data[LOGBOOK_ENTRY_DOMAIN] = domain
|
||||
if entity_id is not None:
|
||||
data[ATTR_ENTITY_ID] = entity_id
|
||||
data[LOGBOOK_ENTRY_ENTITY_ID] = entity_id
|
||||
hass.bus.async_fire(EVENT_LOGBOOK_ENTRY, data, context=context)
|
||||
|
||||
|
||||
|
@ -162,7 +167,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
|
||||
message.hass = hass
|
||||
message = message.async_render(parse_result=False)
|
||||
async_log_entry(hass, name, message, domain, entity_id)
|
||||
async_log_entry(hass, name, message, domain, entity_id, service.context)
|
||||
|
||||
frontend.async_register_built_in_panel(
|
||||
hass, "logbook", "logbook", "hass:format-list-bulleted-type"
|
||||
|
@ -375,13 +380,13 @@ def _humanify(
|
|||
continue
|
||||
|
||||
data = {
|
||||
"when": format_time(row),
|
||||
"name": entity_name_cache.get(entity_id, row),
|
||||
"state": row.state,
|
||||
"entity_id": entity_id,
|
||||
LOGBOOK_ENTRY_WHEN: format_time(row),
|
||||
LOGBOOK_ENTRY_NAME: entity_name_cache.get(entity_id, row),
|
||||
LOGBOOK_ENTRY_STATE: row.state,
|
||||
LOGBOOK_ENTRY_ENTITY_ID: entity_id,
|
||||
}
|
||||
if icon := _row_attributes_extract(row, ICON_JSON_EXTRACT):
|
||||
data["icon"] = icon
|
||||
data[LOGBOOK_ENTRY_ICON] = icon
|
||||
|
||||
context_augmenter.augment(data, entity_id, row)
|
||||
yield data
|
||||
|
@ -389,26 +394,11 @@ def _humanify(
|
|||
elif event_type in external_events:
|
||||
domain, describe_event = external_events[event_type]
|
||||
data = describe_event(event_cache.get(row))
|
||||
data["when"] = format_time(row)
|
||||
data["domain"] = domain
|
||||
data[LOGBOOK_ENTRY_WHEN] = format_time(row)
|
||||
data[LOGBOOK_ENTRY_DOMAIN] = domain
|
||||
context_augmenter.augment(data, data.get(ATTR_ENTITY_ID), row)
|
||||
yield data
|
||||
|
||||
elif event_type == EVENT_HOMEASSISTANT_START:
|
||||
yield {
|
||||
"when": format_time(row),
|
||||
"name": "Home Assistant",
|
||||
"message": "started",
|
||||
"domain": HA_DOMAIN,
|
||||
}
|
||||
elif event_type == EVENT_HOMEASSISTANT_STOP:
|
||||
yield {
|
||||
"when": format_time(row),
|
||||
"name": "Home Assistant",
|
||||
"message": "stopped",
|
||||
"domain": HA_DOMAIN,
|
||||
}
|
||||
|
||||
elif event_type == EVENT_LOGBOOK_ENTRY:
|
||||
event = event_cache.get(row)
|
||||
event_data = event.data
|
||||
|
@ -419,11 +409,11 @@ def _humanify(
|
|||
domain = split_entity_id(str(entity_id))[0]
|
||||
|
||||
data = {
|
||||
"when": format_time(row),
|
||||
"name": event_data.get(ATTR_NAME),
|
||||
"message": event_data.get(ATTR_MESSAGE),
|
||||
"domain": domain,
|
||||
"entity_id": entity_id,
|
||||
LOGBOOK_ENTRY_WHEN: format_time(row),
|
||||
LOGBOOK_ENTRY_NAME: event_data.get(ATTR_NAME),
|
||||
LOGBOOK_ENTRY_MESSAGE: event_data.get(ATTR_MESSAGE),
|
||||
LOGBOOK_ENTRY_DOMAIN: domain,
|
||||
LOGBOOK_ENTRY_ENTITY_ID: entity_id,
|
||||
}
|
||||
context_augmenter.augment(data, entity_id, row)
|
||||
yield data
|
||||
|
@ -505,9 +495,6 @@ def _keep_row(
|
|||
row: Row,
|
||||
entities_filter: EntityFilter | Callable[[str], bool] | None = None,
|
||||
) -> bool:
|
||||
if event_type in HOMEASSISTANT_EVENTS:
|
||||
return entities_filter is None or entities_filter(HA_DOMAIN_ENTITY_ID)
|
||||
|
||||
if entity_id := _row_event_data_extract(row, ENTITY_ID_JSON_EXTRACT):
|
||||
return entities_filter is None or entities_filter(entity_id)
|
||||
|
||||
|
@ -544,7 +531,7 @@ class ContextAugmenter:
|
|||
def augment(self, data: dict[str, Any], entity_id: str | None, row: Row) -> None:
|
||||
"""Augment data from the row and cache."""
|
||||
if context_user_id := row.context_user_id:
|
||||
data["context_user_id"] = context_user_id
|
||||
data[CONTEXT_USER_ID] = context_user_id
|
||||
|
||||
if not (context_row := self.context_lookup.get(row.context_id)):
|
||||
return
|
||||
|
@ -567,43 +554,40 @@ class ContextAugmenter:
|
|||
|
||||
# State change
|
||||
if context_entity_id := context_row.entity_id:
|
||||
data["context_entity_id"] = context_entity_id
|
||||
data["context_entity_id_name"] = self.entity_name_cache.get(
|
||||
data[CONTEXT_ENTITY_ID] = context_entity_id
|
||||
data[CONTEXT_ENTITY_ID_NAME] = self.entity_name_cache.get(
|
||||
context_entity_id, context_row
|
||||
)
|
||||
data["context_event_type"] = event_type
|
||||
data[CONTEXT_EVENT_TYPE] = event_type
|
||||
return
|
||||
|
||||
# Call service
|
||||
if event_type == EVENT_CALL_SERVICE:
|
||||
event = self.event_cache.get(context_row)
|
||||
event_data = event.data
|
||||
data["context_domain"] = event_data.get(ATTR_DOMAIN)
|
||||
data["context_service"] = event_data.get(ATTR_SERVICE)
|
||||
data["context_event_type"] = event_type
|
||||
data[CONTEXT_DOMAIN] = event_data.get(ATTR_DOMAIN)
|
||||
data[CONTEXT_SERVICE] = event_data.get(ATTR_SERVICE)
|
||||
data[CONTEXT_EVENT_TYPE] = event_type
|
||||
return
|
||||
|
||||
if not entity_id:
|
||||
if event_type not in self.external_events:
|
||||
return
|
||||
|
||||
attr_entity_id = _row_event_data_extract(context_row, ENTITY_ID_JSON_EXTRACT)
|
||||
if attr_entity_id is None or (
|
||||
event_type in SCRIPT_AUTOMATION_EVENTS and attr_entity_id == entity_id
|
||||
):
|
||||
domain, describe_event = self.external_events[event_type]
|
||||
data[CONTEXT_EVENT_TYPE] = event_type
|
||||
data[CONTEXT_DOMAIN] = domain
|
||||
event = self.event_cache.get(context_row)
|
||||
described = describe_event(event)
|
||||
if name := described.get(ATTR_NAME):
|
||||
data[CONTEXT_NAME] = name
|
||||
if message := described.get(ATTR_MESSAGE):
|
||||
data[CONTEXT_MESSAGE] = message
|
||||
if not (attr_entity_id := described.get(ATTR_ENTITY_ID)):
|
||||
return
|
||||
|
||||
data["context_entity_id"] = attr_entity_id
|
||||
data["context_entity_id_name"] = self.entity_name_cache.get(
|
||||
data[CONTEXT_ENTITY_ID] = attr_entity_id
|
||||
data[CONTEXT_ENTITY_ID_NAME] = self.entity_name_cache.get(
|
||||
attr_entity_id, context_row
|
||||
)
|
||||
data["context_event_type"] = event_type
|
||||
|
||||
if event_type in self.external_events:
|
||||
domain, describe_event = self.external_events[event_type]
|
||||
data["context_domain"] = domain
|
||||
event = self.event_cache.get(context_row)
|
||||
if name := describe_event(event).get(ATTR_NAME):
|
||||
data["context_name"] = name
|
||||
|
||||
|
||||
def _is_sensor_continuous(
|
||||
|
@ -627,11 +611,14 @@ def _is_sensor_continuous(
|
|||
|
||||
def _rows_match(row: Row, other_row: Row) -> bool:
|
||||
"""Check of rows match by using the same method as Events __hash__."""
|
||||
return bool(
|
||||
row.event_type == other_row.event_type
|
||||
and row.context_id == other_row.context_id
|
||||
and row.time_fired == other_row.time_fired
|
||||
)
|
||||
if (
|
||||
(state_id := row.state_id) is not None
|
||||
and state_id == other_row.state_id
|
||||
or (event_id := row.event_id) is not None
|
||||
and event_id == other_row.event_id
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _row_event_data_extract(row: Row, extractor: re.Pattern) -> str | None:
|
||||
|
|
|
@ -33,6 +33,7 @@ UNIT_OF_MEASUREMENT_JSON_LIKE = f"%{UNIT_OF_MEASUREMENT_JSON}%"
|
|||
|
||||
|
||||
EVENT_COLUMNS = (
|
||||
Events.event_id.label("event_id"),
|
||||
Events.event_type.label("event_type"),
|
||||
Events.event_data.label("event_data"),
|
||||
Events.time_fired.label("time_fired"),
|
||||
|
@ -42,6 +43,7 @@ EVENT_COLUMNS = (
|
|||
)
|
||||
|
||||
STATE_COLUMNS = (
|
||||
States.state_id.label("state_id"),
|
||||
States.state.label("state"),
|
||||
States.entity_id.label("entity_id"),
|
||||
States.attributes.label("attributes"),
|
||||
|
@ -49,6 +51,7 @@ STATE_COLUMNS = (
|
|||
)
|
||||
|
||||
EMPTY_STATE_COLUMNS = (
|
||||
literal(value=None, type_=sqlalchemy.String).label("state_id"),
|
||||
literal(value=None, type_=sqlalchemy.String).label("state"),
|
||||
literal(value=None, type_=sqlalchemy.String).label("entity_id"),
|
||||
literal(value=None, type_=sqlalchemy.Text).label("attributes"),
|
||||
|
@ -294,6 +297,7 @@ def _select_states(start_day: dt, end_day: dt) -> Select:
|
|||
old_state = aliased(States, name="old_state")
|
||||
return (
|
||||
select(
|
||||
literal(value=None, type_=sqlalchemy.Text).label("event_id"),
|
||||
literal(value=EVENT_STATE_CHANGED, type_=sqlalchemy.String).label(
|
||||
"event_type"
|
||||
),
|
||||
|
|
|
@ -49,7 +49,7 @@ def async_describe_events(
|
|||
|
||||
return {
|
||||
"name": "Shelly",
|
||||
"message": f"'{click_type}' click event for {input_name} Input was fired.",
|
||||
"message": f"'{click_type}' click event for {input_name} Input was fired",
|
||||
}
|
||||
|
||||
async_describe_event(DOMAIN, EVENT_SHELLY_CLICK, async_describe_shelly_click_event)
|
||||
|
|
|
@ -1243,12 +1243,12 @@ async def test_logbook_humanify_automation_triggered_event(hass):
|
|||
|
||||
assert event1["name"] == "Hello Automation"
|
||||
assert event1["domain"] == "automation"
|
||||
assert event1["message"] == "has been triggered"
|
||||
assert event1["message"] == "triggered"
|
||||
assert event1["entity_id"] == "automation.hello"
|
||||
|
||||
assert event2["name"] == "Bye Automation"
|
||||
assert event2["domain"] == "automation"
|
||||
assert event2["message"] == "has been triggered by source of trigger"
|
||||
assert event2["message"] == "triggered by source of trigger"
|
||||
assert event2["entity_id"] == "automation.bye"
|
||||
|
||||
|
||||
|
|
|
@ -37,13 +37,13 @@ async def test_humanify_automation_trigger_event(hass):
|
|||
)
|
||||
|
||||
assert event1["name"] == "Bla"
|
||||
assert event1["message"] == "has been triggered by state change of input_boolean.yo"
|
||||
assert event1["message"] == "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["message"] == "triggered"
|
||||
assert event2["source"] is None
|
||||
assert event2["context_id"] == context.id
|
||||
assert event2["entity_id"] == "automation.bla"
|
||||
|
|
|
@ -85,7 +85,7 @@ async def test_humanifying_deconz_alarm_event(hass, aioclient_mock):
|
|||
|
||||
assert events[0]["name"] == "Keypad"
|
||||
assert events[0]["domain"] == "deconz"
|
||||
assert events[0]["message"] == "fired event 'armed_away'."
|
||||
assert events[0]["message"] == "fired event 'armed_away'"
|
||||
|
||||
|
||||
async def test_humanifying_deconz_event(hass, aioclient_mock):
|
||||
|
@ -214,20 +214,20 @@ async def test_humanifying_deconz_event(hass, aioclient_mock):
|
|||
|
||||
assert events[0]["name"] == "Switch 1"
|
||||
assert events[0]["domain"] == "deconz"
|
||||
assert events[0]["message"] == "fired event '2000'."
|
||||
assert events[0]["message"] == "fired event '2000'"
|
||||
|
||||
assert events[1]["name"] == "Hue remote"
|
||||
assert events[1]["domain"] == "deconz"
|
||||
assert events[1]["message"] == "'Long press' event for 'Dim up' was fired."
|
||||
assert events[1]["message"] == "'Long press' event for 'Dim up' was fired"
|
||||
|
||||
assert events[2]["name"] == "Xiaomi cube"
|
||||
assert events[2]["domain"] == "deconz"
|
||||
assert events[2]["message"] == "fired event 'Shake'."
|
||||
assert events[2]["message"] == "fired event 'Shake'"
|
||||
|
||||
assert events[3]["name"] == "Xiaomi cube"
|
||||
assert events[3]["domain"] == "deconz"
|
||||
assert events[3]["message"] == "fired event 'unsupported_gesture'."
|
||||
assert events[3]["message"] == "fired event 'unsupported_gesture'"
|
||||
|
||||
assert events[4]["name"] == "Faulty event"
|
||||
assert events[4]["domain"] == "deconz"
|
||||
assert events[4]["message"] == "fired an unknown event."
|
||||
assert events[4]["message"] == "fired an unknown event"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"""The tests for the logbook component."""
|
||||
# pylint: disable=protected-access,invalid-name
|
||||
import asyncio
|
||||
import collections
|
||||
from datetime import datetime, timedelta
|
||||
from http import HTTPStatus
|
||||
|
@ -208,8 +209,10 @@ async def test_filter_sensor(hass_: ha.HomeAssistant, hass_client):
|
|||
_assert_entry(entries[2], name="ble", entity_id=entity_id4, state="10")
|
||||
|
||||
|
||||
def test_home_assistant_start_stop_not_grouped(hass_):
|
||||
async def test_home_assistant_start_stop_not_grouped(hass_):
|
||||
"""Test if HA start and stop events are no longer grouped."""
|
||||
await async_setup_component(hass_, "homeassistant", {})
|
||||
await hass_.async_block_till_done()
|
||||
entries = mock_humanify(
|
||||
hass_,
|
||||
(
|
||||
|
@ -223,8 +226,10 @@ def test_home_assistant_start_stop_not_grouped(hass_):
|
|||
assert_entry(entries[1], name="Home Assistant", message="started", domain=ha.DOMAIN)
|
||||
|
||||
|
||||
def test_home_assistant_start(hass_):
|
||||
async def test_home_assistant_start(hass_):
|
||||
"""Test if HA start is not filtered or converted into a restart."""
|
||||
await async_setup_component(hass_, "homeassistant", {})
|
||||
await hass_.async_block_till_done()
|
||||
entity_id = "switch.bla"
|
||||
pointA = dt_util.utcnow()
|
||||
|
||||
|
@ -604,9 +609,12 @@ async def test_logbook_view_end_time_entity(hass, hass_client, recorder_mock):
|
|||
|
||||
async def test_logbook_entity_filter_with_automations(hass, hass_client, recorder_mock):
|
||||
"""Test the logbook view with end_time and entity with automations and scripts."""
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await async_setup_component(hass, "automation", {})
|
||||
await async_setup_component(hass, "script", {})
|
||||
await asyncio.gather(
|
||||
*[
|
||||
async_setup_component(hass, comp, {})
|
||||
for comp in ("homeassistant", "logbook", "automation", "script")
|
||||
]
|
||||
)
|
||||
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
|
@ -749,7 +757,12 @@ async def test_filter_continuous_sensor_values(
|
|||
|
||||
async def test_exclude_new_entities(hass, hass_client, recorder_mock, set_utc):
|
||||
"""Test if events are excluded on first update."""
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await asyncio.gather(
|
||||
*[
|
||||
async_setup_component(hass, comp, {})
|
||||
for comp in ("homeassistant", "logbook")
|
||||
]
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
entity_id = "climate.bla"
|
||||
|
@ -781,7 +794,12 @@ async def test_exclude_new_entities(hass, hass_client, recorder_mock, set_utc):
|
|||
|
||||
async def test_exclude_removed_entities(hass, hass_client, recorder_mock, set_utc):
|
||||
"""Test if events are excluded on last update."""
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await asyncio.gather(
|
||||
*[
|
||||
async_setup_component(hass, comp, {})
|
||||
for comp in ("homeassistant", "logbook")
|
||||
]
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
entity_id = "climate.bla"
|
||||
|
@ -820,7 +838,12 @@ async def test_exclude_removed_entities(hass, hass_client, recorder_mock, set_ut
|
|||
|
||||
async def test_exclude_attribute_changes(hass, hass_client, recorder_mock, set_utc):
|
||||
"""Test if events of attribute changes are filtered."""
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await asyncio.gather(
|
||||
*[
|
||||
async_setup_component(hass, comp, {})
|
||||
for comp in ("homeassistant", "logbook")
|
||||
]
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
@ -855,9 +878,12 @@ async def test_exclude_attribute_changes(hass, hass_client, recorder_mock, set_u
|
|||
|
||||
async def test_logbook_entity_context_id(hass, recorder_mock, hass_client):
|
||||
"""Test the logbook view with end_time and entity with automations and scripts."""
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await async_setup_component(hass, "automation", {})
|
||||
await async_setup_component(hass, "script", {})
|
||||
await asyncio.gather(
|
||||
*[
|
||||
async_setup_component(hass, comp, {})
|
||||
for comp in ("homeassistant", "logbook", "automation", "script")
|
||||
]
|
||||
)
|
||||
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
|
@ -1004,9 +1030,12 @@ async def test_logbook_context_id_automation_script_started_manually(
|
|||
hass, recorder_mock, hass_client
|
||||
):
|
||||
"""Test the logbook populates context_ids for scripts and automations started manually."""
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await async_setup_component(hass, "automation", {})
|
||||
await async_setup_component(hass, "script", {})
|
||||
await asyncio.gather(
|
||||
*[
|
||||
async_setup_component(hass, comp, {})
|
||||
for comp in ("homeassistant", "logbook", "automation", "script")
|
||||
]
|
||||
)
|
||||
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
|
@ -1032,6 +1061,19 @@ async def test_logbook_context_id_automation_script_started_manually(
|
|||
)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
||||
script_2_context = ha.Context(
|
||||
id="1234",
|
||||
user_id="b400facee45711eaa9308bfd3d19e474",
|
||||
)
|
||||
hass.bus.async_fire(
|
||||
EVENT_SCRIPT_STARTED,
|
||||
{ATTR_NAME: "Mock script"},
|
||||
context=script_2_context,
|
||||
)
|
||||
hass.states.async_set("switch.new", STATE_ON, context=script_2_context)
|
||||
hass.states.async_set("switch.new", STATE_OFF, context=script_2_context)
|
||||
|
||||
await hass.async_block_till_done()
|
||||
await async_wait_recording_done(hass)
|
||||
|
||||
|
@ -1061,12 +1103,28 @@ async def test_logbook_context_id_automation_script_started_manually(
|
|||
|
||||
assert json_dict[2]["domain"] == "homeassistant"
|
||||
|
||||
assert json_dict[3]["entity_id"] is None
|
||||
assert json_dict[3]["name"] == "Mock script"
|
||||
assert "context_entity_id" not in json_dict[1]
|
||||
assert json_dict[3]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
|
||||
assert json_dict[3]["context_id"] == "1234"
|
||||
|
||||
assert json_dict[4]["entity_id"] == "switch.new"
|
||||
assert json_dict[4]["state"] == "off"
|
||||
assert "context_entity_id" not in json_dict[1]
|
||||
assert json_dict[4]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
|
||||
assert json_dict[4]["context_event_type"] == "script_started"
|
||||
assert json_dict[4]["context_domain"] == "script"
|
||||
|
||||
|
||||
async def test_logbook_entity_context_parent_id(hass, hass_client, recorder_mock):
|
||||
"""Test the logbook view links events via context parent_id."""
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await async_setup_component(hass, "automation", {})
|
||||
await async_setup_component(hass, "script", {})
|
||||
await asyncio.gather(
|
||||
*[
|
||||
async_setup_component(hass, comp, {})
|
||||
for comp in ("homeassistant", "logbook", "automation", "script")
|
||||
]
|
||||
)
|
||||
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
|
@ -1240,7 +1298,13 @@ async def test_logbook_entity_context_parent_id(hass, hass_client, recorder_mock
|
|||
|
||||
async def test_logbook_context_from_template(hass, hass_client, recorder_mock):
|
||||
"""Test the logbook view with end_time and entity with automations and scripts."""
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await asyncio.gather(
|
||||
*[
|
||||
async_setup_component(hass, comp, {})
|
||||
for comp in ("homeassistant", "logbook")
|
||||
]
|
||||
)
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
"switch",
|
||||
|
@ -1637,7 +1701,13 @@ async def test_logbook_invalid_entity(hass, hass_client, recorder_mock):
|
|||
|
||||
async def test_icon_and_state(hass, hass_client, recorder_mock):
|
||||
"""Test to ensure state and custom icons are returned."""
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await asyncio.gather(
|
||||
*[
|
||||
async_setup_component(hass, comp, {})
|
||||
for comp in ("homeassistant", "logbook")
|
||||
]
|
||||
)
|
||||
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
@ -1705,6 +1775,7 @@ async def test_exclude_events_domain(hass, hass_client, recorder_mock):
|
|||
entity_id = "switch.bla"
|
||||
entity_id2 = "sensor.blu"
|
||||
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
config = logbook.CONFIG_SCHEMA(
|
||||
{
|
||||
ha.DOMAIN: {},
|
||||
|
@ -1750,7 +1821,10 @@ async def test_exclude_events_domain_glob(hass, hass_client, recorder_mock):
|
|||
},
|
||||
}
|
||||
)
|
||||
await async_setup_component(hass, "logbook", config)
|
||||
await asyncio.gather(
|
||||
async_setup_component(hass, "homeassistant", {}),
|
||||
async_setup_component(hass, "logbook", config),
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
@ -1789,7 +1863,10 @@ async def test_include_events_entity(hass, hass_client, recorder_mock):
|
|||
},
|
||||
}
|
||||
)
|
||||
await async_setup_component(hass, "logbook", config)
|
||||
await asyncio.gather(
|
||||
async_setup_component(hass, "homeassistant", {}),
|
||||
async_setup_component(hass, "logbook", config),
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
@ -1821,7 +1898,10 @@ async def test_exclude_events_entity(hass, hass_client, recorder_mock):
|
|||
logbook.DOMAIN: {CONF_EXCLUDE: {CONF_ENTITIES: [entity_id]}},
|
||||
}
|
||||
)
|
||||
await async_setup_component(hass, "logbook", config)
|
||||
await asyncio.gather(
|
||||
async_setup_component(hass, "homeassistant", {}),
|
||||
async_setup_component(hass, "logbook", config),
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
@ -1854,7 +1934,10 @@ async def test_include_events_domain(hass, hass_client, recorder_mock):
|
|||
},
|
||||
}
|
||||
)
|
||||
await async_setup_component(hass, "logbook", config)
|
||||
await asyncio.gather(
|
||||
async_setup_component(hass, "homeassistant", {}),
|
||||
async_setup_component(hass, "logbook", config),
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
@ -1897,7 +1980,10 @@ async def test_include_events_domain_glob(hass, hass_client, recorder_mock):
|
|||
},
|
||||
}
|
||||
)
|
||||
await async_setup_component(hass, "logbook", config)
|
||||
await asyncio.gather(
|
||||
async_setup_component(hass, "homeassistant", {}),
|
||||
async_setup_component(hass, "logbook", config),
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
@ -1948,7 +2034,10 @@ async def test_include_exclude_events(hass, hass_client, recorder_mock):
|
|||
},
|
||||
}
|
||||
)
|
||||
await async_setup_component(hass, "logbook", config)
|
||||
await asyncio.gather(
|
||||
async_setup_component(hass, "homeassistant", {}),
|
||||
async_setup_component(hass, "logbook", config),
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
@ -2004,7 +2093,10 @@ async def test_include_exclude_events_with_glob_filters(
|
|||
},
|
||||
}
|
||||
)
|
||||
await async_setup_component(hass, "logbook", config)
|
||||
await asyncio.gather(
|
||||
async_setup_component(hass, "homeassistant", {}),
|
||||
async_setup_component(hass, "logbook", config),
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
@ -2047,7 +2139,10 @@ async def test_empty_config(hass, hass_client, recorder_mock):
|
|||
logbook.DOMAIN: {},
|
||||
}
|
||||
)
|
||||
await async_setup_component(hass, "logbook", config)
|
||||
await asyncio.gather(
|
||||
async_setup_component(hass, "homeassistant", {}),
|
||||
async_setup_component(hass, "logbook", config),
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
@ -2141,7 +2236,12 @@ def _assert_entry(
|
|||
async def test_get_events(hass, hass_ws_client, recorder_mock):
|
||||
"""Test logbook get_events."""
|
||||
now = dt_util.utcnow()
|
||||
await async_setup_component(hass, "logbook", {})
|
||||
await asyncio.gather(
|
||||
*[
|
||||
async_setup_component(hass, comp, {})
|
||||
for comp in ("homeassistant", "logbook")
|
||||
]
|
||||
)
|
||||
await async_recorder_block_till_done(hass)
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
|
|
@ -46,14 +46,14 @@ async def test_humanify_shelly_click_event_block_device(hass, coap_wrapper):
|
|||
assert event1["domain"] == DOMAIN
|
||||
assert (
|
||||
event1["message"]
|
||||
== "'single' click event for Test name channel 1 Input was fired."
|
||||
== "'single' click event for Test name channel 1 Input was fired"
|
||||
)
|
||||
|
||||
assert event2["name"] == "Shelly"
|
||||
assert event2["domain"] == DOMAIN
|
||||
assert (
|
||||
event2["message"]
|
||||
== "'long' click event for shellyswitch25-12345678 channel 2 Input was fired."
|
||||
== "'long' click event for shellyswitch25-12345678 channel 2 Input was fired"
|
||||
)
|
||||
|
||||
|
||||
|
@ -91,12 +91,12 @@ async def test_humanify_shelly_click_event_rpc_device(hass, rpc_wrapper):
|
|||
assert event1["domain"] == DOMAIN
|
||||
assert (
|
||||
event1["message"]
|
||||
== "'single_push' click event for test switch_0 Input was fired."
|
||||
== "'single_push' click event for test switch_0 Input was fired"
|
||||
)
|
||||
|
||||
assert event2["name"] == "Shelly"
|
||||
assert event2["domain"] == DOMAIN
|
||||
assert (
|
||||
event2["message"]
|
||||
== "'btn_down' click event for shellypro4pm-12345678 channel 2 Input was fired."
|
||||
== "'btn_down' click event for shellypro4pm-12345678 channel 2 Input was fired"
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue