Suppress log warnings when a sensor group has non numeric members (#102828)
parent
c59345338e
commit
340df38bd0
|
@ -299,7 +299,7 @@ class SensorGroup(GroupEntity, SensorEntity):
|
||||||
unique_id: str | None,
|
unique_id: str | None,
|
||||||
name: str,
|
name: str,
|
||||||
entity_ids: list[str],
|
entity_ids: list[str],
|
||||||
mode: bool,
|
ignore_non_numeric: bool,
|
||||||
sensor_type: str,
|
sensor_type: str,
|
||||||
unit_of_measurement: str | None,
|
unit_of_measurement: str | None,
|
||||||
state_class: SensorStateClass | None,
|
state_class: SensorStateClass | None,
|
||||||
|
@ -318,7 +318,8 @@ class SensorGroup(GroupEntity, SensorEntity):
|
||||||
self._attr_name = f"{DEFAULT_NAME} {sensor_type}".capitalize()
|
self._attr_name = f"{DEFAULT_NAME} {sensor_type}".capitalize()
|
||||||
self._attr_extra_state_attributes = {ATTR_ENTITY_ID: entity_ids}
|
self._attr_extra_state_attributes = {ATTR_ENTITY_ID: entity_ids}
|
||||||
self._attr_unique_id = unique_id
|
self._attr_unique_id = unique_id
|
||||||
self.mode = all if mode is False else any
|
self._ignore_non_numeric = ignore_non_numeric
|
||||||
|
self.mode = all if ignore_non_numeric is False else any
|
||||||
self._state_calc: Callable[
|
self._state_calc: Callable[
|
||||||
[list[tuple[str, float, State]]],
|
[list[tuple[str, float, State]]],
|
||||||
tuple[dict[str, str | None], float | None],
|
tuple[dict[str, str | None], float | None],
|
||||||
|
@ -358,9 +359,14 @@ class SensorGroup(GroupEntity, SensorEntity):
|
||||||
sensor_values.append((entity_id, numeric_state, state))
|
sensor_values.append((entity_id, numeric_state, state))
|
||||||
if entity_id in self._state_incorrect:
|
if entity_id in self._state_incorrect:
|
||||||
self._state_incorrect.remove(entity_id)
|
self._state_incorrect.remove(entity_id)
|
||||||
|
valid_states.append(True)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
valid_states.append(False)
|
valid_states.append(False)
|
||||||
if entity_id not in self._state_incorrect:
|
# Log invalid states unless ignoring non numeric values
|
||||||
|
if (
|
||||||
|
not self._ignore_non_numeric
|
||||||
|
and entity_id not in self._state_incorrect
|
||||||
|
):
|
||||||
self._state_incorrect.add(entity_id)
|
self._state_incorrect.add(entity_id)
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Unable to use state. Only numerical states are supported,"
|
"Unable to use state. Only numerical states are supported,"
|
||||||
|
@ -388,8 +394,6 @@ class SensorGroup(GroupEntity, SensorEntity):
|
||||||
state.attributes.get("unit_of_measurement"),
|
state.attributes.get("unit_of_measurement"),
|
||||||
self.entity_id,
|
self.entity_id,
|
||||||
)
|
)
|
||||||
continue
|
|
||||||
valid_states.append(True)
|
|
||||||
|
|
||||||
# Set group as unavailable if all members do not have numeric values
|
# Set group as unavailable if all members do not have numeric values
|
||||||
self._attr_available = any(numeric_state for numeric_state in valid_states)
|
self._attr_available = any(numeric_state for numeric_state in valid_states)
|
||||||
|
|
|
@ -245,15 +245,15 @@ async def test_reload(hass: HomeAssistant) -> None:
|
||||||
assert hass.states.get("sensor.second_test")
|
assert hass.states.get("sensor.second_test")
|
||||||
|
|
||||||
|
|
||||||
async def test_sensor_incorrect_state(
|
async def test_sensor_incorrect_state_with_ignore_non_numeric(
|
||||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the min sensor."""
|
"""Test that non numeric values are ignored in a group."""
|
||||||
config = {
|
config = {
|
||||||
SENSOR_DOMAIN: {
|
SENSOR_DOMAIN: {
|
||||||
"platform": GROUP_DOMAIN,
|
"platform": GROUP_DOMAIN,
|
||||||
"name": "test_failure",
|
"name": "test_ignore_non_numeric",
|
||||||
"type": "min",
|
"type": "max",
|
||||||
"ignore_non_numeric": True,
|
"ignore_non_numeric": True,
|
||||||
"entities": ["sensor.test_1", "sensor.test_2", "sensor.test_3"],
|
"entities": ["sensor.test_1", "sensor.test_2", "sensor.test_3"],
|
||||||
"unique_id": "very_unique_id",
|
"unique_id": "very_unique_id",
|
||||||
|
@ -266,24 +266,63 @@ async def test_sensor_incorrect_state(
|
||||||
|
|
||||||
entity_ids = config["sensor"]["entities"]
|
entity_ids = config["sensor"]["entities"]
|
||||||
|
|
||||||
|
# Check that the final sensor value ignores the non numeric input
|
||||||
|
for entity_id, value in dict(zip(entity_ids, VALUES_ERROR)).items():
|
||||||
|
hass.states.async_set(entity_id, value)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.test_ignore_non_numeric")
|
||||||
|
assert state.state == "17.0"
|
||||||
|
assert (
|
||||||
|
"Unable to use state. Only numerical states are supported," not in caplog.text
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check that the final sensor value with all numeric inputs
|
||||||
|
for entity_id, value in dict(zip(entity_ids, VALUES)).items():
|
||||||
|
hass.states.async_set(entity_id, value)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.test_ignore_non_numeric")
|
||||||
|
assert state.state == "20.0"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_sensor_incorrect_state_with_not_ignore_non_numeric(
|
||||||
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
|
) -> None:
|
||||||
|
"""Test that non numeric values cause a group to be unknown."""
|
||||||
|
config = {
|
||||||
|
SENSOR_DOMAIN: {
|
||||||
|
"platform": GROUP_DOMAIN,
|
||||||
|
"name": "test_failure",
|
||||||
|
"type": "max",
|
||||||
|
"ignore_non_numeric": False,
|
||||||
|
"entities": ["sensor.test_1", "sensor.test_2", "sensor.test_3"],
|
||||||
|
"unique_id": "very_unique_id",
|
||||||
|
"state_class": SensorStateClass.MEASUREMENT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert await async_setup_component(hass, "sensor", config)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
entity_ids = config["sensor"]["entities"]
|
||||||
|
|
||||||
|
# Check that the final sensor value is unavailable if a non numeric input exists
|
||||||
for entity_id, value in dict(zip(entity_ids, VALUES_ERROR)).items():
|
for entity_id, value in dict(zip(entity_ids, VALUES_ERROR)).items():
|
||||||
hass.states.async_set(entity_id, value)
|
hass.states.async_set(entity_id, value)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("sensor.test_failure")
|
state = hass.states.get("sensor.test_failure")
|
||||||
|
assert state.state == "unknown"
|
||||||
|
assert "Unable to use state. Only numerical states are supported" in caplog.text
|
||||||
|
|
||||||
assert state.state == "15.3"
|
# Check that the final sensor value is correct with all numeric inputs
|
||||||
assert (
|
|
||||||
"Unable to use state. Only numerical states are supported, entity sensor.test_2 with value string excluded from calculation"
|
|
||||||
in caplog.text
|
|
||||||
)
|
|
||||||
|
|
||||||
for entity_id, value in dict(zip(entity_ids, VALUES)).items():
|
for entity_id, value in dict(zip(entity_ids, VALUES)).items():
|
||||||
hass.states.async_set(entity_id, value)
|
hass.states.async_set(entity_id, value)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
state = hass.states.get("sensor.test_failure")
|
state = hass.states.get("sensor.test_failure")
|
||||||
assert state.state == "15.3"
|
assert state.state == "20.0"
|
||||||
|
|
||||||
|
|
||||||
async def test_sensor_require_all_states(hass: HomeAssistant) -> None:
|
async def test_sensor_require_all_states(hass: HomeAssistant) -> None:
|
||||||
|
|
Loading…
Reference in New Issue