8000 Initializing statistics sensor with data from database by ChristianKuehnel · Pull Request #9753 · home-assistant/core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Initializing statistics sensor with data from database #9753

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 40 additions & 8 deletions homeassistant/components/sensor/statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_state_change
from homeassistant.util import dt as dt_util
from homeassistant.components.recorder.util import session_scope, execute

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -88,27 +89,34 @@ def __init__(self, hass, entity_id, name, sampling_size, max_age):
self.min = self.max = self.total = self.count = 0
self.average_change = self.change = 0

if 'recorder' in self._hass.config.components:
# only use the database if it's configured
hass.async_add_job(self._initzialize_from_database)

@callback
# pylint: disable=invalid-name
def async_stats_sensor_state_listener(entity, old_state, new_state):
"""Handle the sensor state changes."""
self._unit_of_measurement = new_state.attributes.get(
ATTR_UNIT_OF_MEASUREMENT)

try:
self.states.append(float(new_state.state))
if self._max_age i 8000 s not None:
now = dt_util.utcnow()
self.ages.append(now)
self.count = self.count + 1
except ValueError:
self.count = self.count + 1
self._add_state_to_queue(new_state)

hass.async_add_job(self.async_update_ha_state, True)

async_track_state_change(
hass, entity_id, async_stats_sensor_state_listener)

def _add_state_to_queue(self, new_state):
try:
self.states.append(float(new_state.state))
if self._max_age is not None:
now = dt_util.utcnow()
self.ages.append(now)
self.count = self.count + 1
except ValueError:
self.count = self.count + 1

@property
def name(self):
"""Return the name of the sensor."""
Expand Down Expand Up @@ -187,3 +195,27 @@ def async_update(self):
else:
self.min = self.max = self.total = STATE_UNKNOWN
self.average_change = self.change = STATE_UNKNOWN

@asyncio.coroutine
def _initzialize_from_database(self):
"""Initialize the list of states from the database.

The query will get the list of states in DESCENDING order so that we
can limit the result to self._sample_size. Afterwards reverse the
list so that we get it in the right order again.
"""
from homeassistant.components.recorder.models import States
_LOGGER.debug("initializing values for %s from the database",
self.entity_id)

with session_scope(hass=self._hass) as session:
query = session.query(States)\
.filter(States.entity_id == self._entity_id.lower())\
.order_by(States.last_updated.desc())\
.limit(self._sampling_size)
states = execute(query)

for state in reversed(states):
self._add_state_to_queue(state)

_LOGGER.debug("initializing from database completed")
27 changes: 27 additions & 0 deletions tests/components/sensor/test_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from tests.common import get_test_home_assistant
from unittest.mock import patch
from datetime import datetime, timedelta
from tests.common import init_recorder_component
from homeassistant.components import recorder


class TestStatisticsSensor(unittest.TestCase):
Expand Down Expand Up @@ -135,3 +137,28 @@ def mock_now():

self.assertEqual(6, state.attributes.get('min_value'))
self.assertEqual(14, state.attributes.get('max_value'))

def test_initialize_from_database(self):
"""Test initializing the statistics from the database."""
# enable the recorder
init_recorder_component(self.hass)
# store some values
for value in self.values:
self.hass.states.set('sensor.test_monitored', value,
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS})
self.hass.block_till_done()
# wait for the recorder to really store the data
self.hass.data[recorder.DATA_INSTANCE].block_till_done()
# only now create the statistics component, so that it must read the
# data from the database
assert setup_component(self.hass, 'sensor', {
'sensor': {
'platform': 'statistics',
'name': 'test',
'entity_id': 'sensor.test_monitored',
'sampling_size': 100,
}
})
# check if the result is as in test_sensor_source()
state = self.hass.states.get('sensor.test_mean')
self.assertEqual(str(self.mean), state.state)
0