diff --git a/homeassistant/components/sensor/statistics.py b/homeassistant/components/sensor/statistics.py index a6932e2aebb..19281d36d88 100644 --- a/homeassistant/components/sensor/statistics.py +++ b/homeassistant/components/sensor/statistics.py @@ -175,15 +175,20 @@ class StatisticsSensor(Entity): self._purge_old() if not self.is_binary: - try: + try: # require only one data point self.mean = round(statistics.mean(self.states), 2) self.median = round(statistics.median(self.states), 2) + except statistics.StatisticsError as err: + _LOGGER.error(err) + self.mean = self.median = STATE_UNKNOWN + + try: # require at least two data points self.stdev = round(statistics.stdev(self.states), 2) self.variance = round(statistics.variance(self.states), 2) except statistics.StatisticsError as err: _LOGGER.error(err) - self.mean = self.median = STATE_UNKNOWN self.stdev = self.variance = STATE_UNKNOWN + if self.states: self.total = round(sum(self.states), 2) self.min = min(self.states) diff --git a/tests/components/sensor/test_statistics.py b/tests/components/sensor/test_statistics.py index bfb8fb61f9b..48ebf720633 100644 --- a/tests/components/sensor/test_statistics.py +++ b/tests/components/sensor/test_statistics.py @@ -3,7 +3,8 @@ import unittest import statistics from homeassistant.setup import setup_component -from homeassistant.const import (ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS) +from homeassistant.const import ( + ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS, STATE_UNKNOWN) from homeassistant.util import dt as dt_util from tests.common import get_test_home_assistant from unittest.mock import patch @@ -106,6 +107,38 @@ class TestStatisticsSensor(unittest.TestCase): self.assertEqual(3.8, state.attributes.get('min_value')) self.assertEqual(14, state.attributes.get('max_value')) + def test_sampling_size_1(self): + """Test validity of stats requiring only one sample.""" + assert setup_component(self.hass, 'sensor', { + 'sensor': { + 'platform': 'statistics', + 'name': 'test', + 'entity_id': 'sensor.test_monitored', + 'sampling_size': 1, + } + }) + + for value in self.values[-3:]: # just the last 3 will do + self.hass.states.set('sensor.test_monitored', value, + {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}) + self.hass.block_till_done() + + state = self.hass.states.get('sensor.test_mean') + + # require only one data point + self.assertEqual(self.values[-1], state.attributes.get('min_value')) + self.assertEqual(self.values[-1], state.attributes.get('max_value')) + self.assertEqual(self.values[-1], state.attributes.get('mean')) + self.assertEqual(self.values[-1], state.attributes.get('median')) + self.assertEqual(self.values[-1], state.attributes.get('total')) + self.assertEqual(0, state.attributes.get('change')) + self.assertEqual(0, state.attributes.get('average_change')) + + # require at least two data points + self.assertEqual(STATE_UNKNOWN, state.attributes.get('variance')) + self.assertEqual(STATE_UNKNOWN, + state.attributes.get('standard_deviation')) + def test_max_age(self): """Test value deprecation.""" mock_data = {