Improve binary sensor group when member is unknown or unavailable (#67468)
This commit is contained in:
parent
5b8cf379a3
commit
c5dd5e18c0
2 changed files with 33 additions and 5 deletions
|
@ -17,6 +17,7 @@ from homeassistant.const import (
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
STATE_ON,
|
STATE_ON,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
|
STATE_UNKNOWN,
|
||||||
)
|
)
|
||||||
from homeassistant.core import Event, HomeAssistant, callback
|
from homeassistant.core import Event, HomeAssistant, callback
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
@ -80,7 +81,6 @@ class BinarySensorGroup(GroupEntity, BinarySensorEntity):
|
||||||
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._device_class = device_class
|
self._device_class = device_class
|
||||||
self._state: str | None = None
|
|
||||||
self.mode = any
|
self.mode = any
|
||||||
if mode:
|
if mode:
|
||||||
self.mode = all
|
self.mode = all
|
||||||
|
@ -106,13 +106,23 @@ class BinarySensorGroup(GroupEntity, BinarySensorEntity):
|
||||||
def async_update_group_state(self) -> None:
|
def async_update_group_state(self) -> None:
|
||||||
"""Query all members and determine the binary sensor group state."""
|
"""Query all members and determine the binary sensor group state."""
|
||||||
all_states = [self.hass.states.get(x) for x in self._entity_ids]
|
all_states = [self.hass.states.get(x) for x in self._entity_ids]
|
||||||
|
|
||||||
|
# filtered_states are members currently in the state machine
|
||||||
filtered_states: list[str] = [x.state for x in all_states if x is not None]
|
filtered_states: list[str] = [x.state for x in all_states if x is not None]
|
||||||
|
|
||||||
|
# Set group as unavailable if all members are unavailable
|
||||||
self._attr_available = any(
|
self._attr_available = any(
|
||||||
state != STATE_UNAVAILABLE for state in filtered_states
|
state != STATE_UNAVAILABLE for state in filtered_states
|
||||||
)
|
)
|
||||||
if STATE_UNAVAILABLE in filtered_states:
|
|
||||||
|
valid_state = self.mode(
|
||||||
|
state not in (STATE_UNKNOWN, STATE_UNAVAILABLE) for state in filtered_states
|
||||||
|
)
|
||||||
|
if not valid_state:
|
||||||
|
# Set as unknown if any / all member is not unknown or unavailable
|
||||||
self._attr_is_on = None
|
self._attr_is_on = None
|
||||||
else:
|
else:
|
||||||
|
# Set as ON if any / all member is ON
|
||||||
states = list(map(lambda x: x == STATE_ON, filtered_states))
|
states = list(map(lambda x: x == STATE_ON, filtered_states))
|
||||||
state = self.mode(states)
|
state = self.mode(states)
|
||||||
self._attr_is_on = state
|
self._attr_is_on = state
|
||||||
|
|
|
@ -95,6 +95,16 @@ async def test_state_reporting_all(hass):
|
||||||
hass.states.get("binary_sensor.binary_sensor_group").state == STATE_UNAVAILABLE
|
hass.states.get("binary_sensor.binary_sensor_group").state == STATE_UNAVAILABLE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
hass.states.async_set("binary_sensor.test1", STATE_ON)
|
||||||
|
hass.states.async_set("binary_sensor.test2", STATE_UNKNOWN)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("binary_sensor.binary_sensor_group").state == STATE_UNKNOWN
|
||||||
|
|
||||||
|
hass.states.async_set("binary_sensor.test1", STATE_UNKNOWN)
|
||||||
|
hass.states.async_set("binary_sensor.test2", STATE_UNKNOWN)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("binary_sensor.binary_sensor_group").state == STATE_UNKNOWN
|
||||||
|
|
||||||
|
|
||||||
async def test_state_reporting_any(hass):
|
async def test_state_reporting_any(hass):
|
||||||
"""Test the state reporting."""
|
"""Test the state reporting."""
|
||||||
|
@ -116,11 +126,10 @@ async def test_state_reporting_any(hass):
|
||||||
await hass.async_start()
|
await hass.async_start()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# binary sensors have state off if unavailable
|
|
||||||
hass.states.async_set("binary_sensor.test1", STATE_ON)
|
hass.states.async_set("binary_sensor.test1", STATE_ON)
|
||||||
hass.states.async_set("binary_sensor.test2", STATE_UNAVAILABLE)
|
hass.states.async_set("binary_sensor.test2", STATE_UNAVAILABLE)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.get("binary_sensor.binary_sensor_group").state == STATE_UNKNOWN
|
assert hass.states.get("binary_sensor.binary_sensor_group").state == STATE_ON
|
||||||
|
|
||||||
hass.states.async_set("binary_sensor.test1", STATE_ON)
|
hass.states.async_set("binary_sensor.test1", STATE_ON)
|
||||||
hass.states.async_set("binary_sensor.test2", STATE_OFF)
|
hass.states.async_set("binary_sensor.test2", STATE_OFF)
|
||||||
|
@ -137,7 +146,6 @@ async def test_state_reporting_any(hass):
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.get("binary_sensor.binary_sensor_group").state == STATE_ON
|
assert hass.states.get("binary_sensor.binary_sensor_group").state == STATE_ON
|
||||||
|
|
||||||
# binary sensors have state off if unavailable
|
|
||||||
hass.states.async_set("binary_sensor.test1", STATE_UNAVAILABLE)
|
hass.states.async_set("binary_sensor.test1", STATE_UNAVAILABLE)
|
||||||
hass.states.async_set("binary_sensor.test2", STATE_UNAVAILABLE)
|
hass.states.async_set("binary_sensor.test2", STATE_UNAVAILABLE)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
@ -149,3 +157,13 @@ async def test_state_reporting_any(hass):
|
||||||
entry = entity_registry.async_get("binary_sensor.binary_sensor_group")
|
entry = entity_registry.async_get("binary_sensor.binary_sensor_group")
|
||||||
assert entry
|
assert entry
|
||||||
assert entry.unique_id == "unique_identifier"
|
assert entry.unique_id == "unique_identifier"
|
||||||
|
|
||||||
|
hass.states.async_set("binary_sensor.test1", STATE_ON)
|
||||||
|
hass.states.async_set("binary_sensor.test2", STATE_UNKNOWN)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("binary_sensor.binary_sensor_group").state == STATE_ON
|
||||||
|
|
||||||
|
hass.states.async_set("binary_sensor.test1", STATE_UNKNOWN)
|
||||||
|
hass.states.async_set("binary_sensor.test2", STATE_UNKNOWN)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("binary_sensor.binary_sensor_group").state == STATE_UNKNOWN
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue