Add soundtouch attributes exposing multiroom zone info (#28298)
* [soundtouch] workaround for API bug when removing multiple slaves from a zone at once * [soundtouch] added additional attributes exposing multiroom zone info * Fix update with slave entities * Add zone attributes test * Fix and clean up tests * Fix typo Co-authored-by: Martin Hjelmare <marhje52@gmail.com>pull/32489/head
parent
2316f7ace4
commit
b848c97211
|
@ -22,11 +22,13 @@ from homeassistant.const import (
|
|||
CONF_HOST,
|
||||
CONF_NAME,
|
||||
CONF_PORT,
|
||||
EVENT_HOMEASSISTANT_START,
|
||||
STATE_OFF,
|
||||
STATE_PAUSED,
|
||||
STATE_PLAYING,
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
||||
from .const import (
|
||||
|
@ -47,6 +49,8 @@ MAP_STATUS = {
|
|||
}
|
||||
|
||||
DATA_SOUNDTOUCH = "soundtouch"
|
||||
ATTR_SOUNDTOUCH_GROUP = "soundtouch_group"
|
||||
ATTR_SOUNDTOUCH_ZONE = "soundtouch_zone"
|
||||
|
||||
SOUNDTOUCH_PLAY_EVERYWHERE = vol.Schema({vol.Required("master"): cv.entity_id})
|
||||
|
||||
|
@ -103,7 +107,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
remote_config = {"id": "ha.component.soundtouch", "host": host, "port": port}
|
||||
bose_soundtouch_entity = SoundTouchDevice(None, remote_config)
|
||||
hass.data[DATA_SOUNDTOUCH].append(bose_soundtouch_entity)
|
||||
add_entities([bose_soundtouch_entity])
|
||||
add_entities([bose_soundtouch_entity], True)
|
||||
else:
|
||||
name = config.get(CONF_NAME)
|
||||
remote_config = {
|
||||
|
@ -113,7 +117,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
|
|||
}
|
||||
bose_soundtouch_entity = SoundTouchDevice(name, remote_config)
|
||||
hass.data[DATA_SOUNDTOUCH].append(bose_soundtouch_entity)
|
||||
add_entities([bose_soundtouch_entity])
|
||||
add_entities([bose_soundtouch_entity], True)
|
||||
|
||||
def service_handle(service):
|
||||
"""Handle the applying of a service."""
|
||||
|
@ -191,9 +195,10 @@ class SoundTouchDevice(MediaPlayerDevice):
|
|||
self._name = self._device.config.name
|
||||
else:
|
||||
self._name = name
|
||||
self._status = self._device.status()
|
||||
self._volume = self._device.volume()
|
||||
self._status = None
|
||||
self._volume = None
|
||||
self._config = config
|
||||
self._zone = None
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
|
@ -209,6 +214,7 @@ class SoundTouchDevice(MediaPlayerDevice):
|
|||
"""Retrieve the latest data."""
|
||||
self._status = self._device.status()
|
||||
self._volume = self._device.volume()
|
||||
self._zone = self.get_zone_info()
|
||||
|
||||
@property
|
||||
def volume_level(self):
|
||||
|
@ -317,6 +323,18 @@ class SoundTouchDevice(MediaPlayerDevice):
|
|||
"""Album name of current playing media."""
|
||||
return self._status.album
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Populate zone info which requires entity_id."""
|
||||
|
||||
@callback
|
||||
def async_update_on_start(event):
|
||||
"""Schedule an update when all platform entities have been added."""
|
||||
self.async_schedule_update_ha_state(True)
|
||||
|
||||
self.hass.bus.async_listen_once(
|
||||
EVENT_HOMEASSISTANT_START, async_update_on_start
|
||||
)
|
||||
|
||||
def play_media(self, media_type, media_id, **kwargs):
|
||||
"""Play a piece of media."""
|
||||
_LOGGER.debug("Starting media with media_id: %s", media_id)
|
||||
|
@ -369,7 +387,13 @@ class SoundTouchDevice(MediaPlayerDevice):
|
|||
_LOGGER.info(
|
||||
"Removing slaves from zone with master %s", self._device.config.name
|
||||
)
|
||||
self._device.remove_zone_slave([slave.device for slave in slaves])
|
||||
# SoundTouch API seems to have a bug and won't remove slaves if there are
|
||||
# more than one in the payload. Therefore we have to loop over all slaves
|
||||
# and remove them individually
|
||||
for slave in slaves:
|
||||
# make sure to not try to remove the master (aka current device)
|
||||
if slave.entity_id != self.entity_id:
|
||||
self._device.remove_zone_slave([slave.device])
|
||||
|
||||
def add_zone_slave(self, slaves):
|
||||
"""
|
||||
|
@ -387,3 +411,62 @@ class SoundTouchDevice(MediaPlayerDevice):
|
|||
"Adding slaves to zone with master %s", self._device.config.name
|
||||
)
|
||||
self._device.add_zone_slave([slave.device for slave in slaves])
|
||||
|
||||
@property
|
||||
def device_state_attributes(self):
|
||||
"""Return entity specific state attributes."""
|
||||
attributes = {}
|
||||
|
||||
if self._zone and "master" in self._zone:
|
||||
attributes[ATTR_SOUNDTOUCH_ZONE] = self._zone
|
||||
# Compatibility with how other components expose their groups (like SONOS).
|
||||
# First entry is the master, others are slaves
|
||||
group_members = [self._zone["master"]] + self._zone["slaves"]
|
||||
attributes[ATTR_SOUNDTOUCH_GROUP] = group_members
|
||||
|
||||
return attributes
|
||||
|
||||
def get_zone_info(self):
|
||||
"""Return the current zone info."""
|
||||
zone_status = self._device.zone_status()
|
||||
if not zone_status:
|
||||
return None
|
||||
|
||||
# Due to a bug in the SoundTouch API itself client devices do NOT return their
|
||||
# siblings as part of the "slaves" list. Only the master has the full list of
|
||||
# slaves for some reason. To compensate for this shortcoming we have to fetch
|
||||
# the zone info from the master when the current device is a slave until this is
|
||||
# fixed in the SoundTouch API or libsoundtouch, or of course until somebody has a
|
||||
# better idea on how to fix this
|
||||
if zone_status.is_master:
|
||||
return self._build_zone_info(self.entity_id, zone_status.slaves)
|
||||
|
||||
master_instance = self._get_instance_by_ip(zone_status.master_ip)
|
||||
master_zone_status = master_instance.device.zone_status()
|
||||
return self._build_zone_info(
|
||||
master_instance.entity_id, master_zone_status.slaves
|
||||
)
|
||||
|
||||
def _get_instance_by_ip(self, ip_address):
|
||||
"""Search and return a SoundTouchDevice instance by it's IP address."""
|
||||
for instance in self.hass.data[DATA_SOUNDTOUCH]:
|
||||
if instance and instance.config["host"] == ip_address:
|
||||
return instance
|
||||
return None
|
||||
|
||||
def _build_zone_info(self, master, zone_slaves):
|
||||
"""Build the exposed zone attributes."""
|
||||
slaves = []
|
||||
|
||||
for slave in zone_slaves:
|
||||
slave_instance = self._get_instance_by_ip(slave.device_ip)
|
||||
if slave_instance:
|
||||
slaves.append(slave_instance.entity_id)
|
||||
|
||||
attributes = {
|
||||
"master": master,
|
||||
"is_master": master == self.entity_id,
|
||||
"slaves": slaves,
|
||||
}
|
||||
|
||||
return attributes
|
||||
|
|
|
@ -19,7 +19,11 @@ from homeassistant.components.media_player.const import (
|
|||
)
|
||||
from homeassistant.components.soundtouch import media_player as soundtouch
|
||||
from homeassistant.components.soundtouch.const import DOMAIN
|
||||
from homeassistant.components.soundtouch.media_player import DATA_SOUNDTOUCH
|
||||
from homeassistant.components.soundtouch.media_player import (
|
||||
ATTR_SOUNDTOUCH_GROUP,
|
||||
ATTR_SOUNDTOUCH_ZONE,
|
||||
DATA_SOUNDTOUCH,
|
||||
)
|
||||
from homeassistant.const import STATE_OFF, STATE_PAUSED, STATE_PLAYING
|
||||
from homeassistant.helpers.discovery import async_load_platform
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
@ -154,9 +158,9 @@ def _mocked_presets(*args, **kwargs):
|
|||
class MockPreset(Preset):
|
||||
"""Mock preset."""
|
||||
|
||||
def __init__(self, id):
|
||||
def __init__(self, id_):
|
||||
"""Init the class."""
|
||||
self._id = id
|
||||
self._id = id_
|
||||
self._name = "preset"
|
||||
|
||||
|
||||
|
@ -318,8 +322,8 @@ async def test_playing_media(mocked_status, mocked_volume, hass, one_device):
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
entity_1_state = hass.states.get("media_player.soundtouch_1")
|
||||
assert entity_1_state.state == STATE_PLAYING
|
||||
|
@ -336,8 +340,8 @@ async def test_playing_unknown_media(mocked_status, mocked_volume, hass, one_dev
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
entity_1_state = hass.states.get("media_player.soundtouch_1")
|
||||
assert entity_1_state.state == STATE_PLAYING
|
||||
|
@ -349,8 +353,8 @@ async def test_playing_radio(mocked_status, mocked_volume, hass, one_device):
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
entity_1_state = hass.states.get("media_player.soundtouch_1")
|
||||
assert entity_1_state.state == STATE_PLAYING
|
||||
|
@ -363,8 +367,8 @@ async def test_get_volume_level(mocked_status, mocked_volume, hass, one_device):
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
entity_1_state = hass.states.get("media_player.soundtouch_1")
|
||||
assert entity_1_state.attributes["volume_level"] == 0.12
|
||||
|
@ -376,8 +380,8 @@ async def test_get_state_off(mocked_status, mocked_volume, hass, one_device):
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
entity_1_state = hass.states.get("media_player.soundtouch_1")
|
||||
assert entity_1_state.state == STATE_OFF
|
||||
|
@ -389,8 +393,8 @@ async def test_get_state_pause(mocked_status, mocked_volume, hass, one_device):
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
entity_1_state = hass.states.get("media_player.soundtouch_1")
|
||||
assert entity_1_state.state == STATE_PAUSED
|
||||
|
@ -402,8 +406,8 @@ async def test_is_muted(mocked_status, mocked_volume, hass, one_device):
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
entity_1_state = hass.states.get("media_player.soundtouch_1")
|
||||
assert entity_1_state.attributes["is_volume_muted"]
|
||||
|
@ -414,8 +418,8 @@ async def test_media_commands(mocked_status, mocked_volume, hass, one_device):
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
entity_1_state = hass.states.get("media_player.soundtouch_1")
|
||||
assert entity_1_state.attributes["supported_features"] == 18365
|
||||
|
@ -429,13 +433,13 @@ async def test_should_turn_off(
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player", "turn_off", {"entity_id": "media_player.soundtouch_1"}, True,
|
||||
)
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_status.call_count == 3
|
||||
assert mocked_power_off.call_count == 1
|
||||
|
||||
|
||||
|
@ -448,13 +452,13 @@ async def test_should_turn_on(
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player", "turn_on", {"entity_id": "media_player.soundtouch_1"}, True,
|
||||
)
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_status.call_count == 3
|
||||
assert mocked_power_on.call_count == 1
|
||||
|
||||
|
||||
|
@ -466,13 +470,13 @@ async def test_volume_up(
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player", "volume_up", {"entity_id": "media_player.soundtouch_1"}, True,
|
||||
)
|
||||
assert mocked_volume.call_count == 2
|
||||
assert mocked_volume.call_count == 3
|
||||
assert mocked_volume_up.call_count == 1
|
||||
|
||||
|
||||
|
@ -484,13 +488,13 @@ async def test_volume_down(
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player", "volume_down", {"entity_id": "media_player.soundtouch_1"}, True,
|
||||
)
|
||||
assert mocked_volume.call_count == 2
|
||||
assert mocked_volume.call_count == 3
|
||||
assert mocked_volume_down.call_count == 1
|
||||
|
||||
|
||||
|
@ -502,8 +506,8 @@ async def test_set_volume_level(
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
|
@ -511,7 +515,7 @@ async def test_set_volume_level(
|
|||
{"entity_id": "media_player.soundtouch_1", "volume_level": 0.17},
|
||||
True,
|
||||
)
|
||||
assert mocked_volume.call_count == 2
|
||||
assert mocked_volume.call_count == 3
|
||||
mocked_set_volume.assert_called_with(17)
|
||||
|
||||
|
||||
|
@ -521,8 +525,8 @@ async def test_mute(mocked_mute, mocked_status, mocked_volume, hass, one_device)
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
|
@ -530,7 +534,7 @@ async def test_mute(mocked_mute, mocked_status, mocked_volume, hass, one_device)
|
|||
{"entity_id": "media_player.soundtouch_1", "is_volume_muted": True},
|
||||
True,
|
||||
)
|
||||
assert mocked_volume.call_count == 2
|
||||
assert mocked_volume.call_count == 3
|
||||
assert mocked_mute.call_count == 1
|
||||
|
||||
|
||||
|
@ -540,13 +544,13 @@ async def test_play(mocked_play, mocked_status, mocked_volume, hass, one_device)
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player", "media_play", {"entity_id": "media_player.soundtouch_1"}, True,
|
||||
)
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_status.call_count == 3
|
||||
assert mocked_play.call_count == 1
|
||||
|
||||
|
||||
|
@ -556,13 +560,13 @@ async def test_pause(mocked_pause, mocked_status, mocked_volume, hass, one_devic
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player", "media_pause", {"entity_id": "media_player.soundtouch_1"}, True,
|
||||
)
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_status.call_count == 3
|
||||
assert mocked_pause.call_count == 1
|
||||
|
||||
|
||||
|
@ -574,8 +578,8 @@ async def test_play_pause(
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
|
@ -583,7 +587,7 @@ async def test_play_pause(
|
|||
{"entity_id": "media_player.soundtouch_1"},
|
||||
True,
|
||||
)
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_status.call_count == 3
|
||||
assert mocked_play_pause.call_count == 1
|
||||
|
||||
|
||||
|
@ -601,8 +605,8 @@ async def test_next_previous_track(
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
|
@ -610,7 +614,7 @@ async def test_next_previous_track(
|
|||
{"entity_id": "media_player.soundtouch_1"},
|
||||
True,
|
||||
)
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_status.call_count == 3
|
||||
assert mocked_next_track.call_count == 1
|
||||
|
||||
await hass.services.async_call(
|
||||
|
@ -619,7 +623,7 @@ async def test_next_previous_track(
|
|||
{"entity_id": "media_player.soundtouch_1"},
|
||||
True,
|
||||
)
|
||||
assert mocked_status.call_count == 3
|
||||
assert mocked_status.call_count == 4
|
||||
assert mocked_previous_track.call_count == 1
|
||||
|
||||
|
||||
|
@ -632,8 +636,8 @@ async def test_play_media(
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
|
@ -670,8 +674,8 @@ async def test_play_media_url(
|
|||
await setup_soundtouch(hass, DEVICE_1_CONFIG)
|
||||
|
||||
assert one_device.call_count == 1
|
||||
assert mocked_status.call_count == 1
|
||||
assert mocked_volume.call_count == 1
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
|
||||
await hass.services.async_call(
|
||||
"media_player",
|
||||
|
@ -695,8 +699,8 @@ async def test_play_everywhere(
|
|||
await setup_soundtouch(hass, [DEVICE_1_CONFIG, DEVICE_2_CONFIG])
|
||||
|
||||
assert mocked_device.call_count == 2
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
assert mocked_status.call_count == 4
|
||||
assert mocked_volume.call_count == 4
|
||||
|
||||
# one master, one slave => create zone
|
||||
await hass.services.async_call(
|
||||
|
@ -740,8 +744,8 @@ async def test_create_zone(
|
|||
await setup_soundtouch(hass, [DEVICE_1_CONFIG, DEVICE_2_CONFIG])
|
||||
|
||||
assert mocked_device.call_count == 2
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
assert mocked_status.call_count == 4
|
||||
assert mocked_volume.call_count == 4
|
||||
|
||||
# one master, one slave => create zone
|
||||
await hass.services.async_call(
|
||||
|
@ -783,8 +787,8 @@ async def test_remove_zone_slave(
|
|||
await setup_soundtouch(hass, [DEVICE_1_CONFIG, DEVICE_2_CONFIG])
|
||||
|
||||
assert mocked_device.call_count == 2
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
assert mocked_status.call_count == 4
|
||||
assert mocked_volume.call_count == 4
|
||||
|
||||
# remove one slave
|
||||
await hass.services.async_call(
|
||||
|
@ -826,8 +830,8 @@ async def test_add_zone_slave(
|
|||
await setup_soundtouch(hass, [DEVICE_1_CONFIG, DEVICE_2_CONFIG])
|
||||
|
||||
assert mocked_device.call_count == 2
|
||||
assert mocked_status.call_count == 2
|
||||
assert mocked_volume.call_count == 2
|
||||
assert mocked_status.call_count == 4
|
||||
assert mocked_volume.call_count == 4
|
||||
|
||||
# add one slave
|
||||
await hass.services.async_call(
|
||||
|
@ -858,3 +862,43 @@ async def test_add_zone_slave(
|
|||
True,
|
||||
)
|
||||
assert mocked_add_zone_slave.call_count == 1
|
||||
|
||||
|
||||
@patch("libsoundtouch.device.SoundTouchDevice.create_zone")
|
||||
async def test_zone_attributes(
|
||||
mocked_create_zone, mocked_status, mocked_volume, hass, two_zones,
|
||||
):
|
||||
"""Test play everywhere."""
|
||||
mocked_device = two_zones
|
||||
await setup_soundtouch(hass, [DEVICE_1_CONFIG, DEVICE_2_CONFIG])
|
||||
|
||||
assert mocked_device.call_count == 2
|
||||
assert mocked_status.call_count == 4
|
||||
assert mocked_volume.call_count == 4
|
||||
|
||||
entity_1_state = hass.states.get("media_player.soundtouch_1")
|
||||
assert entity_1_state.attributes[ATTR_SOUNDTOUCH_ZONE]["is_master"]
|
||||
assert (
|
||||
entity_1_state.attributes[ATTR_SOUNDTOUCH_ZONE]["master"]
|
||||
== "media_player.soundtouch_1"
|
||||
)
|
||||
assert entity_1_state.attributes[ATTR_SOUNDTOUCH_ZONE]["slaves"] == [
|
||||
"media_player.soundtouch_2"
|
||||
]
|
||||
assert entity_1_state.attributes[ATTR_SOUNDTOUCH_GROUP] == [
|
||||
"media_player.soundtouch_1",
|
||||
"media_player.soundtouch_2",
|
||||
]
|
||||
entity_2_state = hass.states.get("media_player.soundtouch_2")
|
||||
assert not entity_2_state.attributes[ATTR_SOUNDTOUCH_ZONE]["is_master"]
|
||||
assert (
|
||||
entity_2_state.attributes[ATTR_SOUNDTOUCH_ZONE]["master"]
|
||||
== "media_player.soundtouch_1"
|
||||
)
|
||||
assert entity_2_state.attributes[ATTR_SOUNDTOUCH_ZONE]["slaves"] == [
|
||||
"media_player.soundtouch_2"
|
||||
]
|
||||
assert entity_2_state.attributes[ATTR_SOUNDTOUCH_GROUP] == [
|
||||
"media_player.soundtouch_1",
|
||||
"media_player.soundtouch_2",
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue