Modify behavior of media_player groups (#74056)

pull/74097/head
Erik Montnemery 2022-06-28 10:22:46 +02:00 committed by GitHub
parent c19a8ef8e0
commit 9a613aeb96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 26 deletions

View File

@ -103,6 +103,8 @@ async def async_setup_entry(
class MediaPlayerGroup(MediaPlayerEntity):
"""Representation of a Media Group."""
_attr_available: bool = False
def __init__(self, unique_id: str | None, name: str, entities: list[str]) -> None:
"""Initialize a Media Group entity."""
self._name = name
@ -390,19 +392,29 @@ class MediaPlayerGroup(MediaPlayerEntity):
@callback
def async_update_state(self) -> None:
"""Query all members and determine the media group state."""
states = [self.hass.states.get(entity) for entity in self._entities]
states_values = [state.state for state in states if state is not None]
off_values = STATE_OFF, STATE_UNAVAILABLE, STATE_UNKNOWN
states = [
state.state
for entity_id in self._entities
if (state := self.hass.states.get(entity_id)) is not None
]
if states_values:
if states_values.count(states_values[0]) == len(states_values):
self._state = states_values[0]
elif any(state for state in states_values if state not in off_values):
# Set group as unavailable if all members are unavailable or missing
self._attr_available = any(state != STATE_UNAVAILABLE for state in states)
valid_state = any(
state not in (STATE_UNKNOWN, STATE_UNAVAILABLE) for state in states
)
if not valid_state:
# Set as unknown if all members are unknown or unavailable
self._state = None
else:
off_values = (STATE_OFF, STATE_UNAVAILABLE, STATE_UNKNOWN)
if states.count(states[0]) == len(states):
self._state = states[0]
elif any(state for state in states if state not in off_values):
self._state = STATE_ON
else:
self._state = STATE_OFF
else:
self._state = None
supported_features = 0
if self._features[KEY_CLEAR_PLAYLIST]:

View File

@ -126,7 +126,23 @@ async def test_state_reporting(hass):
await hass.async_start()
await hass.async_block_till_done()
# Initial state with no group member in the state machine -> unknown
# Initial state with no group member in the state machine -> unavailable
assert hass.states.get("media_player.media_group").state == STATE_UNAVAILABLE
# All group members unavailable -> unavailable
hass.states.async_set("media_player.player_1", STATE_UNAVAILABLE)
hass.states.async_set("media_player.player_2", STATE_UNAVAILABLE)
await hass.async_block_till_done()
assert hass.states.get("media_player.media_group").state == STATE_UNAVAILABLE
# The group state is unknown if all group members are unknown or unavailable.
for state_1 in (
STATE_UNAVAILABLE,
STATE_UNKNOWN,
):
hass.states.async_set("media_player.player_1", state_1)
hass.states.async_set("media_player.player_2", STATE_UNKNOWN)
await hass.async_block_till_done()
assert hass.states.get("media_player.media_group").state == STATE_UNKNOWN
# All group members buffering -> buffering
@ -156,30 +172,18 @@ async def test_state_reporting(hass):
await hass.async_block_till_done()
assert hass.states.get("media_player.media_group").state == STATE_ON
# Otherwise off
for state_1 in (STATE_OFF, STATE_UNAVAILABLE, STATE_UNKNOWN):
hass.states.async_set("media_player.player_1", state_1)
hass.states.async_set("media_player.player_2", STATE_OFF)
await hass.async_block_till_done()
assert hass.states.get("media_player.media_group").state == STATE_OFF
# Otherwise off
for state_1 in (STATE_OFF, STATE_UNKNOWN):
hass.states.async_set("media_player.player_1", state_1)
hass.states.async_set("media_player.player_2", STATE_UNAVAILABLE)
await hass.async_block_till_done()
assert hass.states.get("media_player.media_group").state == STATE_OFF
for state_1 in (STATE_OFF, STATE_UNAVAILABLE):
hass.states.async_set("media_player.player_1", state_1)
hass.states.async_set("media_player.player_2", STATE_UNKNOWN)
await hass.async_block_till_done()
assert hass.states.get("media_player.media_group").state == STATE_OFF
# All group members removed from the state machine -> unknown
# All group members removed from the state machine -> unavailable
hass.states.async_remove("media_player.player_1")
hass.states.async_remove("media_player.player_2")
await hass.async_block_till_done()
assert hass.states.get("media_player.media_group").state == STATE_UNKNOWN
assert hass.states.get("media_player.media_group").state == STATE_UNAVAILABLE
async def test_supported_features(hass):