mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 08:17:08 +00:00
Merge pull request #1482 from balloob/history-significant-states
History: update significant states
This commit is contained in:
commit
18f48191d9
@ -11,7 +11,7 @@ from collections import defaultdict
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
|
|
||||||
import homeassistant.components.recorder as recorder
|
from homeassistant.components import recorder, script
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
from homeassistant.const import HTTP_BAD_REQUEST
|
from homeassistant.const import HTTP_BAD_REQUEST
|
||||||
|
|
||||||
@ -19,6 +19,7 @@ DOMAIN = 'history'
|
|||||||
DEPENDENCIES = ['recorder', 'http']
|
DEPENDENCIES = ['recorder', 'http']
|
||||||
|
|
||||||
SIGNIFICANT_DOMAINS = ('thermostat',)
|
SIGNIFICANT_DOMAINS = ('thermostat',)
|
||||||
|
IGNORE_DOMAINS = ('zone', 'scene',)
|
||||||
|
|
||||||
URL_HISTORY_PERIOD = re.compile(
|
URL_HISTORY_PERIOD = re.compile(
|
||||||
r'/api/history/period(?:/(?P<date>\d{4}-\d{1,2}-\d{1,2})|)')
|
r'/api/history/period(?:/(?P<date>\d{4}-\d{1,2}-\d{1,2})|)')
|
||||||
@ -46,9 +47,10 @@ def get_significant_states(start_time, end_time=None, entity_id=None):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
where = """
|
where = """
|
||||||
(domain in ({}) or last_changed=last_updated)
|
(domain IN ({}) OR last_changed=last_updated)
|
||||||
AND last_updated > ?
|
AND domain NOT IN ({}) AND last_updated > ?
|
||||||
""".format(",".join(["'%s'" % x for x in SIGNIFICANT_DOMAINS]))
|
""".format(",".join("'%s'" % x for x in SIGNIFICANT_DOMAINS),
|
||||||
|
",".join("'%s'" % x for x in IGNORE_DOMAINS))
|
||||||
|
|
||||||
data = [start_time]
|
data = [start_time]
|
||||||
|
|
||||||
@ -63,7 +65,8 @@ def get_significant_states(start_time, end_time=None, entity_id=None):
|
|||||||
query = ("SELECT * FROM states WHERE {} "
|
query = ("SELECT * FROM states WHERE {} "
|
||||||
"ORDER BY entity_id, last_updated ASC").format(where)
|
"ORDER BY entity_id, last_updated ASC").format(where)
|
||||||
|
|
||||||
states = recorder.query_states(query, data)
|
states = (state for state in recorder.query_states(query, data)
|
||||||
|
if _is_significant(state))
|
||||||
|
|
||||||
return states_to_json(states, start_time, entity_id)
|
return states_to_json(states, start_time, entity_id)
|
||||||
|
|
||||||
@ -200,3 +203,13 @@ def _api_history_period(handler, path_match, data):
|
|||||||
|
|
||||||
handler.write_json(
|
handler.write_json(
|
||||||
get_significant_states(start_time, end_time, entity_id).values())
|
get_significant_states(start_time, end_time, entity_id).values())
|
||||||
|
|
||||||
|
|
||||||
|
def _is_significant(state):
|
||||||
|
"""Test if state is significant for history charts.
|
||||||
|
|
||||||
|
Will only test for things that are not filtered out in SQL.
|
||||||
|
"""
|
||||||
|
# scripts that are not cancellable will never change state
|
||||||
|
return (state.domain != 'script' or
|
||||||
|
state.attributes.get(script.ATTR_CAN_CANCEL))
|
||||||
|
@ -148,7 +148,7 @@ class TestComponentHistory(unittest.TestCase):
|
|||||||
"""test that only significant states are returned with
|
"""test that only significant states are returned with
|
||||||
get_significant_states.
|
get_significant_states.
|
||||||
|
|
||||||
We inject a bunch of state updates from media player and
|
We inject a bunch of state updates from media player, zone and
|
||||||
thermostat. We should get back every thermostat change that
|
thermostat. We should get back every thermostat change that
|
||||||
includes an attribute change, but only the state updates for
|
includes an attribute change, but only the state updates for
|
||||||
media player (attribute changes are not significant and not returned).
|
media player (attribute changes are not significant and not returned).
|
||||||
@ -157,6 +157,9 @@ class TestComponentHistory(unittest.TestCase):
|
|||||||
self.init_recorder()
|
self.init_recorder()
|
||||||
mp = 'media_player.test'
|
mp = 'media_player.test'
|
||||||
therm = 'thermostat.test'
|
therm = 'thermostat.test'
|
||||||
|
zone = 'zone.home'
|
||||||
|
script_nc = 'script.cannot_cancel_this_one'
|
||||||
|
script_c = 'script.can_cancel_this_one'
|
||||||
|
|
||||||
def set_state(entity_id, state, **kwargs):
|
def set_state(entity_id, state, **kwargs):
|
||||||
self.hass.states.set(entity_id, state, **kwargs)
|
self.hass.states.set(entity_id, state, **kwargs)
|
||||||
@ -169,7 +172,7 @@ class TestComponentHistory(unittest.TestCase):
|
|||||||
three = two + timedelta(seconds=1)
|
three = two + timedelta(seconds=1)
|
||||||
four = three + timedelta(seconds=1)
|
four = three + timedelta(seconds=1)
|
||||||
|
|
||||||
states = {therm: [], mp: []}
|
states = {therm: [], mp: [], script_c: []}
|
||||||
with patch('homeassistant.components.recorder.dt_util.utcnow',
|
with patch('homeassistant.components.recorder.dt_util.utcnow',
|
||||||
return_value=one):
|
return_value=one):
|
||||||
states[mp].append(
|
states[mp].append(
|
||||||
@ -186,6 +189,11 @@ class TestComponentHistory(unittest.TestCase):
|
|||||||
# this state will be skipped only different in time
|
# this state will be skipped only different in time
|
||||||
set_state(mp, 'YouTube',
|
set_state(mp, 'YouTube',
|
||||||
attributes={'media_title': str(sentinel.mt3)})
|
attributes={'media_title': str(sentinel.mt3)})
|
||||||
|
# this state will be skipped because domain blacklisted
|
||||||
|
set_state(zone, 'zoning')
|
||||||
|
set_state(script_nc, 'off')
|
||||||
|
states[script_c].append(
|
||||||
|
set_state(script_c, 'off', attributes={'can_cancel': True}))
|
||||||
states[therm].append(
|
states[therm].append(
|
||||||
set_state(therm, 21, attributes={'current_temperature': 19.8}))
|
set_state(therm, 21, attributes={'current_temperature': 19.8}))
|
||||||
|
|
||||||
@ -199,4 +207,4 @@ class TestComponentHistory(unittest.TestCase):
|
|||||||
set_state(therm, 21, attributes={'current_temperature': 20}))
|
set_state(therm, 21, attributes={'current_temperature': 20}))
|
||||||
|
|
||||||
hist = history.get_significant_states(zero, four)
|
hist = history.get_significant_states(zero, four)
|
||||||
self.assertEqual(states, hist)
|
assert states == hist
|
||||||
|
Loading…
x
Reference in New Issue
Block a user