From 59e43ab6e4a456d64593faa155e07aa8a3fb6137 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 21 Jun 2020 12:50:58 -0500 Subject: [PATCH] Prefilter more logbook events in sql (#36958) * Prefilter more logbook events in sql Prefilter sensor events in _keep_event before humanify Cache static attribute lookup Reduces logbook execution time by ~35% * fix mocking in benchmark * Update tests for logbook users --- homeassistant/components/logbook/__init__.py | 116 ++++++++--- homeassistant/scripts/benchmark/__init__.py | 59 +++++- tests/components/alexa/test_init.py | 2 + tests/components/automation/test_init.py | 2 + tests/components/homekit/test_init.py | 2 + tests/components/logbook/test_init.py | 200 ++++++++++++------- tests/components/script/test_init.py | 2 + 7 files changed, 275 insertions(+), 108 deletions(-) diff --git a/homeassistant/components/logbook/__init__.py b/homeassistant/components/logbook/__init__.py index bacf0364d25..43caa56fe88 100644 --- a/homeassistant/components/logbook/__init__.py +++ b/homeassistant/components/logbook/__init__.py @@ -18,11 +18,13 @@ from homeassistant.components.recorder.util import ( session_scope, ) from homeassistant.const import ( + ATTR_DEVICE_CLASS, ATTR_DOMAIN, ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, ATTR_HIDDEN, ATTR_NAME, + ATTR_UNIT_OF_MEASUREMENT, CONF_EXCLUDE, CONF_INCLUDE, EVENT_HOMEASSISTANT_START, @@ -52,6 +54,8 @@ DOMAIN = "logbook" GROUP_BY_MINUTES = 15 +EMPTY_JSON_OBJECT = "{}" + CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema( @@ -194,7 +198,7 @@ class LogbookView(HomeAssistantView): return await hass.async_add_job(json_events) -def humanify(hass, events, prev_states=None): +def humanify(hass, events, entity_attr_cache, prev_states=None): """Generate a converted list of events into Entry objects. Will try to group events if possible: @@ -257,24 +261,22 @@ def humanify(hass, events, prev_states=None): prev_states[entity_id] = event.state domain = event.domain - if domain in CONTINUOUS_DOMAINS: + if ( + domain in CONTINUOUS_DOMAINS + and event != last_sensor_event[entity_id] + ): # Skip all but the last sensor state - if event != last_sensor_event[entity_id]: - continue + continue - # Don't show continuous sensor value changes in the logbook - if _get_attribute(hass, entity_id, event, "unit_of_measurement"): - continue - - name = _get_attribute( - hass, entity_id, event, ATTR_FRIENDLY_NAME + name = entity_attr_cache.get( + entity_id, ATTR_FRIENDLY_NAME, event ) or split_entity_id(entity_id)[1].replace("_", " ") yield { "when": event.time_fired, "name": name, "message": _entry_message_from_event( - hass, entity_id, domain, event + hass, entity_id, domain, event, entity_attr_cache ), "domain": domain, "entity_id": entity_id, @@ -375,12 +377,13 @@ def _generate_filter_from_config(config): def _get_events(hass, config, start_day, end_day, entity_id=None): """Get events for a period of time.""" entities_filter = _generate_filter_from_config(config) + entity_attr_cache = EntityAttributeCache(hass) def yield_events(query): """Yield Events that are not filtered away.""" for row in query.yield_per(1000): event = LazyEventPartialState(row) - if _keep_event(hass, event, entities_filter): + if _keep_event(hass, event, entities_filter, entity_attr_cache): yield event with session_scope(hass=hass) as session: @@ -409,6 +412,24 @@ def _get_events(hass, config, start_day, end_day, entity_id=None): .order_by(Events.time_fired) .outerjoin(States, (Events.event_id == States.event_id)) .outerjoin(old_state, (States.old_state_id == old_state.state_id)) + # The below filter, removes state change events that do not have + # and old_state, new_state, or the old and + # new state are the same for v8 schema or later. + # + # If the events/states were stored before v8 schema, we relay on the + # prev_states dict to remove them. + # + # When all data is schema v8 or later, the check for EMPTY_JSON_OBJECT + # can be removed. + .filter( + (Events.event_type != EVENT_STATE_CHANGED) + | (Events.event_data != EMPTY_JSON_OBJECT) + | ( + (States.state_id.isnot(None)) + & (old_state.state_id.isnot(None)) + & (States.state != old_state.state) + ) + ) .filter( Events.event_type.in_(ALL_EVENT_TYPES + list(hass.data.get(DOMAIN, {}))) ) @@ -429,18 +450,12 @@ def _get_events(hass, config, start_day, end_day, entity_id=None): | (States.state_id.is_(None)) ) + # When all data is schema v8 or later, prev_states can be removed prev_states = {} - return list(humanify(hass, yield_events(query), prev_states)) + return list(humanify(hass, yield_events(query), entity_attr_cache, prev_states)) -def _get_attribute(hass, entity_id, event, attribute): - current_state = hass.states.get(entity_id) - if not current_state: - return event.attributes.get(attribute) - return current_state.attributes.get(attribute, None) - - -def _keep_event(hass, event, entities_filter): +def _keep_event(hass, event, entities_filter, entity_attr_cache): if event.event_type == EVENT_STATE_CHANGED: entity_id = event.entity_id @@ -456,6 +471,11 @@ def _keep_event(hass, event, entities_filter): if event.hidden: return False + if event.domain in CONTINUOUS_DOMAINS and entity_attr_cache.get( + entity_id, ATTR_UNIT_OF_MEASUREMENT, event + ): + # Don't show continuous sensor value changes in the logbook + return False elif event.event_type == EVENT_LOGBOOK_ENTRY: event_data = event.data domain = event_data.get(ATTR_DOMAIN) @@ -478,7 +498,7 @@ def _keep_event(hass, event, entities_filter): return not entity_id or entities_filter(entity_id) -def _entry_message_from_event(hass, entity_id, domain, event): +def _entry_message_from_event(hass, entity_id, domain, event, entity_attr_cache): """Convert a state to a message for the logbook.""" # We pass domain in so we don't have to split entity_id again state_state = event.state @@ -494,7 +514,7 @@ def _entry_message_from_event(hass, entity_id, domain, event): return "has set" if domain == "binary_sensor": - device_class = _get_attribute(hass, entity_id, event, "device_class") + device_class = entity_attr_cache.get(entity_id, ATTR_DEVICE_CLASS, event) if device_class == "battery": if state_state == STATE_ON: return "is low" @@ -600,7 +620,10 @@ class LazyEventPartialState: def attributes(self): """State attributes.""" if not self._attributes: - if self._row.attributes is None or self._row.attributes == "{}": + if ( + self._row.attributes is None + or self._row.attributes == EMPTY_JSON_OBJECT + ): self._attributes = {} else: self._attributes = json.loads(self._row.attributes) @@ -611,7 +634,7 @@ class LazyEventPartialState: """Event data.""" if not self._event_data: - if self._row.event_data == "{}": + if self._row.event_data == EMPTY_JSON_OBJECT: self._event_data = {} else: self._event_data = json.loads(self._row.event_data) @@ -634,9 +657,15 @@ class LazyEventPartialState: @property def has_old_and_new_state(self): """Check the json data to see if new_state and old_state is present without decoding.""" - if self._row.event_data == "{}": + + # Delete this check once all states are saved in the v8 schema + # format or later (they have the old_state_id column). + + # New events in v8 schema format + if self._row.event_data == EMPTY_JSON_OBJECT: return self._row.state_id is not None and self._row.old_state_id is not None + # Old events not in v8 schema format return ( '"old_state": {' in self._row.event_data and '"new_state": {' in self._row.event_data @@ -648,3 +677,38 @@ class LazyEventPartialState: if '"hidden":' in self._row.attributes: return self.attributes.get(ATTR_HIDDEN, False) return False + + +class EntityAttributeCache: + """A cache to lookup static entity_id attribute. + + This class should not be used to lookup attributes + that are expected to change state. + """ + + def __init__(self, hass): + """Init the cache.""" + self._hass = hass + self._cache = {} + + def get(self, entity_id, attribute, event): + """Lookup an attribute for an entity or get it from the cache.""" + if entity_id in self._cache: + if attribute in self._cache[entity_id]: + return self._cache[entity_id][attribute] + else: + self._cache[entity_id] = {} + + current_state = self._hass.states.get(entity_id) + if current_state: + # Try the current state as its faster than decoding the + # attributes + self._cache[entity_id][attribute] = current_state.attributes.get( + attribute, None + ) + else: + # If the entity has been removed, decode the attributes + # instead + self._cache[entity_id][attribute] = event.attributes.get(attribute) + + return self._cache[entity_id][attribute] diff --git a/homeassistant/scripts/benchmark/__init__.py b/homeassistant/scripts/benchmark/__init__.py index 69de7970745..80828d40ec5 100644 --- a/homeassistant/scripts/benchmark/__init__.py +++ b/homeassistant/scripts/benchmark/__init__.py @@ -1,8 +1,10 @@ """Script to run benchmarks.""" import argparse import asyncio +import collections from contextlib import suppress from datetime import datetime +import json import logging from timeit import default_timer as timer from typing import Callable, Dict, TypeVar @@ -10,6 +12,7 @@ from typing import Callable, Dict, TypeVar from homeassistant import core from homeassistant.components.websocket_api.const import JSON_DUMP from homeassistant.const import ATTR_NOW, EVENT_STATE_CHANGED, EVENT_TIME_CHANGED +from homeassistant.helpers.json import JSONEncoder from homeassistant.util import dt as dt_util # mypy: allow-untyped-calls, allow-untyped-defs, no-check-untyped-defs @@ -169,21 +172,22 @@ async def _logbook_filtering(hass, last_changed, last_updated): "last_changed": last_changed, } - event = core.Event( - EVENT_STATE_CHANGED, - {"entity_id": entity_id, "old_state": old_state, "new_state": new_state}, + event = _create_state_changed_event_from_old_new( + entity_id, dt_util.utcnow(), old_state, new_state ) + entity_attr_cache = logbook.EntityAttributeCache(hass) + def yield_events(event): # pylint: disable=protected-access entities_filter = logbook._generate_filter_from_config({}) for _ in range(10 ** 5): - if logbook._keep_event(hass, event, entities_filter): + if logbook._keep_event(hass, event, entities_filter, entity_attr_cache): yield event start = timer() - list(logbook.humanify(hass, yield_events(event))) + list(logbook.humanify(hass, yield_events(event), entity_attr_cache)) return timer() - start @@ -208,3 +212,48 @@ async def json_serialize_states(hass): start = timer() JSON_DUMP(states) return timer() - start + + +def _create_state_changed_event_from_old_new( + entity_id, event_time_fired, old_state, new_state +): + """Create a state changed event from a old and new state.""" + attributes = {} + if new_state is not None: + attributes = new_state.get("attributes") + attributes_json = json.dumps(attributes, cls=JSONEncoder) + if attributes_json == "null": + attributes_json = "{}" + row = collections.namedtuple( + "Row", + [ + "event_type" + "event_data" + "time_fired" + "context_id" + "context_user_id" + "state" + "entity_id" + "domain" + "attributes" + "state_id", + "old_state_id", + ], + ) + + row.event_type = EVENT_STATE_CHANGED + row.event_data = "{}" + row.attributes = attributes_json + row.time_fired = event_time_fired + row.state = new_state and new_state.get("state") + row.entity_id = entity_id + row.domain = entity_id and core.split_entity_id(entity_id)[0] + row.context_id = None + row.context_user_id = None + row.old_state_id = old_state and 1 + row.state_id = new_state and 1 + + # pylint: disable=import-outside-toplevel + from homeassistant.components import logbook + + return logbook.LazyEventPartialState(row) diff --git a/tests/components/alexa/test_init.py b/tests/components/alexa/test_init.py index 2a9e72aaef7..f5071cf3f01 100644 --- a/tests/components/alexa/test_init.py +++ b/tests/components/alexa/test_init.py @@ -10,6 +10,7 @@ async def test_humanify_alexa_event(hass): """Test humanifying Alexa event.""" await async_setup_component(hass, "alexa", {}) hass.states.async_set("light.kitchen", "on", {"friendly_name": "Kitchen Light"}) + entity_attr_cache = logbook.EntityAttributeCache(hass) results = list( logbook.humanify( @@ -40,6 +41,7 @@ async def test_humanify_alexa_event(hass): }, ), ], + entity_attr_cache, ) ) diff --git a/tests/components/automation/test_init.py b/tests/components/automation/test_init.py index 2ac89b68a2d..c41eb80d6f2 100644 --- a/tests/components/automation/test_init.py +++ b/tests/components/automation/test_init.py @@ -1040,6 +1040,7 @@ async def test_extraction_functions(hass): async def test_logbook_humanify_automation_triggered_event(hass): """Test humanifying Automation Trigger event.""" await async_setup_component(hass, automation.DOMAIN, {}) + entity_attr_cache = logbook.EntityAttributeCache(hass) event1, event2 = list( logbook.humanify( @@ -1054,6 +1055,7 @@ async def test_logbook_humanify_automation_triggered_event(hass): {ATTR_ENTITY_ID: "automation.bye", ATTR_NAME: "Bye Automation"}, ), ], + entity_attr_cache, ) ) diff --git a/tests/components/homekit/test_init.py b/tests/components/homekit/test_init.py index 05667a5f2a0..4db72ffb374 100644 --- a/tests/components/homekit/test_init.py +++ b/tests/components/homekit/test_init.py @@ -17,6 +17,7 @@ async def test_humanify_homekit_changed_event(hass, hk_driver): """Test humanifying HomeKit changed event.""" with patch("homeassistant.components.homekit.HomeKit"): assert await async_setup_component(hass, "homekit", {"homekit": {}}) + entity_attr_cache = logbook.EntityAttributeCache(hass) event1, event2 = list( logbook.humanify( @@ -40,6 +41,7 @@ async def test_humanify_homekit_changed_event(hass, hk_driver): }, ), ], + entity_attr_cache, ) ) diff --git a/tests/components/logbook/test_init.py b/tests/components/logbook/test_init.py index 84cb827352e..2ce087ca6e3 100644 --- a/tests/components/logbook/test_init.py +++ b/tests/components/logbook/test_init.py @@ -121,12 +121,15 @@ class TestComponentLogbook(unittest.TestCase): pointA = dt_util.utcnow().replace(minute=2) pointB = pointA.replace(minute=5) pointC = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) + entity_attr_cache = logbook.EntityAttributeCache(self.hass) eventA = self.create_state_changed_event(pointA, entity_id, 10) eventB = self.create_state_changed_event(pointB, entity_id, 20) eventC = self.create_state_changed_event(pointC, entity_id, 30) - entries = list(logbook.humanify(self.hass, (eventA, eventB, eventC))) + entries = list( + logbook.humanify(self.hass, (eventA, eventB, eventC), entity_attr_cache) + ) assert len(entries) == 2 self.assert_entry( @@ -141,12 +144,15 @@ class TestComponentLogbook(unittest.TestCase): """Test remove continuous sensor events from logbook.""" entity_id = "sensor.bla" pointA = dt_util.utcnow() + entity_attr_cache = logbook.EntityAttributeCache(self.hass) attributes = {"unit_of_measurement": "foo"} eventA = self.create_state_changed_event(pointA, entity_id, 10, attributes) - entries = list(logbook.humanify(self.hass, (eventA,))) - - assert len(entries) == 0 + entities_filter = logbook._generate_filter_from_config({}) + assert ( + logbook._keep_event(self.hass, eventA, entities_filter, entity_attr_cache) + is False + ) def test_exclude_new_entities(self): """Test if events are excluded on first update.""" @@ -154,6 +160,7 @@ class TestComponentLogbook(unittest.TestCase): entity_id2 = "sensor.blu" pointA = dt_util.utcnow() pointB = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) + entity_attr_cache = logbook.EntityAttributeCache(self.hass) state_on = ha.State( entity_id, "on", {"brightness": 200}, pointA, pointA @@ -172,9 +179,9 @@ class TestComponentLogbook(unittest.TestCase): eventA, eventB, ) - if logbook._keep_event(self.hass, e, entities_filter) + if logbook._keep_event(self.hass, e, entities_filter, entity_attr_cache) ] - entries = list(logbook.humanify(self.hass, events)) + entries = list(logbook.humanify(self.hass, events, entity_attr_cache)) assert len(entries) == 2 self.assert_entry( @@ -190,6 +197,7 @@ class TestComponentLogbook(unittest.TestCase): entity_id2 = "sensor.blu" pointA = dt_util.utcnow() pointB = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) + entity_attr_cache = logbook.EntityAttributeCache(self.hass) state_on = ha.State( entity_id, "on", {"brightness": 200}, pointA, pointA @@ -207,9 +215,9 @@ class TestComponentLogbook(unittest.TestCase): eventA, eventB, ) - if logbook._keep_event(self.hass, e, entities_filter) + if logbook._keep_event(self.hass, e, entities_filter, entity_attr_cache) ] - entries = list(logbook.humanify(self.hass, events)) + entries = list(logbook.humanify(self.hass, events, entity_attr_cache)) assert len(entries) == 2 self.assert_entry( @@ -225,6 +233,7 @@ class TestComponentLogbook(unittest.TestCase): entity_id2 = "sensor.blu" pointA = dt_util.utcnow() pointB = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) + entity_attr_cache = logbook.EntityAttributeCache(self.hass) eventA = self.create_state_changed_event( pointA, entity_id, 10, {ATTR_HIDDEN: "true"} @@ -239,9 +248,9 @@ class TestComponentLogbook(unittest.TestCase): eventA, eventB, ) - if logbook._keep_event(self.hass, e, entities_filter) + if logbook._keep_event(self.hass, e, entities_filter, entity_attr_cache) ] - entries = list(logbook.humanify(self.hass, events)) + entries = list(logbook.humanify(self.hass, events, entity_attr_cache)) assert len(entries) == 2 self.assert_entry( @@ -257,6 +266,7 @@ class TestComponentLogbook(unittest.TestCase): entity_id2 = "sensor.blu" pointA = dt_util.utcnow() pointB = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) + entity_attr_cache = logbook.EntityAttributeCache(self.hass) eventA = self.create_state_changed_event(pointA, entity_id, 10) eventB = self.create_state_changed_event(pointB, entity_id2, 20) @@ -277,9 +287,9 @@ class TestComponentLogbook(unittest.TestCase): eventA, eventB, ) - if logbook._keep_event(self.hass, e, entities_filter) + if logbook._keep_event(self.hass, e, entities_filter, entity_attr_cache) ] - entries = list(logbook.humanify(self.hass, events)) + entries = list(logbook.humanify(self.hass, events, entity_attr_cache)) assert len(entries) == 2 self.assert_entry( @@ -295,6 +305,7 @@ class TestComponentLogbook(unittest.TestCase): entity_id2 = "sensor.blu" pointA = dt_util.utcnow() pointB = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) + entity_attr_cache = logbook.EntityAttributeCache(self.hass) eventA = self.create_state_changed_event(pointA, entity_id, 10) eventB = self.create_state_changed_event(pointB, entity_id2, 20) @@ -316,9 +327,9 @@ class TestComponentLogbook(unittest.TestCase): eventA, eventB, ) - if logbook._keep_event(self.hass, e, entities_filter) + if logbook._keep_event(self.hass, e, entities_filter, entity_attr_cache) ] - entries = list(logbook.humanify(self.hass, events)) + entries = list(logbook.humanify(self.hass, events, entity_attr_cache)) assert len(entries) == 2 self.assert_entry( @@ -334,6 +345,7 @@ class TestComponentLogbook(unittest.TestCase): entity_id2 = "sensor.blu" pointA = dt_util.utcnow() pointB = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) + entity_attr_cache = logbook.EntityAttributeCache(self.hass) eventA = self.create_state_changed_event(pointA, entity_id, 10) eventB = self.create_state_changed_event(pointB, entity_id2, 20) @@ -354,9 +366,9 @@ class TestComponentLogbook(unittest.TestCase): eventA, eventB, ) - if logbook._keep_event(self.hass, e, entities_filter) + if logbook._keep_event(self.hass, e, entities_filter, entity_attr_cache) ] - entries = list(logbook.humanify(self.hass, events)) + entries = list(logbook.humanify(self.hass, events, entity_attr_cache)) assert len(entries) == 2 self.assert_entry( @@ -373,6 +385,7 @@ class TestComponentLogbook(unittest.TestCase): entity_id2 = "sensor.blu" pointA = dt_util.utcnow() pointB = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) + entity_attr_cache = logbook.EntityAttributeCache(self.hass) event_alexa = MockLazyEventPartialState( EVENT_ALEXA_SMART_HOME, @@ -399,9 +412,9 @@ class TestComponentLogbook(unittest.TestCase): eventA, eventB, ) - if logbook._keep_event(self.hass, e, entities_filter) + if logbook._keep_event(self.hass, e, entities_filter, entity_attr_cache) ] - entries = list(logbook.humanify(self.hass, events)) + entries = list(logbook.humanify(self.hass, events, entity_attr_cache)) assert len(entries) == 3 self.assert_entry( @@ -419,6 +432,7 @@ class TestComponentLogbook(unittest.TestCase): entity_id3 = "sensor.bli" pointA = dt_util.utcnow() pointB = pointA + timedelta(minutes=logbook.GROUP_BY_MINUTES) + entity_attr_cache = logbook.EntityAttributeCache(self.hass) eventA1 = self.create_state_changed_event(pointA, entity_id, 10) eventA2 = self.create_state_changed_event(pointA, entity_id2, 10) @@ -452,9 +466,9 @@ class TestComponentLogbook(unittest.TestCase): eventB1, eventB2, ) - if logbook._keep_event(self.hass, e, entities_filter) + if logbook._keep_event(self.hass, e, entities_filter, entity_attr_cache) ] - entries = list(logbook.humanify(self.hass, events)) + entries = list(logbook.humanify(self.hass, events, entity_attr_cache)) assert len(entries) == 5 self.assert_entry( @@ -478,6 +492,7 @@ class TestComponentLogbook(unittest.TestCase): pointA = dt_util.utcnow() pointB = pointA + timedelta(minutes=1) pointC = pointB + timedelta(minutes=1) + entity_attr_cache = logbook.EntityAttributeCache(self.hass) state_off = ha.State("light.kitchen", "off", {}, pointA, pointA).as_dict() state_100 = ha.State( @@ -498,9 +513,9 @@ class TestComponentLogbook(unittest.TestCase): events = [ e for e in (eventA, eventB) - if logbook._keep_event(self.hass, e, entities_filter) + if logbook._keep_event(self.hass, e, entities_filter, entity_attr_cache) ] - entries = list(logbook.humanify(self.hass, events)) + entries = list(logbook.humanify(self.hass, events, entity_attr_cache)) assert len(entries) == 1 self.assert_entry( @@ -512,6 +527,7 @@ class TestComponentLogbook(unittest.TestCase): Events that are occurring in the same minute. """ + entity_attr_cache = logbook.EntityAttributeCache(self.hass) entries = list( logbook.humanify( self.hass, @@ -519,7 +535,8 @@ class TestComponentLogbook(unittest.TestCase): MockLazyEventPartialState(EVENT_HOMEASSISTANT_STOP), MockLazyEventPartialState(EVENT_HOMEASSISTANT_START), ), - ) + entity_attr_cache, + ), ) assert len(entries) == 1 @@ -531,6 +548,7 @@ class TestComponentLogbook(unittest.TestCase): """Test if HA start is not filtered or converted into a restart.""" entity_id = "switch.bla" pointA = dt_util.utcnow() + entity_attr_cache = logbook.EntityAttributeCache(self.hass) entries = list( logbook.humanify( @@ -539,6 +557,7 @@ class TestComponentLogbook(unittest.TestCase): MockLazyEventPartialState(EVENT_HOMEASSISTANT_START), self.create_state_changed_event(pointA, entity_id, 10), ), + entity_attr_cache, ) ) @@ -556,76 +575,79 @@ class TestComponentLogbook(unittest.TestCase): Especially test if the special handling for turn on/off events is done. """ pointA = dt_util.utcnow() - + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # 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 + self.hass, 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 + self.hass, 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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "turned off" def test_entry_message_from_event_device_tracker(self): """Test if logbook message is correctly created for device tracker.""" pointA = dt_util.utcnow() + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a device tracker "not home" state eventA = self.create_state_changed_event( pointA, "device_tracker.john", STATE_NOT_HOME ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, 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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is at work" def test_entry_message_from_event_person(self): """Test if logbook message is correctly created for a person.""" pointA = dt_util.utcnow() + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # 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 + self.hass, 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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is at work" def test_entry_message_from_event_sun(self): """Test if logbook message is correctly created for sun.""" pointA = dt_util.utcnow() + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a sun rise eventA = self.create_state_changed_event( pointA, "sun.sun", sun.STATE_ABOVE_HORIZON ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "has risen" @@ -634,7 +656,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "has set" @@ -642,13 +664,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "battery"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor battery "low" state eventA = self.create_state_changed_event( pointA, "binary_sensor.battery", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is low" @@ -657,7 +680,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is normal" @@ -665,13 +688,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "connectivity"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor connectivity "connected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.connectivity", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is connected" @@ -680,7 +704,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is disconnected" @@ -688,13 +712,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "door"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor door "open" state eventA = self.create_state_changed_event( pointA, "binary_sensor.door", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is opened" @@ -703,7 +728,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is closed" @@ -711,13 +736,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "garage_door"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor garage_door "open" state eventA = self.create_state_changed_event( pointA, "binary_sensor.garage_door", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is opened" @@ -726,7 +752,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is closed" @@ -734,13 +760,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "opening"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor opening "open" state eventA = self.create_state_changed_event( pointA, "binary_sensor.opening", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is opened" @@ -749,7 +776,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is closed" @@ -757,13 +784,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "window"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor window "open" state eventA = self.create_state_changed_event( pointA, "binary_sensor.window", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is opened" @@ -772,7 +800,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is closed" @@ -780,13 +808,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "lock"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor lock "unlocked" state eventA = self.create_state_changed_event( pointA, "binary_sensor.lock", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is unlocked" @@ -795,7 +824,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is locked" @@ -803,13 +832,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "plug"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor plug "unpluged" state eventA = self.create_state_changed_event( pointA, "binary_sensor.plug", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is plugged in" @@ -818,7 +848,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is unplugged" @@ -826,13 +856,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "presence"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor presence "home" state eventA = self.create_state_changed_event( pointA, "binary_sensor.presence", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is at home" @@ -841,7 +872,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is away" @@ -849,13 +880,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "safety"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor safety "unsafe" state eventA = self.create_state_changed_event( pointA, "binary_sensor.safety", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is unsafe" @@ -864,7 +896,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "is safe" @@ -872,13 +904,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "cold"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor cold "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.cold", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected cold" @@ -887,7 +920,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no cold detected)" @@ -895,13 +928,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "gas"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor gas "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.gas", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected gas" @@ -910,7 +944,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no gas detected)" @@ -918,13 +952,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "heat"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor heat "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.heat", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected heat" @@ -933,7 +968,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no heat detected)" @@ -941,13 +976,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "light"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor light "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.light", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected light" @@ -956,7 +992,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no light detected)" @@ -964,13 +1000,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "moisture"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor moisture "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.moisture", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected moisture" @@ -979,7 +1016,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no moisture detected)" @@ -987,13 +1024,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "motion"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor motion "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.motion", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected motion" @@ -1002,7 +1040,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no motion detected)" @@ -1010,13 +1048,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "occupancy"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor occupancy "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.occupancy", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected occupancy" @@ -1025,7 +1064,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no occupancy detected)" @@ -1033,13 +1072,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "power"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor power "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.power", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected power" @@ -1048,7 +1088,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no power detected)" @@ -1056,13 +1096,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "problem"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor problem "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.problem", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected problem" @@ -1071,7 +1112,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no problem detected)" @@ -1079,13 +1120,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "smoke"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor smoke "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.smoke", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected smoke" @@ -1094,7 +1136,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no smoke detected)" @@ -1102,13 +1144,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "sound"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor sound "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.sound", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected sound" @@ -1117,7 +1160,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no sound detected)" @@ -1125,13 +1168,14 @@ class TestComponentLogbook(unittest.TestCase): """Test if logbook message is correctly created for a binary_sensor.""" pointA = dt_util.utcnow() attributes = {"device_class": "vibration"} + entity_attr_cache = logbook.EntityAttributeCache(self.hass) # message for a binary_sensor vibration "detected" state eventA = self.create_state_changed_event( pointA, "binary_sensor.vibration", STATE_ON, attributes ) message = logbook._entry_message_from_event( - self.hass, eventA.entity_id, eventA.domain, eventA + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "detected vibration" @@ -1140,7 +1184,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 + self.hass, eventA.entity_id, eventA.domain, eventA, entity_attr_cache ) assert message == "cleared (no vibration detected)" @@ -1149,6 +1193,7 @@ class TestComponentLogbook(unittest.TestCase): name = "Nice name" message = "has a custom entry" entity_id = "sun.sun" + entity_attr_cache = logbook.EntityAttributeCache(self.hass) entries = list( logbook.humanify( @@ -1163,6 +1208,7 @@ class TestComponentLogbook(unittest.TestCase): }, ), ), + entity_attr_cache, ) ) diff --git a/tests/components/script/test_init.py b/tests/components/script/test_init.py index 6ec02d05575..9bcf0dc1be8 100644 --- a/tests/components/script/test_init.py +++ b/tests/components/script/test_init.py @@ -473,6 +473,7 @@ async def test_config(hass): async def test_logbook_humanify_script_started_event(hass): """Test humanifying script started event.""" await async_setup_component(hass, DOMAIN, {}) + entity_attr_cache = logbook.EntityAttributeCache(hass) event1, event2 = list( logbook.humanify( @@ -487,6 +488,7 @@ async def test_logbook_humanify_script_started_event(hass): {ATTR_ENTITY_ID: "script.bye", ATTR_NAME: "Bye Script"}, ), ], + entity_attr_cache, ) )