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:
parent
b1c0d8fb6c
commit
6b7a7939d2
9 changed files with 473 additions and 101 deletions
|
@ -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."""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue