mirror of
https://github.com/home-assistant/core.git
synced 2025-04-19 14:57:52 +00:00
Bang & Olufsen add beolink grouping (#113438)
* Add Beolink custom services Add support for media player grouping via beolink Give media player entity name * Fix progress not being set to None as Beolink listener Revert naming changes * Update API simplify Beolink attributes * Improve beolink custom services * Fix Beolink expandable source check Add unexpand return value Set entity name on initialization * Handle entity naming as intended * Fix "null" Beolink self friendly name * Add regex service input validation Add all_discovered to beolink_expand service Improve beolink_expand response * Add service icons * Fix merge Remove unnecessary assignment * Remove invalid typing Update response typing for updated API * Revert to old typed response dict method Remove mypy ignore line Fix jid possibly used before assignment * Re add debugging logging * Fix coroutine Fix formatting * Remove unnecessary update control * Make tests pass Fix remote leader media position bug Improve remote leader BangOlufsenSource comparison * Fix naming and add callback decorators * Move regex service check to variable Suppress KeyError Update tests * Re-add hass running check * Improve comments, naming and type hinting * Remove old temporary fix * Convert logged warning to raised exception for invalid media_player Simplify code using walrus operator * Fix test for invalid media_player grouping * Improve method naming * Improve _beolink_sources explanation * Improve _beolink_sources explanation * Fix tests * Remove service responses Fix and add tests * Change service to action where applicable * Show playback progress for listeners * Fix testing * Remove useless initialization * Fix allstandby name * Fix various casts with assertions Fix comment placement Fix group leader group_members rebase error Replace entity_id method call with attribute * Add syrupy snapshots for Beolink tests, checking entity states Use test JIDs 3 and 4 instead of 2 and 3 to avoid invalid attributes in testing * Add sections for fields using Beolink JIDs directly * Fix typo * FIx rebase mistake * Sort actions alphabetically
This commit is contained in:
parent
ed1366f463
commit
e3dfa84d65
9
homeassistant/components/bang_olufsen/icons.json
Normal file
9
homeassistant/components/bang_olufsen/icons.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"services": {
|
||||
"beolink_join": { "service": "mdi:location-enter" },
|
||||
"beolink_expand": { "service": "mdi:location-enter" },
|
||||
"beolink_unexpand": { "service": "mdi:location-exit" },
|
||||
"beolink_leave": { "service": "mdi:close-circle-outline" },
|
||||
"beolink_allstandby": { "service": "mdi:close-circle-multiple-outline" }
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ from typing import TYPE_CHECKING, Any, cast
|
||||
|
||||
from aiohttp import ClientConnectorError
|
||||
from mozart_api import __version__ as MOZART_API_VERSION
|
||||
from mozart_api.exceptions import ApiException
|
||||
from mozart_api.exceptions import ApiException, NotFoundException
|
||||
from mozart_api.models import (
|
||||
Action,
|
||||
Art,
|
||||
@ -38,6 +38,7 @@ from mozart_api.models import (
|
||||
VolumeState,
|
||||
)
|
||||
from mozart_api.mozart_client import MozartClient, get_highest_resolution_artwork
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import media_source
|
||||
from homeassistant.components.media_player import (
|
||||
@ -55,10 +56,17 @@ from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_MODEL, Platform
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
device_registry as dr,
|
||||
entity_registry as er,
|
||||
)
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.entity_platform import (
|
||||
AddEntitiesCallback,
|
||||
async_get_current_platform,
|
||||
)
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
||||
from . import BangOlufsenConfigEntry
|
||||
@ -116,6 +124,58 @@ async def async_setup_entry(
|
||||
]
|
||||
)
|
||||
|
||||
# Register actions.
|
||||
platform = async_get_current_platform()
|
||||
|
||||
jid_regex = vol.Match(
|
||||
r"(^\d{4})[.](\d{7})[.](\d{8})(@products\.bang-olufsen\.com)$"
|
||||
)
|
||||
|
||||
platform.async_register_entity_service(
|
||||
name="beolink_join",
|
||||
schema={vol.Optional("beolink_jid"): jid_regex},
|
||||
func="async_beolink_join",
|
||||
)
|
||||
|
||||
platform.async_register_entity_service(
|
||||
name="beolink_expand",
|
||||
schema={
|
||||
vol.Exclusive("all_discovered", "devices", ""): cv.boolean,
|
||||
vol.Exclusive(
|
||||
"beolink_jids",
|
||||
"devices",
|
||||
"Define either specific Beolink JIDs or all discovered",
|
||||
): vol.All(
|
||||
cv.ensure_list,
|
||||
[jid_regex],
|
||||
),
|
||||
},
|
||||
func="async_beolink_expand",
|
||||
)
|
||||
|
||||
platform.async_register_entity_service(
|
||||
name="beolink_unexpand",
|
||||
schema={
|
||||
vol.Required("beolink_jids"): vol.All(
|
||||
cv.ensure_list,
|
||||
[jid_regex],
|
||||
),
|
||||
},
|
||||
func="async_beolink_unexpand",
|
||||
)
|
||||
|
||||
platform.async_register_entity_service(
|
||||
name="beolink_leave",
|
||||
schema=None,
|
||||
func="async_beolink_leave",
|
||||
)
|
||||
|
||||
platform.async_register_entity_service(
|
||||
name="beolink_allstandby",
|
||||
schema=None,
|
||||
func="async_beolink_allstandby",
|
||||
)
|
||||
|
||||
|
||||
class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
"""Representation of a media player."""
|
||||
@ -156,6 +216,8 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
# Beolink compatible sources
|
||||
self._beolink_sources: dict[str, bool] = {}
|
||||
self._remote_leader: BeolinkLeader | None = None
|
||||
# Extra state attributes for showing Beolink: peer(s), listener(s), leader and self
|
||||
self._beolink_attributes: dict[str, dict[str, dict[str, str]]] = {}
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Turn on the dispatchers."""
|
||||
@ -165,6 +227,7 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
CONNECTION_STATUS: self._async_update_connection_state,
|
||||
WebsocketNotification.ACTIVE_LISTENING_MODE: self._async_update_sound_modes,
|
||||
WebsocketNotification.BEOLINK: self._async_update_beolink,
|
||||
WebsocketNotification.CONFIGURATION: self._async_update_name_and_beolink,
|
||||
WebsocketNotification.PLAYBACK_ERROR: self._async_update_playback_error,
|
||||
WebsocketNotification.PLAYBACK_METADATA: self._async_update_playback_metadata_and_beolink,
|
||||
WebsocketNotification.PLAYBACK_PROGRESS: self._async_update_playback_progress,
|
||||
@ -230,6 +293,9 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
|
||||
await self._async_update_sound_modes()
|
||||
|
||||
# Update beolink attributes and device name.
|
||||
await self._async_update_name_and_beolink()
|
||||
|
||||
async def async_update(self) -> None:
|
||||
"""Update queue settings."""
|
||||
# The WebSocket event listener is the main handler for connection state.
|
||||
@ -372,9 +438,44 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def _async_update_name_and_beolink(self) -> None:
|
||||
"""Update the device friendly name."""
|
||||
beolink_self = await self._client.get_beolink_self()
|
||||
|
||||
# Update device name
|
||||
device_registry = dr.async_get(self.hass)
|
||||
assert self.device_entry is not None
|
||||
|
||||
device_registry.async_update_device(
|
||||
device_id=self.device_entry.id,
|
||||
name=beolink_self.friendly_name,
|
||||
)
|
||||
|
||||
await self._async_update_beolink()
|
||||
|
||||
async def _async_update_beolink(self) -> None:
|
||||
"""Update the current Beolink leader, listeners, peers and self."""
|
||||
|
||||
self._beolink_attributes = {}
|
||||
|
||||
assert self.device_entry is not None
|
||||
assert self.device_entry.name is not None
|
||||
|
||||
# Add Beolink self
|
||||
self._beolink_attributes = {
|
||||
"beolink": {"self": {self.device_entry.name: self._beolink_jid}}
|
||||
}
|
||||
|
||||
# Add Beolink peers
|
||||
peers = await self._client.get_beolink_peers()
|
||||
|
||||
if len(peers) > 0:
|
||||
self._beolink_attributes["beolink"]["peers"] = {}
|
||||
for peer in peers:
|
||||
self._beolink_attributes["beolink"]["peers"][peer.friendly_name] = (
|
||||
peer.jid
|
||||
)
|
||||
|
||||
# Add Beolink listeners / leader
|
||||
self._remote_leader = self._playback_metadata.remote_leader
|
||||
|
||||
@ -394,9 +495,14 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
# Add self
|
||||
group_members.append(self.entity_id)
|
||||
|
||||
self._beolink_attributes["beolink"]["leader"] = {
|
||||
self._remote_leader.friendly_name: self._remote_leader.jid,
|
||||
}
|
||||
|
||||
# If not listener, check if leader.
|
||||
else:
|
||||
beolink_listeners = await self._client.get_beolink_listeners()
|
||||
beolink_listeners_attribute = {}
|
||||
|
||||
# Check if the device is a leader.
|
||||
if len(beolink_listeners) > 0:
|
||||
@ -417,6 +523,18 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
for beolink_listener in beolink_listeners
|
||||
]
|
||||
)
|
||||
# Update Beolink attributes
|
||||
for beolink_listener in beolink_listeners:
|
||||
for peer in peers:
|
||||
if peer.jid == beolink_listener.jid:
|
||||
# Get the friendly names for the listeners from the peers
|
||||
beolink_listeners_attribute[peer.friendly_name] = (
|
||||
beolink_listener.jid
|
||||
)
|
||||
break
|
||||
self._beolink_attributes["beolink"]["listeners"] = (
|
||||
beolink_listeners_attribute
|
||||
)
|
||||
|
||||
self._attr_group_members = group_members
|
||||
|
||||
@ -602,6 +720,17 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
|
||||
return self._source_change.name
|
||||
|
||||
@property
|
||||
def extra_state_attributes(self) -> dict[str, Any] | None:
|
||||
"""Return information that is not returned anywhere else."""
|
||||
attributes: dict[str, Any] = {}
|
||||
|
||||
# Add Beolink attributes
|
||||
if self._beolink_attributes:
|
||||
attributes.update(self._beolink_attributes)
|
||||
|
||||
return attributes
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Set the device to "networkStandby"."""
|
||||
await self._client.post_standby()
|
||||
@ -873,23 +1002,30 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
# Beolink compatible B&O device.
|
||||
# Repeated presses / calls will cycle between compatible playing devices.
|
||||
if len(group_members) == 0:
|
||||
await self._async_beolink_join()
|
||||
await self.async_beolink_join()
|
||||
return
|
||||
|
||||
# Get JID for each group member
|
||||
jids = [self._get_beolink_jid(group_member) for group_member in group_members]
|
||||
await self._async_beolink_expand(jids)
|
||||
await self.async_beolink_expand(jids)
|
||||
|
||||
async def async_unjoin_player(self) -> None:
|
||||
"""Unjoin Beolink session. End session if leader."""
|
||||
await self._async_beolink_leave()
|
||||
await self.async_beolink_leave()
|
||||
|
||||
async def _async_beolink_join(self) -> None:
|
||||
# Custom actions:
|
||||
async def async_beolink_join(self, beolink_jid: str | None = None) -> None:
|
||||
"""Join a Beolink multi-room experience."""
|
||||
await self._client.join_latest_beolink_experience()
|
||||
if beolink_jid is None:
|
||||
await self._client.join_latest_beolink_experience()
|
||||
else:
|
||||
await self._client.join_beolink_peer(jid=beolink_jid)
|
||||
|
||||
async def _async_beolink_expand(self, beolink_jids: list[str]) -> None:
|
||||
async def async_beolink_expand(
|
||||
self, beolink_jids: list[str] | None = None, all_discovered: bool = False
|
||||
) -> None:
|
||||
"""Expand a Beolink multi-room experience with a device or devices."""
|
||||
|
||||
# Ensure that the current source is expandable
|
||||
if not self._beolink_sources[cast(str, self._source_change.id)]:
|
||||
raise ServiceValidationError(
|
||||
@ -901,10 +1037,37 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity):
|
||||
},
|
||||
)
|
||||
|
||||
# Try to expand to all defined devices
|
||||
for beolink_jid in beolink_jids:
|
||||
await self._client.post_beolink_expand(jid=beolink_jid)
|
||||
# Expand to all discovered devices
|
||||
if all_discovered:
|
||||
peers = await self._client.get_beolink_peers()
|
||||
|
||||
async def _async_beolink_leave(self) -> None:
|
||||
for peer in peers:
|
||||
try:
|
||||
await self._client.post_beolink_expand(jid=peer.jid)
|
||||
except NotFoundException:
|
||||
_LOGGER.warning("Unable to expand to %s", peer.jid)
|
||||
|
||||
# Try to expand to all defined devices
|
||||
elif beolink_jids:
|
||||
for beolink_jid in beolink_jids:
|
||||
try:
|
||||
await self._client.post_beolink_expand(jid=beolink_jid)
|
||||
except NotFoundException:
|
||||
_LOGGER.warning(
|
||||
"Unable to expand to %s. Is the device available on the network?",
|
||||
beolink_jid,
|
||||
)
|
||||
|
||||
async def async_beolink_unexpand(self, beolink_jids: list[str]) -> None:
|
||||
"""Unexpand a Beolink multi-room experience with a device or devices."""
|
||||
# Unexpand all defined devices
|
||||
for beolink_jid in beolink_jids:
|
||||
await self._client.post_beolink_unexpand(jid=beolink_jid)
|
||||
|
||||
async def async_beolink_leave(self) -> None:
|
||||
"""Leave the current Beolink experience."""
|
||||
await self._client.post_beolink_leave()
|
||||
|
||||
async def async_beolink_allstandby(self) -> None:
|
||||
"""Set all connected Beolink devices to standby."""
|
||||
await self._client.post_beolink_allstandby()
|
||||
|
79
homeassistant/components/bang_olufsen/services.yaml
Normal file
79
homeassistant/components/bang_olufsen/services.yaml
Normal file
@ -0,0 +1,79 @@
|
||||
beolink_allstandby:
|
||||
target:
|
||||
entity:
|
||||
integration: bang_olufsen
|
||||
domain: media_player
|
||||
device:
|
||||
integration: bang_olufsen
|
||||
|
||||
beolink_expand:
|
||||
target:
|
||||
entity:
|
||||
integration: bang_olufsen
|
||||
domain: media_player
|
||||
device:
|
||||
integration: bang_olufsen
|
||||
fields:
|
||||
all_discovered:
|
||||
required: false
|
||||
example: false
|
||||
selector:
|
||||
boolean:
|
||||
jid_options:
|
||||
collapsed: false
|
||||
fields:
|
||||
beolink_jids:
|
||||
required: false
|
||||
example: >-
|
||||
[
|
||||
1111.2222222.33333333@products.bang-olufsen.com,
|
||||
4444.5555555.66666666@products.bang-olufsen.com
|
||||
]
|
||||
selector:
|
||||
object:
|
||||
|
||||
beolink_join:
|
||||
target:
|
||||
entity:
|
||||
integration: bang_olufsen
|
||||
domain: media_player
|
||||
device:
|
||||
integration: bang_olufsen
|
||||
fields:
|
||||
jid_options:
|
||||
collapsed: false
|
||||
fields:
|
||||
beolink_jid:
|
||||
required: false
|
||||
example: 1111.2222222.33333333@products.bang-olufsen.com
|
||||
selector:
|
||||
text:
|
||||
|
||||
beolink_leave:
|
||||
target:
|
||||
entity:
|
||||
integration: bang_olufsen
|
||||
domain: media_player
|
||||
device:
|
||||
integration: bang_olufsen
|
||||
|
||||
beolink_unexpand:
|
||||
target:
|
||||
entity:
|
||||
integration: bang_olufsen
|
||||
domain: media_player
|
||||
device:
|
||||
integration: bang_olufsen
|
||||
fields:
|
||||
jid_options:
|
||||
collapsed: false
|
||||
fields:
|
||||
beolink_jids:
|
||||
required: true
|
||||
example: >-
|
||||
[
|
||||
1111.2222222.33333333@products.bang-olufsen.com,
|
||||
4444.5555555.66666666@products.bang-olufsen.com
|
||||
]
|
||||
selector:
|
||||
object:
|
@ -1,4 +1,8 @@
|
||||
{
|
||||
"common": {
|
||||
"jid_options_name": "JID options",
|
||||
"jid_options_description": "Advanced grouping options, where devices' unique Beolink IDs (Called JIDs) are used directly. JIDs can be found in the state attributes of the media player entity."
|
||||
},
|
||||
"config": {
|
||||
"error": {
|
||||
"api_exception": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
@ -25,6 +29,68 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
"beolink_allstandby": {
|
||||
"name": "Beolink all standby",
|
||||
"description": "Set all Connected Beolink devices to standby."
|
||||
},
|
||||
"beolink_expand": {
|
||||
"name": "Beolink expand",
|
||||
"description": "Expand current Beolink experience.",
|
||||
"fields": {
|
||||
"all_discovered": {
|
||||
"name": "All discovered",
|
||||
"description": "Expand Beolink experience to all discovered devices."
|
||||
},
|
||||
"beolink_jids": {
|
||||
"name": "Beolink JIDs",
|
||||
"description": "Specify which Beolink JIDs will join current Beolink experience."
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"jid_options": {
|
||||
"name": "[%key:component::bang_olufsen::common::jid_options_name%]",
|
||||
"description": "[%key:component::bang_olufsen::common::jid_options_description%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"beolink_join": {
|
||||
"name": "Beolink join",
|
||||
"description": "Join a Beolink experience.",
|
||||
"fields": {
|
||||
"beolink_jid": {
|
||||
"name": "Beolink JID",
|
||||
"description": "Manually specify Beolink JID to join."
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"jid_options": {
|
||||
"name": "[%key:component::bang_olufsen::common::jid_options_name%]",
|
||||
"description": "[%key:component::bang_olufsen::common::jid_options_description%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"beolink_leave": {
|
||||
"name": "Beolink leave",
|
||||
"description": "Leave a Beolink experience."
|
||||
},
|
||||
"beolink_unexpand": {
|
||||
"name": "Beolink unexpand",
|
||||
"description": "Unexpand from current Beolink experience.",
|
||||
"fields": {
|
||||
"beolink_jids": {
|
||||
"name": "Beolink JIDs",
|
||||
"description": "Specify which Beolink JIDs will leave from current Beolink experience."
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"jid_options": {
|
||||
"name": "[%key:component::bang_olufsen::common::jid_options_name%]",
|
||||
"description": "[%key:component::bang_olufsen::common::jid_options_description%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"exceptions": {
|
||||
"m3u_invalid_format": {
|
||||
"message": "Media sources with the .m3u extension are not supported."
|
||||
|
@ -120,6 +120,11 @@ class BangOlufsenWebsocket(BangOlufsenBase):
|
||||
self.hass,
|
||||
f"{self._unique_id}_{WebsocketNotification.BEOLINK}",
|
||||
)
|
||||
elif notification_type is WebsocketNotification.CONFIGURATION:
|
||||
async_dispatcher_send(
|
||||
self.hass,
|
||||
f"{self._unique_id}_{WebsocketNotification.CONFIGURATION}",
|
||||
)
|
||||
elif notification_type is WebsocketNotification.REMOTE_MENU_CHANGED:
|
||||
async_dispatcher_send(
|
||||
self.hass,
|
||||
|
@ -35,13 +35,13 @@ from .const import (
|
||||
TEST_DATA_CREATE_ENTRY,
|
||||
TEST_DATA_CREATE_ENTRY_2,
|
||||
TEST_FRIENDLY_NAME,
|
||||
TEST_FRIENDLY_NAME_2,
|
||||
TEST_FRIENDLY_NAME_3,
|
||||
TEST_HOST_2,
|
||||
TEST_FRIENDLY_NAME_4,
|
||||
TEST_HOST_3,
|
||||
TEST_HOST_4,
|
||||
TEST_JID_1,
|
||||
TEST_JID_2,
|
||||
TEST_JID_3,
|
||||
TEST_JID_4,
|
||||
TEST_NAME,
|
||||
TEST_NAME_2,
|
||||
TEST_SERIAL_NUMBER,
|
||||
@ -267,29 +267,29 @@ def mock_mozart_client() -> Generator[AsyncMock]:
|
||||
}
|
||||
client.get_beolink_peers = AsyncMock()
|
||||
client.get_beolink_peers.return_value = [
|
||||
BeolinkPeer(
|
||||
friendly_name=TEST_FRIENDLY_NAME_2,
|
||||
jid=TEST_JID_2,
|
||||
ip_address=TEST_HOST_2,
|
||||
),
|
||||
BeolinkPeer(
|
||||
friendly_name=TEST_FRIENDLY_NAME_3,
|
||||
jid=TEST_JID_3,
|
||||
ip_address=TEST_HOST_3,
|
||||
),
|
||||
BeolinkPeer(
|
||||
friendly_name=TEST_FRIENDLY_NAME_4,
|
||||
jid=TEST_JID_4,
|
||||
ip_address=TEST_HOST_4,
|
||||
),
|
||||
]
|
||||
client.get_beolink_listeners = AsyncMock()
|
||||
client.get_beolink_listeners.return_value = [
|
||||
BeolinkPeer(
|
||||
friendly_name=TEST_FRIENDLY_NAME_2,
|
||||
jid=TEST_JID_2,
|
||||
ip_address=TEST_HOST_2,
|
||||
),
|
||||
BeolinkPeer(
|
||||
friendly_name=TEST_FRIENDLY_NAME_3,
|
||||
jid=TEST_JID_3,
|
||||
ip_address=TEST_HOST_3,
|
||||
),
|
||||
BeolinkPeer(
|
||||
friendly_name=TEST_FRIENDLY_NAME_4,
|
||||
jid=TEST_JID_4,
|
||||
ip_address=TEST_HOST_4,
|
||||
),
|
||||
]
|
||||
|
||||
client.get_listening_mode_set = AsyncMock()
|
||||
|
874
tests/components/bang_olufsen/snapshots/test_media_player.ambr
Normal file
874
tests/components/bang_olufsen/snapshots/test_media_player.ambr
Normal file
@ -0,0 +1,874 @@
|
||||
# serializer version: 1
|
||||
# name: test_async_beolink_allstandby
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'repeat': <RepeatMode.OFF: 'off'>,
|
||||
'shuffle': False,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_beolink_expand[all_discovered-True-None-log_messages0-2]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'repeat': <RepeatMode.OFF: 'off'>,
|
||||
'shuffle': False,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source': 'Tidal',
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095935>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_beolink_expand[all_discovered-True-expand_side_effect1-log_messages1-2]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'repeat': <RepeatMode.OFF: 'off'>,
|
||||
'shuffle': False,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source': 'Tidal',
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095935>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_beolink_expand[beolink_jids-parameter_value2-None-log_messages2-1]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'repeat': <RepeatMode.OFF: 'off'>,
|
||||
'shuffle': False,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source': 'Tidal',
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095935>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_beolink_expand[beolink_jids-parameter_value3-expand_side_effect3-log_messages3-1]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'repeat': <RepeatMode.OFF: 'off'>,
|
||||
'shuffle': False,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source': 'Tidal',
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095935>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_beolink_join
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'repeat': <RepeatMode.OFF: 'off'>,
|
||||
'shuffle': False,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_beolink_unexpand
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'repeat': <RepeatMode.OFF: 'off'>,
|
||||
'shuffle': False,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_join_players[group_members0-1-0]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'repeat': <RepeatMode.OFF: 'off'>,
|
||||
'shuffle': False,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source': 'Tidal',
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095935>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_join_players[group_members0-1-0].1
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.22222222@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_22222222',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_22222222',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_join_players[group_members1-0-1]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'repeat': <RepeatMode.OFF: 'off'>,
|
||||
'shuffle': False,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source': 'Tidal',
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095935>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_join_players[group_members1-0-1].1
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.22222222@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_22222222',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_22222222',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_join_players_invalid[source0-group_members0-expected_result0-invalid_source]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'media_position': 0,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source': 'Chromecast built-in',
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_join_players_invalid[source0-group_members0-expected_result0-invalid_source].1
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.22222222@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_22222222',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_22222222',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_join_players_invalid[source1-group_members1-expected_result1-invalid_grouping_entity]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source': 'Tidal',
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095935>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_join_players_invalid[source1-group_members1-expected_result1-invalid_grouping_entity].1
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.22222222@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_22222222',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_22222222',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_unjoin_player
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_11111111',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'repeat': <RepeatMode.OFF: 'off'>,
|
||||
'shuffle': False,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_update_beolink_listener
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'leader': dict({
|
||||
'Laundry room Balance': '1111.1111111.22222222@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.11111111@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_22222222',
|
||||
'media_player.beosound_balance_11111111',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_11111111',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
||||
# name: test_async_update_beolink_listener.1
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'beolink': dict({
|
||||
'listeners': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'peers': dict({
|
||||
'Lego room Balance': '1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'Lounge room Balance': '1111.1111111.44444444@products.bang-olufsen.com',
|
||||
}),
|
||||
'self': dict({
|
||||
'Living room Balance': '1111.1111111.22222222@products.bang-olufsen.com',
|
||||
}),
|
||||
}),
|
||||
'device_class': 'speaker',
|
||||
'entity_picture_local': None,
|
||||
'friendly_name': 'Living room Balance',
|
||||
'group_members': list([
|
||||
'media_player.beosound_balance_22222222',
|
||||
'listener_not_in_hass-1111.1111111.33333333@products.bang-olufsen.com',
|
||||
'listener_not_in_hass-1111.1111111.44444444@products.bang-olufsen.com',
|
||||
]),
|
||||
'icon': 'mdi:speaker-wireless',
|
||||
'media_content_type': <MediaType.MUSIC: 'music'>,
|
||||
'sound_mode': 'Test Listening Mode (123)',
|
||||
'sound_mode_list': list([
|
||||
'Test Listening Mode (123)',
|
||||
'Test Listening Mode (234)',
|
||||
'Test Listening Mode 2 (345)',
|
||||
]),
|
||||
'source_list': list([
|
||||
'Tidal',
|
||||
'Line-In',
|
||||
'HDMI A',
|
||||
]),
|
||||
'supported_features': <MediaPlayerEntityFeature: 2095933>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'media_player.beosound_balance_22222222',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'playing',
|
||||
})
|
||||
# ---
|
@ -9,7 +9,7 @@ from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceRegistry
|
||||
|
||||
from .const import TEST_MODEL_BALANCE, TEST_NAME, TEST_SERIAL_NUMBER
|
||||
from .const import TEST_FRIENDLY_NAME, TEST_MODEL_BALANCE, TEST_SERIAL_NUMBER
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
@ -35,7 +35,8 @@ async def test_setup_entry(
|
||||
identifiers={(DOMAIN, TEST_SERIAL_NUMBER)}
|
||||
)
|
||||
assert device is not None
|
||||
assert device.name == TEST_NAME
|
||||
# Is usually TEST_NAME, but is updated to the device's friendly name by _update_name_and_beolink
|
||||
assert device.name == TEST_FRIENDLY_NAME
|
||||
assert device.model == TEST_MODEL_BALANCE
|
||||
|
||||
# Ensure that the connection has been checked WebSocket connection has been initialized
|
||||
|
@ -4,8 +4,10 @@ from contextlib import AbstractContextManager, nullcontext as does_not_raise
|
||||
import logging
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from mozart_api.exceptions import NotFoundException
|
||||
from mozart_api.models import (
|
||||
BeolinkLeader,
|
||||
BeolinkSelf,
|
||||
PlaybackContentMetadata,
|
||||
PlayQueueSettings,
|
||||
RenderingState,
|
||||
@ -14,6 +16,8 @@ from mozart_api.models import (
|
||||
WebsocketNotificationTag,
|
||||
)
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from syrupy.filters import props
|
||||
|
||||
from homeassistant.components.bang_olufsen.const import (
|
||||
BANG_OLUFSEN_REPEAT_FROM_HA,
|
||||
@ -46,24 +50,29 @@ from homeassistant.components.media_player import (
|
||||
ATTR_SOUND_MODE_LIST,
|
||||
DOMAIN as MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_CLEAR_PLAYLIST,
|
||||
SERVICE_JOIN,
|
||||
SERVICE_MEDIA_NEXT_TRACK,
|
||||
SERVICE_MEDIA_PLAY_PAUSE,
|
||||
SERVICE_MEDIA_PREVIOUS_TRACK,
|
||||
SERVICE_MEDIA_SEEK,
|
||||
SERVICE_MEDIA_STOP,
|
||||
SERVICE_PLAY_MEDIA,
|
||||
SERVICE_REPEAT_SET,
|
||||
SERVICE_SELECT_SOUND_MODE,
|
||||
SERVICE_SELECT_SOURCE,
|
||||
SERVICE_SHUFFLE_SET,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_UNJOIN,
|
||||
SERVICE_VOLUME_MUTE,
|
||||
SERVICE_VOLUME_SET,
|
||||
MediaPlayerState,
|
||||
MediaType,
|
||||
RepeatMode,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_REPEAT_SET, SERVICE_SHUFFLE_SET
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers.device_registry import DeviceRegistry
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from .const import (
|
||||
@ -76,7 +85,10 @@ from .const import (
|
||||
TEST_DEEZER_TRACK,
|
||||
TEST_FALLBACK_SOURCES,
|
||||
TEST_FRIENDLY_NAME_2,
|
||||
TEST_JID_1,
|
||||
TEST_JID_2,
|
||||
TEST_JID_3,
|
||||
TEST_JID_4,
|
||||
TEST_LISTENING_MODE_REF,
|
||||
TEST_MEDIA_PLAYER_ENTITY_ID,
|
||||
TEST_MEDIA_PLAYER_ENTITY_ID_2,
|
||||
@ -136,6 +148,9 @@ async def test_initialization(
|
||||
mock_mozart_client.get_remote_menu.assert_called_once()
|
||||
mock_mozart_client.get_listening_mode_set.assert_called_once()
|
||||
mock_mozart_client.get_active_listening_mode.assert_called_once()
|
||||
mock_mozart_client.get_beolink_self.assert_called_once()
|
||||
mock_mozart_client.get_beolink_peers.assert_called_once()
|
||||
mock_mozart_client.get_beolink_listeners.assert_called_once()
|
||||
|
||||
|
||||
async def test_async_update_sources_audio_only(
|
||||
@ -530,11 +545,14 @@ async def test_async_update_beolink_line_in(
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert states.attributes["group_members"] == []
|
||||
|
||||
assert mock_mozart_client.get_beolink_listeners.call_count == 1
|
||||
# Called once during _initialize and once during _async_update_beolink
|
||||
assert mock_mozart_client.get_beolink_listeners.call_count == 2
|
||||
assert mock_mozart_client.get_beolink_peers.call_count == 2
|
||||
|
||||
|
||||
async def test_async_update_beolink_listener(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_mozart_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_config_entry_2: MockConfigEntry,
|
||||
@ -567,7 +585,56 @@ async def test_async_update_beolink_listener(
|
||||
TEST_MEDIA_PLAYER_ENTITY_ID,
|
||||
]
|
||||
|
||||
assert mock_mozart_client.get_beolink_listeners.call_count == 0
|
||||
# Called once for each entity during _initialize
|
||||
assert mock_mozart_client.get_beolink_listeners.call_count == 2
|
||||
# Called once for each entity during _initialize and
|
||||
# once more during _async_update_beolink for the entity that has the callback associated with it.
|
||||
assert mock_mozart_client.get_beolink_peers.call_count == 3
|
||||
|
||||
# Main entity
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
# Secondary entity
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID_2))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
|
||||
async def test_async_update_name_and_beolink(
|
||||
hass: HomeAssistant,
|
||||
device_registry: DeviceRegistry,
|
||||
mock_mozart_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test _async_update_name_and_beolink."""
|
||||
# Change response to ensure device name is changed
|
||||
mock_mozart_client.get_beolink_self.return_value = BeolinkSelf(
|
||||
friendly_name=TEST_FRIENDLY_NAME_2, jid=TEST_JID_1
|
||||
)
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
configuration_callback = (
|
||||
mock_mozart_client.get_notification_notifications.call_args[0][0]
|
||||
)
|
||||
# Trigger callback
|
||||
configuration_callback(WebsocketNotificationTag(value="configuration"))
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert mock_mozart_client.get_beolink_self.call_count == 2
|
||||
assert mock_mozart_client.get_beolink_peers.call_count == 2
|
||||
assert mock_mozart_client.get_beolink_listeners.call_count == 2
|
||||
|
||||
# Check that device name has been changed
|
||||
assert mock_config_entry.unique_id
|
||||
assert (
|
||||
device := device_registry.async_get_device(
|
||||
identifiers={(DOMAIN, mock_config_entry.unique_id)}
|
||||
)
|
||||
)
|
||||
assert device.name == TEST_FRIENDLY_NAME_2
|
||||
|
||||
|
||||
async def test_async_mute_volume(
|
||||
@ -1343,6 +1410,7 @@ async def test_async_browse_media(
|
||||
)
|
||||
async def test_async_join_players(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_mozart_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_config_entry_2: MockConfigEntry,
|
||||
@ -1367,8 +1435,8 @@ async def test_async_join_players(
|
||||
source_change_callback(BangOlufsenSource.TIDAL)
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
"join",
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_JOIN,
|
||||
{
|
||||
ATTR_ENTITY_ID: TEST_MEDIA_PLAYER_ENTITY_ID,
|
||||
ATTR_GROUP_MEMBERS: group_members,
|
||||
@ -1379,6 +1447,14 @@ async def test_async_join_players(
|
||||
assert mock_mozart_client.post_beolink_expand.call_count == expand_count
|
||||
assert mock_mozart_client.join_latest_beolink_experience.call_count == join_count
|
||||
|
||||
# Main entity
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
# Secondary entity
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID_2))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("source", "group_members", "expected_result", "error_type"),
|
||||
@ -1401,6 +1477,7 @@ async def test_async_join_players(
|
||||
)
|
||||
async def test_async_join_players_invalid(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_mozart_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_config_entry_2: MockConfigEntry,
|
||||
@ -1425,8 +1502,8 @@ async def test_async_join_players_invalid(
|
||||
|
||||
with expected_result as exc_info:
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
"join",
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_JOIN,
|
||||
{
|
||||
ATTR_ENTITY_ID: TEST_MEDIA_PLAYER_ENTITY_ID,
|
||||
ATTR_GROUP_MEMBERS: group_members,
|
||||
@ -1441,9 +1518,18 @@ async def test_async_join_players_invalid(
|
||||
assert mock_mozart_client.post_beolink_expand.call_count == 0
|
||||
assert mock_mozart_client.join_latest_beolink_experience.call_count == 0
|
||||
|
||||
# Main entity
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
# Secondary entity
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID_2))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
|
||||
async def test_async_unjoin_player(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_mozart_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
@ -1453,14 +1539,181 @@ async def test_async_unjoin_player(
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
"unjoin",
|
||||
MEDIA_PLAYER_DOMAIN,
|
||||
SERVICE_UNJOIN,
|
||||
{ATTR_ENTITY_ID: TEST_MEDIA_PLAYER_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_mozart_client.post_beolink_leave.assert_called_once()
|
||||
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
|
||||
async def test_async_beolink_join(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_mozart_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test async_beolink_join with defined JID."""
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"beolink_join",
|
||||
{
|
||||
ATTR_ENTITY_ID: TEST_MEDIA_PLAYER_ENTITY_ID,
|
||||
"beolink_jid": TEST_JID_2,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_mozart_client.join_beolink_peer.assert_called_once_with(jid=TEST_JID_2)
|
||||
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
(
|
||||
"parameter",
|
||||
"parameter_value",
|
||||
"expand_side_effect",
|
||||
"log_messages",
|
||||
"peers_call_count",
|
||||
),
|
||||
[
|
||||
# All discovered
|
||||
# Valid peers
|
||||
("all_discovered", True, None, [], 2),
|
||||
# Invalid peers
|
||||
(
|
||||
"all_discovered",
|
||||
True,
|
||||
NotFoundException(),
|
||||
[f"Unable to expand to {TEST_JID_3}", f"Unable to expand to {TEST_JID_4}"],
|
||||
2,
|
||||
),
|
||||
# Beolink JIDs
|
||||
# Valid peer
|
||||
("beolink_jids", [TEST_JID_3, TEST_JID_4], None, [], 1),
|
||||
# Invalid peer
|
||||
(
|
||||
"beolink_jids",
|
||||
[TEST_JID_3, TEST_JID_4],
|
||||
NotFoundException(),
|
||||
[
|
||||
f"Unable to expand to {TEST_JID_3}. Is the device available on the network?",
|
||||
f"Unable to expand to {TEST_JID_4}. Is the device available on the network?",
|
||||
],
|
||||
1,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_async_beolink_expand(
|
||||
hass: HomeAssistant,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_mozart_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
parameter: str,
|
||||
parameter_value: bool | list[str],
|
||||
expand_side_effect: NotFoundException | None,
|
||||
log_messages: list[str],
|
||||
peers_call_count: int,
|
||||
) -> None:
|
||||
"""Test async_beolink_expand."""
|
||||
mock_mozart_client.post_beolink_expand.side_effect = expand_side_effect
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
source_change_callback = (
|
||||
mock_mozart_client.get_source_change_notifications.call_args[0][0]
|
||||
)
|
||||
|
||||
# Set the source to a beolink expandable source
|
||||
source_change_callback(BangOlufsenSource.TIDAL)
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"beolink_expand",
|
||||
{
|
||||
ATTR_ENTITY_ID: TEST_MEDIA_PLAYER_ENTITY_ID,
|
||||
parameter: parameter_value,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
# Check log messages
|
||||
for log_message in log_messages:
|
||||
assert log_message in caplog.text
|
||||
|
||||
# Called once during _initialize and once during async_beolink_expand for all_discovered
|
||||
assert mock_mozart_client.get_beolink_peers.call_count == peers_call_count
|
||||
|
||||
assert mock_mozart_client.post_beolink_expand.call_count == len(
|
||||
await mock_mozart_client.get_beolink_peers()
|
||||
)
|
||||
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
|
||||
async def test_async_beolink_unexpand(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_mozart_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test test_async_beolink_unexpand."""
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"beolink_unexpand",
|
||||
{
|
||||
ATTR_ENTITY_ID: TEST_MEDIA_PLAYER_ENTITY_ID,
|
||||
"beolink_jids": [TEST_JID_3, TEST_JID_4],
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert mock_mozart_client.post_beolink_unexpand.call_count == 2
|
||||
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
|
||||
async def test_async_beolink_allstandby(
|
||||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
mock_mozart_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test async_beolink_allstandby."""
|
||||
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"beolink_allstandby",
|
||||
{ATTR_ENTITY_ID: TEST_MEDIA_PLAYER_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
mock_mozart_client.post_beolink_allstandby.assert_called_once()
|
||||
|
||||
assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID))
|
||||
assert states == snapshot(exclude=props("media_position_updated_at"))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("repeat"),
|
||||
|
Loading…
x
Reference in New Issue
Block a user