Fix logbook filtering by entity id (#36973)
* Fix logbook filtering by entity_id * remove debugpull/37160/head
parent
a6536bb622
commit
1de97e3a35
|
@ -82,13 +82,13 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
ALL_EVENT_TYPES = [
|
||||
EVENT_STATE_CHANGED,
|
||||
EVENT_LOGBOOK_ENTRY,
|
||||
HOMEASSISTANT_EVENTS = [
|
||||
EVENT_HOMEASSISTANT_START,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
]
|
||||
|
||||
ALL_EVENT_TYPES = [EVENT_STATE_CHANGED, EVENT_LOGBOOK_ENTRY, *HOMEASSISTANT_EVENTS]
|
||||
|
||||
LOG_MESSAGE_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(ATTR_NAME): cv.string,
|
||||
|
@ -124,7 +124,9 @@ def async_describe_event(hass, domain, event_name, describe_callback):
|
|||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Listen for download events to download files."""
|
||||
"""Logbook setup."""
|
||||
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
|
||||
@callback
|
||||
def log_message(service):
|
||||
|
@ -374,9 +376,14 @@ def _generate_filter_from_config(config):
|
|||
)
|
||||
|
||||
|
||||
def _all_entities_filter(_):
|
||||
"""Filter that accepts all entities."""
|
||||
return True
|
||||
|
||||
|
||||
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):
|
||||
|
@ -389,9 +396,12 @@ def _get_events(hass, config, start_day, end_day, entity_id=None):
|
|||
with session_scope(hass=hass) as session:
|
||||
if entity_id is not None:
|
||||
entity_ids = [entity_id.lower()]
|
||||
entities_filter = generate_filter([], entity_ids, [], [])
|
||||
elif config.get(CONF_EXCLUDE) or config.get(CONF_INCLUDE):
|
||||
entities_filter = _generate_filter_from_config(config)
|
||||
entity_ids = _get_related_entity_ids(session, entities_filter)
|
||||
else:
|
||||
entities_filter = _all_entities_filter
|
||||
entity_ids = None
|
||||
|
||||
old_state = aliased(States, name="old_state")
|
||||
|
@ -456,7 +466,6 @@ def _get_events(hass, config, start_day, end_day, entity_id=None):
|
|||
|
||||
|
||||
def _keep_event(hass, event, entities_filter, entity_attr_cache):
|
||||
|
||||
if event.event_type == EVENT_STATE_CHANGED:
|
||||
entity_id = event.entity_id
|
||||
if entity_id is None:
|
||||
|
@ -476,26 +485,25 @@ def _keep_event(hass, event, entities_filter, entity_attr_cache):
|
|||
):
|
||||
# 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)
|
||||
entity_id = None
|
||||
elif event.event_type in hass.data.get(DOMAIN, {}) and not event.data.get(
|
||||
"entity_id"
|
||||
):
|
||||
elif event.event_type in HOMEASSISTANT_EVENTS:
|
||||
entity_id = f"{HA_DOMAIN}."
|
||||
elif event.event_type in hass.data[DOMAIN] and ATTR_ENTITY_ID not in event.data:
|
||||
# If the entity_id isn't described, use the domain that describes
|
||||
# the event for filtering.
|
||||
domain = hass.data[DOMAIN][event.event_type][0]
|
||||
entity_id = None
|
||||
if domain is None:
|
||||
return False
|
||||
entity_id = f"{domain}."
|
||||
else:
|
||||
event_data = event.data
|
||||
domain = event_data.get(ATTR_DOMAIN)
|
||||
entity_id = event_data.get("entity_id")
|
||||
entity_id = event_data.get(ATTR_ENTITY_ID)
|
||||
if entity_id is None:
|
||||
domain = event_data.get(ATTR_DOMAIN)
|
||||
if domain is None:
|
||||
return False
|
||||
entity_id = f"{domain}."
|
||||
|
||||
if not entity_id and domain:
|
||||
entity_id = f"{domain}."
|
||||
|
||||
return not entity_id or entities_filter(entity_id)
|
||||
return entities_filter(entity_id)
|
||||
|
||||
|
||||
def _entry_message_from_event(hass, entity_id, domain, event, entity_attr_cache):
|
||||
|
|
|
@ -12,9 +12,12 @@ import voluptuous as vol
|
|||
|
||||
from homeassistant.components import logbook, recorder, sun
|
||||
from homeassistant.components.alexa.smart_home import EVENT_ALEXA_SMART_HOME
|
||||
from homeassistant.components.automation import EVENT_AUTOMATION_TRIGGERED
|
||||
from homeassistant.components.script import EVENT_SCRIPT_STARTED
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
ATTR_HIDDEN,
|
||||
ATTR_NAME,
|
||||
EVENT_HOMEASSISTANT_START,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
EVENT_STATE_CHANGED,
|
||||
|
@ -354,7 +357,10 @@ class TestComponentLogbook(unittest.TestCase):
|
|||
{
|
||||
ha.DOMAIN: {},
|
||||
logbook.DOMAIN: {
|
||||
logbook.CONF_INCLUDE: {logbook.CONF_ENTITIES: [entity_id2]}
|
||||
logbook.CONF_INCLUDE: {
|
||||
logbook.CONF_DOMAINS: ["homeassistant"],
|
||||
logbook.CONF_ENTITIES: [entity_id2],
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -399,7 +405,9 @@ class TestComponentLogbook(unittest.TestCase):
|
|||
{
|
||||
ha.DOMAIN: {},
|
||||
logbook.DOMAIN: {
|
||||
logbook.CONF_INCLUDE: {logbook.CONF_DOMAINS: ["sensor", "alexa"]}
|
||||
logbook.CONF_INCLUDE: {
|
||||
logbook.CONF_DOMAINS: ["homeassistant", "sensor", "alexa"]
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
@ -445,7 +453,7 @@ class TestComponentLogbook(unittest.TestCase):
|
|||
ha.DOMAIN: {},
|
||||
logbook.DOMAIN: {
|
||||
logbook.CONF_INCLUDE: {
|
||||
logbook.CONF_DOMAINS: ["sensor"],
|
||||
logbook.CONF_DOMAINS: ["sensor", "homeassistant"],
|
||||
logbook.CONF_ENTITIES: ["switch.bla"],
|
||||
},
|
||||
logbook.CONF_EXCLUDE: {
|
||||
|
@ -1543,6 +1551,82 @@ async def test_logbook_view_end_time_entity(hass, hass_client):
|
|||
assert json[0]["entity_id"] == entity_id_test
|
||||
|
||||
|
||||
async def test_logbook_entity_filter_with_automations(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)
|
||||
|
||||
entity_id_test = "alarm_control_panel.area_001"
|
||||
hass.states.async_set(entity_id_test, STATE_OFF)
|
||||
hass.states.async_set(entity_id_test, STATE_ON)
|
||||
entity_id_second = "alarm_control_panel.area_002"
|
||||
hass.states.async_set(entity_id_second, STATE_OFF)
|
||||
hass.states.async_set(entity_id_second, STATE_ON)
|
||||
|
||||
hass.bus.async_fire(
|
||||
EVENT_AUTOMATION_TRIGGERED,
|
||||
{ATTR_NAME: "Mock automation", ATTR_ENTITY_ID: "automation.mock_automation"},
|
||||
)
|
||||
hass.bus.async_fire(
|
||||
EVENT_SCRIPT_STARTED,
|
||||
{ATTR_NAME: "Mock script", ATTR_ENTITY_ID: "script.mock_script"},
|
||||
)
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
|
||||
|
||||
await hass.async_add_job(partial(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 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"
|
||||
assert json_dict[3]["entity_id"] == "script.mock_script"
|
||||
assert json_dict[4]["domain"] == "homeassistant"
|
||||
|
||||
# Test entries for 3 days with filter by entity_id
|
||||
end_time = start + timedelta(hours=72)
|
||||
response = await client.get(
|
||||
f"/api/logbook/{start_date.isoformat()}?end_time={end_time}&entity=alarm_control_panel.area_001"
|
||||
)
|
||||
assert response.status == 200
|
||||
json_dict = await response.json()
|
||||
assert len(json_dict) == 1
|
||||
assert json_dict[0]["entity_id"] == entity_id_test
|
||||
|
||||
# Tomorrow time 00:00:00
|
||||
start = dt_util.utcnow()
|
||||
start_date = datetime(start.year, start.month, start.day)
|
||||
|
||||
# Test entries from today to 3 days with filter by entity_id
|
||||
end_time = start_date + timedelta(hours=72)
|
||||
response = await client.get(
|
||||
f"/api/logbook/{start_date.isoformat()}?end_time={end_time}&entity=alarm_control_panel.area_002"
|
||||
)
|
||||
assert response.status == 200
|
||||
json_dict = await response.json()
|
||||
assert len(json_dict) == 1
|
||||
assert json_dict[0]["entity_id"] == entity_id_second
|
||||
|
||||
|
||||
class MockLazyEventPartialState(ha.Event):
|
||||
"""Minimal mock of a Lazy event."""
|
||||
|
||||
|
|
Loading…
Reference in New Issue