From 44477f3d322b3e31c7d94141b7de01faf64e507a Mon Sep 17 00:00:00 2001 From: Nikolay Vasilchuk Date: Thu, 11 Oct 2018 15:15:04 +0300 Subject: [PATCH] Logbook: filter by entity and period (#17095) * Filter logbook by entity_id * Filter logbook by period * Simple test * houndci-bot review * Tests * Test fix * Test Fix --- homeassistant/components/logbook.py | 19 ++++-- tests/components/test_logbook.py | 89 ++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/logbook.py b/homeassistant/components/logbook.py index 9e66c8d3aca..5cbd2b9432b 100644 --- a/homeassistant/components/logbook.py +++ b/homeassistant/components/logbook.py @@ -133,14 +133,21 @@ class LogbookView(HomeAssistantView): else: datetime = dt_util.start_of_local_day() - start_day = dt_util.as_utc(datetime) - end_day = start_day + timedelta(days=1) + period = request.query.get('period') + if period is None: + period = 1 + else: + period = int(period) + + entity_id = request.query.get('entity') + start_day = dt_util.as_utc(datetime) - timedelta(days=period - 1) + end_day = start_day + timedelta(days=period) hass = request.app['hass'] def json_events(): """Fetch events and generate JSON.""" return self.json(list( - _get_events(hass, self.config, start_day, end_day))) + _get_events(hass, self.config, start_day, end_day, entity_id))) return await hass.async_add_job(json_events) @@ -288,7 +295,7 @@ def humanify(hass, events): } -def _get_events(hass, config, start_day, end_day): +def _get_events(hass, config, start_day, end_day, entity_id=None): """Get events for a period of time.""" from homeassistant.components.recorder.models import Events, States from homeassistant.components.recorder.util import ( @@ -302,6 +309,10 @@ def _get_events(hass, config, start_day, end_day): & (Events.time_fired < end_day)) \ .filter((States.last_updated == States.last_changed) | (States.state_id.is_(None))) + + if entity_id is not None: + query = query.filter(States.entity_id == entity_id.lower()) + events = execute(query) return humanify(hass, _exclude_events(events, config)) diff --git a/tests/components/test_logbook.py b/tests/components/test_logbook.py index 8e7c2299731..3bb3ae57c68 100644 --- a/tests/components/test_logbook.py +++ b/tests/components/test_logbook.py @@ -1,7 +1,7 @@ """The tests for the logbook component.""" # pylint: disable=protected-access,invalid-name import logging -from datetime import timedelta +from datetime import (timedelta, datetime) import unittest from homeassistant.components import sun @@ -558,6 +558,93 @@ async def test_logbook_view(hass, aiohttp_client): assert response.status == 200 +async def test_logbook_view_period_entity(hass, aiohttp_client): + """Test the logbook view with period and entity.""" + await hass.async_add_job(init_recorder_component, hass) + await async_setup_component(hass, 'logbook', {}) + await hass.components.recorder.wait_connection_ready() + await hass.async_add_job(hass.data[recorder.DATA_INSTANCE].block_till_done) + + entity_id_test = 'switch.test' + hass.states.async_set(entity_id_test, STATE_OFF) + hass.states.async_set(entity_id_test, STATE_ON) + entity_id_second = 'switch.second' + hass.states.async_set(entity_id_second, STATE_OFF) + hass.states.async_set(entity_id_second, STATE_ON) + await hass.async_block_till_done() + await hass.async_add_job(hass.data[recorder.DATA_INSTANCE].block_till_done) + + client = await aiohttp_client(hass.http.app) + + # Today time 00:00:00 + start = dt_util.utcnow().date() + start_date = datetime(start.year, start.month, start.day) + + # Test today entries without filters + response = await client.get( + '/api/logbook/{}'.format(start_date.isoformat())) + assert response.status == 200 + json = await response.json() + assert len(json) == 2 + assert json[0]['entity_id'] == entity_id_test + assert json[1]['entity_id'] == entity_id_second + + # Test today entries with filter by period + response = await client.get( + '/api/logbook/{}?period=1'.format(start_date.isoformat())) + assert response.status == 200 + json = await response.json() + assert len(json) == 2 + assert json[0]['entity_id'] == entity_id_test + assert json[1]['entity_id'] == entity_id_second + + # Test today entries with filter by entity_id + response = await client.get( + '/api/logbook/{}?entity=switch.test'.format( + start_date.isoformat())) + assert response.status == 200 + json = await response.json() + assert len(json) == 1 + assert json[0]['entity_id'] == entity_id_test + + # Test entries for 3 days with filter by entity_id + response = await client.get( + '/api/logbook/{}?period=3&entity=switch.test'.format( + start_date.isoformat())) + assert response.status == 200 + json = await response.json() + assert len(json) == 1 + assert json[0]['entity_id'] == entity_id_test + + # Tomorrow time 00:00:00 + start = (dt_util.utcnow() + timedelta(days=1)).date() + start_date = datetime(start.year, start.month, start.day) + + # Test tomorrow entries without filters + response = await client.get( + '/api/logbook/{}'.format(start_date.isoformat())) + assert response.status == 200 + json = await response.json() + assert len(json) == 0 + + # Test tomorrow entries with filter by entity_id + response = await client.get( + '/api/logbook/{}?entity=switch.test'.format( + start_date.isoformat())) + assert response.status == 200 + json = await response.json() + assert len(json) == 0 + + # Test entries from tomorrow to 3 days ago with filter by entity_id + response = await client.get( + '/api/logbook/{}?period=3&entity=switch.test'.format( + start_date.isoformat())) + assert response.status == 200 + json = await response.json() + assert len(json) == 1 + assert json[0]['entity_id'] == entity_id_test + + async def test_humanify_alexa_event(hass): """Test humanifying Alexa event.""" hass.states.async_set('light.kitchen', 'on', {