Enforce MediaPlayerState in group (#78465)
* Enforce MediaPlayerState in group * Adjust * Use self._attr_state * Add warning * Add group name to logger warning * Remove logger warning * Remove duplicate code * Add type hints to tests * Improve coverage * Improve coverage * suppress ValueErrorpull/78467/head
parent
b5aac9a1c7
commit
200f29563a
|
@ -1,6 +1,7 @@
|
|||
"""This platform allows several media players to be grouped into one media player."""
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import suppress
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
|
@ -108,7 +109,6 @@ class MediaPlayerGroup(MediaPlayerEntity):
|
|||
def __init__(self, unique_id: str | None, name: str, entities: list[str]) -> None:
|
||||
"""Initialize a Media Group entity."""
|
||||
self._name = name
|
||||
self._state: str | None = None
|
||||
self._attr_unique_id = unique_id
|
||||
|
||||
self._entities = entities
|
||||
|
@ -206,11 +206,6 @@ class MediaPlayerGroup(MediaPlayerEntity):
|
|||
"""Return the name of the entity."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def state(self) -> str | None:
|
||||
"""Return the state of the media group."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict:
|
||||
"""Return the state attributes for the media group."""
|
||||
|
@ -395,15 +390,17 @@ class MediaPlayerGroup(MediaPlayerEntity):
|
|||
)
|
||||
if not valid_state:
|
||||
# Set as unknown if all members are unknown or unavailable
|
||||
self._state = None
|
||||
self._attr_state = None
|
||||
else:
|
||||
off_values = {MediaPlayerState.OFF, STATE_UNAVAILABLE, STATE_UNKNOWN}
|
||||
if states.count(states[0]) == len(states):
|
||||
self._state = states[0]
|
||||
if states.count(single_state := states[0]) == len(states):
|
||||
self._attr_state = None
|
||||
with suppress(ValueError):
|
||||
self._attr_state = MediaPlayerState(single_state)
|
||||
elif any(state for state in states if state not in off_values):
|
||||
self._state = MediaPlayerState.ON
|
||||
self._attr_state = MediaPlayerState.ON
|
||||
else:
|
||||
self._state = MediaPlayerState.OFF
|
||||
self._attr_state = MediaPlayerState.OFF
|
||||
|
||||
supported_features = MediaPlayerEntityFeature(0)
|
||||
if self._features[KEY_CLEAR_PLAYLIST]:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""The tests for the Media group platform."""
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import async_timeout
|
||||
import pytest
|
||||
|
@ -43,6 +43,7 @@ from homeassistant.const import (
|
|||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
|
@ -57,7 +58,7 @@ def media_player_media_seek_fixture():
|
|||
yield seek
|
||||
|
||||
|
||||
async def test_default_state(hass):
|
||||
async def test_default_state(hass: HomeAssistant) -> None:
|
||||
"""Test media group default state."""
|
||||
hass.states.async_set("media_player.player_1", "on")
|
||||
await async_setup_component(
|
||||
|
@ -91,7 +92,7 @@ async def test_default_state(hass):
|
|||
assert entry.unique_id == "unique_identifier"
|
||||
|
||||
|
||||
async def test_state_reporting(hass):
|
||||
async def test_state_reporting(hass: HomeAssistant) -> None:
|
||||
"""Test the state reporting.
|
||||
|
||||
The group state is unavailable if all group members are unavailable.
|
||||
|
@ -170,6 +171,12 @@ async def test_state_reporting(hass):
|
|||
await hass.async_block_till_done()
|
||||
assert hass.states.get("media_player.media_group").state == STATE_OFF
|
||||
|
||||
# All group members in same invalid state -> unknown
|
||||
hass.states.async_set("media_player.player_1", "invalid_state")
|
||||
hass.states.async_set("media_player.player_2", "invalid_state")
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get("media_player.media_group").state == STATE_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")
|
||||
|
@ -177,7 +184,7 @@ async def test_state_reporting(hass):
|
|||
assert hass.states.get("media_player.media_group").state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
async def test_supported_features(hass):
|
||||
async def test_supported_features(hass: HomeAssistant) -> None:
|
||||
"""Test supported features reporting."""
|
||||
pause_play_stop = (
|
||||
MediaPlayerEntityFeature.PAUSE
|
||||
|
@ -241,7 +248,7 @@ async def test_supported_features(hass):
|
|||
assert state.attributes[ATTR_SUPPORTED_FEATURES] == pause_play_stop | play_media
|
||||
|
||||
|
||||
async def test_service_calls(hass, mock_media_seek):
|
||||
async def test_service_calls(hass: HomeAssistant, mock_media_seek: Mock) -> None:
|
||||
"""Test service calls."""
|
||||
await async_setup_component(
|
||||
hass,
|
||||
|
@ -533,7 +540,7 @@ async def test_service_calls(hass, mock_media_seek):
|
|||
assert hass.states.get("media_player.living_room").state == STATE_OFF
|
||||
|
||||
|
||||
async def test_nested_group(hass):
|
||||
async def test_nested_group(hass: HomeAssistant) -> None:
|
||||
"""Test nested media group."""
|
||||
await async_setup_component(
|
||||
hass,
|
||||
|
|
Loading…
Reference in New Issue