Fix filter sensor None state (#44439)

Co-authored-by: Franck Nijhof <frenck@frenck.dev>
This commit is contained in:
Diogo Gomes 2020-12-24 01:24:11 +00:00 committed by GitHub
parent 6b743c3d16
commit 2d131823ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 87 additions and 4 deletions

View File

@ -197,7 +197,15 @@ class SensorFilter(Entity):
@callback
def _update_filter_sensor_state(self, new_state, update_ha=True):
"""Process device state changes."""
if new_state is None or new_state.state in [STATE_UNKNOWN, STATE_UNAVAILABLE]:
if new_state is None:
_LOGGER.warning(
"While updating filter %s, the new_state is None", self._name
)
self._state = None
self.async_write_ha_state()
return
if new_state.state in [STATE_UNKNOWN, STATE_UNAVAILABLE]:
self._state = new_state.state
self.async_write_ha_state()
return
@ -218,7 +226,11 @@ class SensorFilter(Entity):
return
temp_state = filtered_state
except ValueError:
_LOGGER.error("Could not convert state: %s to number", self._state)
_LOGGER.error(
"Could not convert state: %s (%s) to number",
new_state.state,
type(new_state.state),
)
return
self._state = temp_state.state
@ -425,7 +437,7 @@ class Filter:
"""Implement a common interface for filters."""
fstate = FilterState(new_state)
if self._only_numbers and not isinstance(fstate.state, Number):
raise ValueError
raise ValueError(f"State <{fstate.state}> is not a Number")
filtered = self._filter_state(fstate)
filtered.set_precision(self.precision)

View File

@ -15,7 +15,7 @@ from homeassistant.components.filter.sensor import (
TimeThrottleFilter,
)
from homeassistant.components.sensor import DEVICE_CLASS_TEMPERATURE
from homeassistant.const import SERVICE_RELOAD, STATE_UNAVAILABLE
from homeassistant.const import SERVICE_RELOAD, STATE_UNAVAILABLE, STATE_UNKNOWN
import homeassistant.core as ha
from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util
@ -136,6 +136,71 @@ async def test_chain_history(hass, values, missing=False):
assert "17.05" == state.state
async def test_source_state_none(hass, values):
"""Test is source sensor state is null and sets state to STATE_UNKNOWN."""
await async_init_recorder_component(hass)
config = {
"sensor": [
{
"platform": "template",
"sensors": {
"template_test": {
"value_template": "{{ states.sensor.test_state.state }}"
}
},
},
{
"platform": "filter",
"name": "test",
"entity_id": "sensor.template_test",
"filters": [
{
"filter": "time_simple_moving_average",
"window_size": "00:01",
"precision": "2",
}
],
},
]
}
await async_setup_component(hass, "sensor", config)
await hass.async_block_till_done()
hass.states.async_set("sensor.test_state", 0)
await hass.async_block_till_done()
state = hass.states.get("sensor.template_test")
assert state.state == "0"
await hass.async_block_till_done()
state = hass.states.get("sensor.test")
assert state.state == "0.0"
# Force Template Reload
yaml_path = path.join(
_get_fixtures_base_path(),
"fixtures",
"template/sensor_configuration.yaml",
)
with patch.object(hass_config, "YAML_CONFIG_FILE", yaml_path):
await hass.services.async_call(
"template",
SERVICE_RELOAD,
{},
blocking=True,
)
await hass.async_block_till_done()
# Template state gets to None
state = hass.states.get("sensor.template_test")
assert state is None
# Filter sensor ignores None state setting state to STATE_UNKNOWN
state = hass.states.get("sensor.test")
assert state.state == STATE_UNKNOWN
async def test_chain_history_missing(hass, values):
"""Test if filter chaining works when recorder is enabled but the source is not recorded."""
await test_chain_history(hass, values, missing=True)
@ -239,6 +304,12 @@ async def test_invalid_state(hass):
state = hass.states.get("sensor.test")
assert state.state == STATE_UNAVAILABLE
hass.states.async_set("sensor.test_monitored", "invalid")
await hass.async_block_till_done()
state = hass.states.get("sensor.test")
assert state.state == STATE_UNAVAILABLE
async def test_outlier(values):
"""Test if outlier filter works."""