Fix statistics sensor mean and median when only one sample is available. (#11180)
* Fix statistics sensor mean and median when only one sample is available. With only one data point stddev and variance throw an exception. This would clear the (valid) mean and median calculations. Separate the try..catch blocks for one-or-more and two-or-more stats so that this doesn't happen. Test this with a new sampling_size_1 test. * test_statistics trivial whitespace fixpull/11232/head
parent
061395d2f8
commit
ef22a6e18d
|
@ -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)
|
||||
|
|
|
@ -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 = {
|
||||
|
|
Loading…
Reference in New Issue