Include the first seen context data in the logbook api (#39194)

* Include the context_entity_id in the logbook api

context_entity_id is the first entity seen during
a time period that includes the context

* update test

* more of them

* include friendly name

* pylint wants a ternary

* Refactor

* performance

* fix homekit context

* Fix self describing events

* Fix external_events
This commit is contained in:
J. Nick Koston 2020-08-24 12:44:40 -05:00 committed by GitHub
parent b1c0d8fb6c
commit 6b7a7939d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 473 additions and 101 deletions

View file

@ -15,12 +15,16 @@ from homeassistant.components.automation import EVENT_AUTOMATION_TRIGGERED
from homeassistant.components.recorder.models import process_timestamp_to_utc_isoformat
from homeassistant.components.script import EVENT_SCRIPT_STARTED
from homeassistant.const import (
ATTR_DOMAIN,
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
ATTR_NAME,
ATTR_SERVICE,
CONF_DOMAINS,
CONF_ENTITIES,
CONF_EXCLUDE,
CONF_INCLUDE,
EVENT_CALL_SERVICE,
EVENT_HOMEASSISTANT_START,
EVENT_HOMEASSISTANT_STOP,
EVENT_STATE_CHANGED,
@ -96,7 +100,6 @@ class TestComponentLogbook(unittest.TestCase):
events = list(
logbook._get_events(
self.hass,
{},
dt_util.utcnow() - timedelta(hours=1),
dt_util.utcnow() + timedelta(hours=1),
)
@ -152,7 +155,7 @@ class TestComponentLogbook(unittest.TestCase):
eventC = self.create_state_changed_event(pointC, entity_id, 30)
entries = list(
logbook.humanify(self.hass, (eventA, eventB, eventC), entity_attr_cache)
logbook.humanify(self.hass, (eventA, eventB, eventC), entity_attr_cache, {})
)
assert len(entries) == 2
@ -191,7 +194,7 @@ class TestComponentLogbook(unittest.TestCase):
)
if logbook._keep_event(self.hass, e, entities_filter)
]
entries = list(logbook.humanify(self.hass, events, entity_attr_cache))
entries = list(logbook.humanify(self.hass, events, entity_attr_cache, {}))
assert len(entries) == 2
self.assert_entry(
@ -229,7 +232,7 @@ class TestComponentLogbook(unittest.TestCase):
)
if logbook._keep_event(self.hass, e, entities_filter)
]
entries = list(logbook.humanify(self.hass, events, entity_attr_cache))
entries = list(logbook.humanify(self.hass, events, entity_attr_cache, {}))
assert len(entries) == 2
self.assert_entry(
@ -276,7 +279,7 @@ class TestComponentLogbook(unittest.TestCase):
)
if logbook._keep_event(self.hass, e, entities_filter)
]
entries = list(logbook.humanify(self.hass, events, entity_attr_cache))
entries = list(logbook.humanify(self.hass, events, entity_attr_cache, {}))
assert len(entries) == 2
self.assert_entry(
@ -318,7 +321,7 @@ class TestComponentLogbook(unittest.TestCase):
)
if logbook._keep_event(self.hass, e, entities_filter)
]
entries = list(logbook.humanify(self.hass, events, entity_attr_cache))
entries = list(logbook.humanify(self.hass, events, entity_attr_cache, {}))
assert len(entries) == 2
self.assert_entry(
@ -364,7 +367,7 @@ class TestComponentLogbook(unittest.TestCase):
)
if logbook._keep_event(self.hass, e, entities_filter)
]
entries = list(logbook.humanify(self.hass, events, entity_attr_cache))
entries = list(logbook.humanify(self.hass, events, entity_attr_cache, {}))
assert len(entries) == 3
self.assert_entry(
@ -418,7 +421,7 @@ class TestComponentLogbook(unittest.TestCase):
)
if logbook._keep_event(self.hass, e, entities_filter)
]
entries = list(logbook.humanify(self.hass, events, entity_attr_cache))
entries = list(logbook.humanify(self.hass, events, entity_attr_cache, {}))
assert len(entries) == 4
self.assert_entry(
@ -475,7 +478,7 @@ class TestComponentLogbook(unittest.TestCase):
)
if logbook._keep_event(self.hass, e, entities_filter)
]
entries = list(logbook.humanify(self.hass, events, entity_attr_cache))
entries = list(logbook.humanify(self.hass, events, entity_attr_cache, {}))
assert len(entries) == 5
self.assert_entry(
@ -549,7 +552,7 @@ class TestComponentLogbook(unittest.TestCase):
)
if logbook._keep_event(self.hass, e, entities_filter)
]
entries = list(logbook.humanify(self.hass, events, entity_attr_cache))
entries = list(logbook.humanify(self.hass, events, entity_attr_cache, {}))
assert len(entries) == 6
self.assert_entry(
@ -585,6 +588,7 @@ class TestComponentLogbook(unittest.TestCase):
MockLazyEventPartialState(EVENT_HOMEASSISTANT_START),
),
entity_attr_cache,
{},
),
)
@ -607,6 +611,7 @@ class TestComponentLogbook(unittest.TestCase):
self.create_state_changed_event(pointA, entity_id, 10),
),
entity_attr_cache,
{},
)
)
@ -628,21 +633,21 @@ class TestComponentLogbook(unittest.TestCase):
# message for a device state change
eventA = self.create_state_changed_event(pointA, "switch.bla", 10)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "changed to 10"
# message for a switch turned on
eventA = self.create_state_changed_event(pointA, "switch.bla", STATE_ON)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "turned on"
# message for a switch turned off
eventA = self.create_state_changed_event(pointA, "switch.bla", STATE_OFF)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "turned off"
@ -656,14 +661,14 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "device_tracker.john", STATE_NOT_HOME
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is away"
# message for a device tracker "home" state
eventA = self.create_state_changed_event(pointA, "device_tracker.john", "work")
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is at work"
@ -675,14 +680,14 @@ class TestComponentLogbook(unittest.TestCase):
# message for a device tracker "not home" state
eventA = self.create_state_changed_event(pointA, "person.john", STATE_NOT_HOME)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is away"
# message for a device tracker "home" state
eventA = self.create_state_changed_event(pointA, "person.john", "work")
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is at work"
@ -696,7 +701,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "sun.sun", sun.STATE_ABOVE_HORIZON
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "has risen"
@ -705,7 +710,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "sun.sun", sun.STATE_BELOW_HORIZON
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "has set"
@ -720,7 +725,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.battery", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is low"
@ -729,7 +734,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.battery", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is normal"
@ -744,7 +749,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.connectivity", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is connected"
@ -753,7 +758,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.connectivity", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is disconnected"
@ -768,7 +773,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.door", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is opened"
@ -777,7 +782,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.door", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is closed"
@ -792,7 +797,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.garage_door", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is opened"
@ -801,7 +806,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.garage_door", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is closed"
@ -816,7 +821,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.opening", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is opened"
@ -825,7 +830,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.opening", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is closed"
@ -840,7 +845,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.window", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is opened"
@ -849,7 +854,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.window", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is closed"
@ -864,7 +869,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.lock", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is unlocked"
@ -873,7 +878,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.lock", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is locked"
@ -888,7 +893,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.plug", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is plugged in"
@ -897,7 +902,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.plug", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is unplugged"
@ -912,7 +917,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.presence", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is at home"
@ -921,7 +926,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.presence", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is away"
@ -936,7 +941,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.safety", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is unsafe"
@ -945,7 +950,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.safety", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "is safe"
@ -960,7 +965,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.cold", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected cold"
@ -969,7 +974,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.cold", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no cold detected)"
@ -984,7 +989,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.gas", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected gas"
@ -993,7 +998,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.gas", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no gas detected)"
@ -1008,7 +1013,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.heat", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected heat"
@ -1017,7 +1022,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.heat", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no heat detected)"
@ -1032,7 +1037,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.light", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected light"
@ -1041,7 +1046,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.light", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no light detected)"
@ -1056,7 +1061,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.moisture", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected moisture"
@ -1065,7 +1070,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.moisture", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no moisture detected)"
@ -1080,7 +1085,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.motion", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected motion"
@ -1089,7 +1094,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.motion", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no motion detected)"
@ -1104,7 +1109,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.occupancy", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected occupancy"
@ -1113,7 +1118,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.occupancy", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no occupancy detected)"
@ -1128,7 +1133,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.power", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected power"
@ -1137,7 +1142,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.power", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no power detected)"
@ -1152,7 +1157,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.problem", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected problem"
@ -1161,7 +1166,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.problem", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no problem detected)"
@ -1176,7 +1181,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.smoke", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected smoke"
@ -1185,7 +1190,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.smoke", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no smoke detected)"
@ -1200,7 +1205,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.sound", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected sound"
@ -1209,7 +1214,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.sound", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no sound detected)"
@ -1224,7 +1229,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.vibration", STATE_ON, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "detected vibration"
@ -1233,7 +1238,7 @@ class TestComponentLogbook(unittest.TestCase):
pointA, "binary_sensor.vibration", STATE_OFF, attributes
)
message = logbook._entry_message_from_event(
self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache
eventA.entity_id, eventA.domain, eventA, entity_attr_cache
)
assert message == "cleared (no vibration detected)"
@ -1258,6 +1263,7 @@ class TestComponentLogbook(unittest.TestCase):
),
),
entity_attr_cache,
{},
)
)
@ -1652,7 +1658,6 @@ async def test_logbook_entity_filter_with_automations(hass, hass_client):
assert response.status == 200
json_dict = await response.json()
assert len(json_dict) == 5
assert json_dict[0]["entity_id"] == entity_id_test
assert json_dict[1]["entity_id"] == entity_id_second
assert json_dict[2]["entity_id"] == "automation.mock_automation"
@ -1837,6 +1842,245 @@ async def test_exclude_attribute_changes(hass, hass_client):
assert response_json[2]["entity_id"] == "light.kitchen"
async def test_logbook_entity_context_id(hass, hass_client):
"""Test the logbook view with end_time and entity with automations and scripts."""
await hass.async_add_executor_job(init_recorder_component, hass)
await async_setup_component(hass, "logbook", {})
await async_setup_component(hass, "automation", {})
await async_setup_component(hass, "script", {})
await hass.async_add_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
context = ha.Context(
id="ac5bd62de45711eaaeb351041eec8dd9",
user_id="b400facee45711eaa9308bfd3d19e474",
)
# An Automation
automation_entity_id_test = "automation.alarm"
hass.bus.async_fire(
EVENT_AUTOMATION_TRIGGERED,
{ATTR_NAME: "Mock automation", ATTR_ENTITY_ID: automation_entity_id_test},
context=context,
)
hass.bus.async_fire(
EVENT_SCRIPT_STARTED,
{ATTR_NAME: "Mock script", ATTR_ENTITY_ID: "script.mock_script"},
context=context,
)
hass.states.async_set(
automation_entity_id_test,
STATE_ON,
{ATTR_FRIENDLY_NAME: "Alarm Automation"},
context=context,
)
entity_id_test = "alarm_control_panel.area_001"
hass.states.async_set(entity_id_test, STATE_OFF, context=context)
await hass.async_block_till_done()
hass.states.async_set(entity_id_test, STATE_ON, context=context)
await hass.async_block_till_done()
entity_id_second = "alarm_control_panel.area_002"
hass.states.async_set(entity_id_second, STATE_OFF, context=context)
await hass.async_block_till_done()
hass.states.async_set(entity_id_second, STATE_ON, context=context)
await hass.async_block_till_done()
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
await hass.async_block_till_done()
await hass.async_add_job(
logbook.log_entry,
hass,
"mock_name",
"mock_message",
"alarm_control_panel",
"alarm_control_panel.area_003",
context,
)
await hass.async_block_till_done()
await hass.async_add_job(
logbook.log_entry,
hass,
"mock_name",
"mock_message",
"homeassistant",
None,
context,
)
await hass.async_block_till_done()
# A service call
light_turn_off_service_context = ha.Context(
id="9c5bd62de45711eaaeb351041eec8dd9",
user_id="9400facee45711eaa9308bfd3d19e474",
)
hass.states.async_set("light.switch", STATE_ON)
await hass.async_block_till_done()
hass.bus.async_fire(
EVENT_CALL_SERVICE,
{
ATTR_DOMAIN: "light",
ATTR_SERVICE: "turn_off",
ATTR_ENTITY_ID: "light.switch",
},
context=light_turn_off_service_context,
)
await hass.async_block_till_done()
hass.states.async_set(
"light.switch", STATE_OFF, context=light_turn_off_service_context
)
await hass.async_block_till_done()
await hass.async_add_job(trigger_db_commit, hass)
await hass.async_block_till_done()
await hass.async_add_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
client = await hass_client()
# Today time 00:00:00
start = dt_util.utcnow().date()
start_date = datetime(start.year, start.month, start.day)
# Test today entries with filter by end_time
end_time = start + timedelta(hours=24)
response = await client.get(
f"/api/logbook/{start_date.isoformat()}?end_time={end_time}"
)
assert response.status == 200
json_dict = await response.json()
assert json_dict[0]["entity_id"] == "automation.alarm"
assert "context_entity_id" not in json_dict[0]
assert json_dict[0]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[1]["entity_id"] == "script.mock_script"
assert json_dict[1]["context_event_type"] == "automation_triggered"
assert json_dict[1]["context_entity_id"] == "automation.alarm"
assert json_dict[1]["context_entity_id_name"] == "Alarm Automation"
assert json_dict[1]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[2]["entity_id"] == entity_id_test
assert json_dict[2]["context_event_type"] == "automation_triggered"
assert json_dict[2]["context_entity_id"] == "automation.alarm"
assert json_dict[2]["context_entity_id_name"] == "Alarm Automation"
assert json_dict[2]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[3]["entity_id"] == entity_id_second
assert json_dict[3]["context_event_type"] == "automation_triggered"
assert json_dict[3]["context_entity_id"] == "automation.alarm"
assert json_dict[3]["context_entity_id_name"] == "Alarm Automation"
assert json_dict[3]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[4]["domain"] == "homeassistant"
assert json_dict[5]["entity_id"] == "alarm_control_panel.area_003"
assert json_dict[5]["context_event_type"] == "automation_triggered"
assert json_dict[5]["context_entity_id"] == "automation.alarm"
assert json_dict[5]["domain"] == "alarm_control_panel"
assert json_dict[5]["context_entity_id_name"] == "Alarm Automation"
assert json_dict[5]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[6]["domain"] == "homeassistant"
assert json_dict[6]["context_user_id"] == "b400facee45711eaa9308bfd3d19e474"
assert json_dict[7]["entity_id"] == "light.switch"
assert json_dict[7]["context_event_type"] == "call_service"
assert json_dict[7]["context_domain"] == "light"
assert json_dict[7]["context_service"] == "turn_off"
assert json_dict[7]["domain"] == "light"
assert json_dict[7]["context_user_id"] == "9400facee45711eaa9308bfd3d19e474"
async def test_logbook_context_from_template(hass, hass_client):
"""Test the logbook view with end_time and entity with automations and scripts."""
await hass.async_add_executor_job(init_recorder_component, hass)
await async_setup_component(hass, "logbook", {})
assert await async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "template",
"switches": {
"test_template_switch": {
"value_template": "{{ states.switch.test_state.state }}",
"turn_on": {
"service": "switch.turn_on",
"entity_id": "switch.test_state",
},
"turn_off": {
"service": "switch.turn_off",
"entity_id": "switch.test_state",
},
}
},
}
},
)
await hass.async_add_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
# Entity added (should not be logged)
hass.states.async_set("switch.test_state", STATE_ON)
await hass.async_block_till_done()
# First state change (should be logged)
hass.states.async_set("switch.test_state", STATE_OFF)
await hass.async_block_till_done()
switch_turn_off_context = ha.Context(
id="9c5bd62de45711eaaeb351041eec8dd9",
user_id="9400facee45711eaa9308bfd3d19e474",
)
hass.states.async_set(
"switch.test_state", STATE_ON, context=switch_turn_off_context
)
await hass.async_block_till_done()
await hass.async_add_job(trigger_db_commit, hass)
await hass.async_block_till_done()
await hass.async_add_job(hass.data[recorder.DATA_INSTANCE].block_till_done)
client = await hass_client()
# Today time 00:00:00
start = dt_util.utcnow().date()
start_date = datetime(start.year, start.month, start.day)
# Test today entries with filter by end_time
end_time = start + timedelta(hours=24)
response = await client.get(
f"/api/logbook/{start_date.isoformat()}?end_time={end_time}"
)
assert response.status == 200
json_dict = await response.json()
assert json_dict[0]["domain"] == "homeassistant"
assert "context_entity_id" not in json_dict[0]
assert json_dict[1]["entity_id"] == "switch.test_template_switch"
assert json_dict[2]["entity_id"] == "switch.test_state"
assert json_dict[3]["entity_id"] == "switch.test_template_switch"
assert json_dict[3]["context_entity_id"] == "switch.test_state"
assert json_dict[3]["context_entity_id_name"] == "test state"
assert json_dict[4]["entity_id"] == "switch.test_state"
assert json_dict[4]["context_user_id"] == "9400facee45711eaa9308bfd3d19e474"
assert json_dict[5]["entity_id"] == "switch.test_template_switch"
assert json_dict[5]["context_entity_id"] == "switch.test_state"
assert json_dict[5]["context_entity_id_name"] == "test state"
assert json_dict[5]["context_user_id"] == "9400facee45711eaa9308bfd3d19e474"
class MockLazyEventPartialState(ha.Event):
"""Minimal mock of a Lazy event."""
@ -1850,6 +2094,11 @@ class MockLazyEventPartialState(ha.Event):
"""Context user id of event."""
return self.context.user_id
@property
def context_id(self):
"""Context id of event."""
return self.context.id
@property
def time_fired_isoformat(self):
"""Time event was fired in utc isoformat."""