diff --git a/homeassistant/components/sensor/filter.py b/homeassistant/components/sensor/filter.py index 3d05dd28e79..92e2cc751ac 100644 --- a/homeassistant/components/sensor/filter.py +++ b/homeassistant/components/sensor/filter.py @@ -313,6 +313,7 @@ class Filter: self._entity = entity self._skip_processing = False self._window_size = window_size + self._store_raw = False @property def window_size(self): @@ -337,7 +338,10 @@ class Filter: """Implement a common interface for filters.""" filtered = self._filter_state(FilterState(new_state)) filtered.set_precision(self.precision) - self.states.append(copy(filtered)) + if self._store_raw: + self.states.append(copy(FilterState(new_state))) + else: + self.states.append(copy(filtered)) new_state.state = filtered.state return new_state @@ -402,12 +406,14 @@ class OutlierFilter(Filter): super().__init__(FILTER_NAME_OUTLIER, window_size, precision, entity) self._radius = radius self._stats_internal = Counter() + self._store_raw = True def _filter_state(self, new_state): """Implement the outlier filter.""" + median = statistics.median([s.state for s in self.states]) \ + if self.states else 0 if (len(self.states) == self.states.maxlen and - abs(new_state.state - - statistics.median([s.state for s in self.states])) > + abs(new_state.state - median) > self._radius): self._stats_internal['erasures'] += 1 @@ -415,7 +421,7 @@ class OutlierFilter(Filter): _LOGGER.debug("Outlier nr. %s in %s: %s", self._stats_internal['erasures'], self._entity, new_state) - return self.states[-1] + new_state.state = median return new_state diff --git a/tests/components/sensor/test_filter.py b/tests/components/sensor/test_filter.py index b43d38da5e8..29308f2a83d 100644 --- a/tests/components/sensor/test_filter.py +++ b/tests/components/sensor/test_filter.py @@ -106,6 +106,23 @@ class TestFilterSensor(unittest.TestCase): precision=2, entity=None, radius=4.0) + for state in self.values: + filtered = filt.filter_state(state) + assert 21 == filtered.state + + def test_outlier_step(self): + """ + Test step-change handling in outlier. + + Test if outlier filter handles long-running step-changes correctly. + It should converge to no longer filter once just over half the + window_size is occupied by the new post step-change values. + """ + filt = OutlierFilter(window_size=3, + precision=2, + entity=None, + radius=1.1) + self.values[-1].state = 22 for state in self.values: filtered = filt.filter_state(state) assert 22 == filtered.state @@ -119,7 +136,7 @@ class TestFilterSensor(unittest.TestCase): out = ha.State('sensor.test_monitored', 4000) for state in [out]+self.values: filtered = filt.filter_state(state) - assert 22 == filtered.state + assert 21 == filtered.state def test_lowpass(self): """Test if lowpass filter works."""