Add Bose soundtouch discovery support and upgrade libsoundtouch library (#7005)

* Add Bose soundtouch discovery support and upgrade libsoundtouch library

* Remove DEVICE global variable

* Update netdisco to lastest version
This commit is contained in:
Charles Blonde 2017-04-20 06:52:37 +02:00 committed by Paulus Schoutsen
parent 76d2154820
commit 931fce8239
5 changed files with 341 additions and 274 deletions

View File

@ -50,6 +50,7 @@ SERVICE_HANDLERS = {
'apple_tv': ('media_player', 'apple_tv'), 'apple_tv': ('media_player', 'apple_tv'),
'frontier_silicon': ('media_player', 'frontier_silicon'), 'frontier_silicon': ('media_player', 'frontier_silicon'),
'openhome': ('media_player', 'openhome'), 'openhome': ('media_player', 'openhome'),
'bose_soundtouch': ('media_player', 'soundtouch'),
} }
CONF_IGNORE = 'ignore' CONF_IGNORE = 'ignore'

View File

@ -222,30 +222,39 @@ soundtouch_play_everywhere:
description: Play on all Bose Soundtouch devices description: Play on all Bose Soundtouch devices
fields: fields:
entity_id: master:
description: Name of entites that will coordinate the grouping. Platform dependent. It is a shortcut for creating a multi-room zone with all devices description: Name of the master entity that will coordinate the grouping. Platform dependent. It is a shortcut for creating a multi-room zone with all devices
example: 'media_player.soundtouch_home' example: 'media_player.soundtouch_home'
soundtouch_create_zone: soundtouch_create_zone:
description: Create a multi-room zone description: Create a multi-room zone
fields: fields:
entity_id: master:
description: Name of entites that will coordinate the multi-room zone. Platform dependent. description: Name of the master entity that will coordinate the multi-room zone. Platform dependent.
example: 'media_player.soundtouch_home' example: 'media_player.soundtouch_home'
slaves:
description: Name of slaves entities to add to the new zone
example: 'media_player.soundtouch_bedroom'
soundtouch_add_zone_slave: soundtouch_add_zone_slave:
description: Add a slave to a multi-room zone description: Add a slave to a multi-room zone
fields: fields:
entity_id: master:
description: Name of entites that will be added to the multi-room zone. Platform dependent. description: Name of the master entity that is coordinating the multi-room zone. Platform dependent.
example: 'media_player.soundtouch_home' example: 'media_player.soundtouch_home'
slaves:
description: Name of slaves entities to add to the existing zone
example: 'media_player.soundtouch_bedroom'
soundtouch_remove_zone_slave: soundtouch_remove_zone_slave:
description: Remove a slave from the multi-room zone description: Remove a slave from the multi-room zone
fields: fields:
entity_id: master:
description: Name of entites that will be remove from the multi-room zone. Platform dependent. description: Name of the master entity that is coordinating the multi-room zone. Platform dependent.
example: 'media_player.soundtouch_home' example: 'media_player.soundtouch_home'
slaves:
description: Name of slaves entities to remove from the existing zone
example: 'media_player.soundtouch_bedroom'

View File

@ -15,7 +15,7 @@ from homeassistant.const import (CONF_HOST, CONF_NAME, STATE_OFF, CONF_PORT,
STATE_PAUSED, STATE_PLAYING, STATE_PAUSED, STATE_PLAYING,
STATE_UNAVAILABLE) STATE_UNAVAILABLE)
REQUIREMENTS = ['libsoundtouch==0.1.0'] REQUIREMENTS = ['libsoundtouch==0.3.0']
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -29,33 +29,33 @@ MAP_STATUS = {
"PLAY_STATE": STATE_PLAYING, "PLAY_STATE": STATE_PLAYING,
"BUFFERING_STATE": STATE_PLAYING, "BUFFERING_STATE": STATE_PLAYING,
"PAUSE_STATE": STATE_PAUSED, "PAUSE_STATE": STATE_PAUSED,
"STOp_STATE": STATE_OFF "STOP_STATE": STATE_OFF
} }
DATA_SOUNDTOUCH = "soundtouch"
SOUNDTOUCH_PLAY_EVERYWHERE = vol.Schema({ SOUNDTOUCH_PLAY_EVERYWHERE = vol.Schema({
'master': cv.entity_id, vol.Required('master'): cv.entity_id
}) })
SOUNDTOUCH_CREATE_ZONE_SCHEMA = vol.Schema({ SOUNDTOUCH_CREATE_ZONE_SCHEMA = vol.Schema({
'master': cv.entity_id, vol.Required('master'): cv.entity_id,
'slaves': cv.entity_ids vol.Required('slaves'): cv.entity_ids
}) })
SOUNDTOUCH_ADD_ZONE_SCHEMA = vol.Schema({ SOUNDTOUCH_ADD_ZONE_SCHEMA = vol.Schema({
'master': cv.entity_id, vol.Required('master'): cv.entity_id,
'slaves': cv.entity_ids vol.Required('slaves'): cv.entity_ids
}) })
SOUNDTOUCH_REMOVE_ZONE_SCHEMA = vol.Schema({ SOUNDTOUCH_REMOVE_ZONE_SCHEMA = vol.Schema({
'master': cv.entity_id, vol.Required('master'): cv.entity_id,
'slaves': cv.entity_ids vol.Required('slaves'): cv.entity_ids
}) })
DEFAULT_NAME = 'Bose Soundtouch' DEFAULT_NAME = 'Bose Soundtouch'
DEFAULT_PORT = 8090 DEFAULT_PORT = 8090
DEVICES = []
SUPPORT_SOUNDTOUCH = SUPPORT_PAUSE | SUPPORT_VOLUME_STEP | \ SUPPORT_SOUNDTOUCH = SUPPORT_PAUSE | SUPPORT_VOLUME_STEP | \
SUPPORT_VOLUME_MUTE | SUPPORT_PREVIOUS_TRACK | \ SUPPORT_VOLUME_MUTE | SUPPORT_PREVIOUS_TRACK | \
SUPPORT_NEXT_TRACK | SUPPORT_TURN_OFF | \ SUPPORT_NEXT_TRACK | SUPPORT_TURN_OFF | \
@ -70,180 +70,99 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the Bose Soundtouch platform.""" """Setup the Bose Soundtouch platform."""
name = config.get(CONF_NAME) if DATA_SOUNDTOUCH not in hass.data:
hass.data[DATA_SOUNDTOUCH] = []
if discovery_info:
# Discovery
host = discovery_info["host"]
port = int(discovery_info["port"])
# if device already exists by config
if host in [device.config['host'] for device in
hass.data[DATA_SOUNDTOUCH]]:
return
remote_config = { remote_config = {
'name': 'HomeAssistant', 'id': 'ha.component.soundtouch',
'description': config.get(CONF_NAME), 'host': host,
'port': port
}
soundtouch_device = SoundTouchDevice(None, remote_config)
hass.data[DATA_SOUNDTOUCH].append(soundtouch_device)
add_devices([soundtouch_device])
else:
# Config
name = config.get(CONF_NAME)
remote_config = {
'id': 'ha.component.soundtouch', 'id': 'ha.component.soundtouch',
'port': config.get(CONF_PORT), 'port': config.get(CONF_PORT),
'host': config.get(CONF_HOST) 'host': config.get(CONF_HOST)
} }
soundtouch_device = SoundTouchDevice(name, remote_config) soundtouch_device = SoundTouchDevice(name, remote_config)
DEVICES.append(soundtouch_device) hass.data[DATA_SOUNDTOUCH].append(soundtouch_device)
add_devices([soundtouch_device]) add_devices([soundtouch_device])
descriptions = load_yaml_config_file( descriptions = load_yaml_config_file(
path.join(path.dirname(__file__), 'services.yaml')) path.join(path.dirname(__file__), 'services.yaml'))
def service_handle(service):
"""Internal func for applying a service."""
master_device_id = service.data.get('master')
slaves_ids = service.data.get('slaves')
slaves = []
if slaves_ids:
slaves = [device for device in hass.data[DATA_SOUNDTOUCH] if
device.entity_id in slaves_ids]
master = next([device for device in hass.data[DATA_SOUNDTOUCH] if
device.entity_id == master_device_id].__iter__(), None)
if master is None:
_LOGGER.warning("Unable to find master with entity_id:" + str(
master_device_id))
return
if service.service == SERVICE_PLAY_EVERYWHERE:
slaves = [d for d in hass.data[DATA_SOUNDTOUCH] if
d.entity_id != master_device_id]
master.create_zone(slaves)
elif service.service == SERVICE_CREATE_ZONE:
master.create_zone(slaves)
elif service.service == SERVICE_REMOVE_ZONE_SLAVE:
master.remove_zone_slave(slaves)
elif service.service == SERVICE_ADD_ZONE_SLAVE:
master.add_zone_slave(slaves)
hass.services.register(DOMAIN, SERVICE_PLAY_EVERYWHERE, hass.services.register(DOMAIN, SERVICE_PLAY_EVERYWHERE,
play_everywhere_service, service_handle,
descriptions.get(SERVICE_PLAY_EVERYWHERE), descriptions.get(SERVICE_PLAY_EVERYWHERE),
schema=SOUNDTOUCH_PLAY_EVERYWHERE) schema=SOUNDTOUCH_PLAY_EVERYWHERE)
hass.services.register(DOMAIN, SERVICE_CREATE_ZONE, hass.services.register(DOMAIN, SERVICE_CREATE_ZONE,
create_zone_service, service_handle,
descriptions.get(SERVICE_CREATE_ZONE), descriptions.get(SERVICE_CREATE_ZONE),
schema=SOUNDTOUCH_CREATE_ZONE_SCHEMA) schema=SOUNDTOUCH_CREATE_ZONE_SCHEMA)
hass.services.register(DOMAIN, SERVICE_REMOVE_ZONE_SLAVE, hass.services.register(DOMAIN, SERVICE_REMOVE_ZONE_SLAVE,
remove_zone_slave, service_handle,
descriptions.get(SERVICE_REMOVE_ZONE_SLAVE), descriptions.get(SERVICE_REMOVE_ZONE_SLAVE),
schema=SOUNDTOUCH_REMOVE_ZONE_SCHEMA) schema=SOUNDTOUCH_REMOVE_ZONE_SCHEMA)
hass.services.register(DOMAIN, SERVICE_ADD_ZONE_SLAVE, hass.services.register(DOMAIN, SERVICE_ADD_ZONE_SLAVE,
add_zone_slave, service_handle,
descriptions.get(SERVICE_ADD_ZONE_SLAVE), descriptions.get(SERVICE_ADD_ZONE_SLAVE),
schema=SOUNDTOUCH_ADD_ZONE_SCHEMA) schema=SOUNDTOUCH_ADD_ZONE_SCHEMA)
def play_everywhere_service(service):
"""
Create a zone (multi-room) and play on all devices.
:param service: Home Assistant service with 'master' data set
:Example:
- service: media_player.soundtouch_play_everywhere
data:
master: media_player.soundtouch_living_room
"""
master_device_id = service.data.get('master')
slaves = [d for d in DEVICES if d.entity_id != master_device_id]
master = next([device for device in DEVICES if
device.entity_id == master_device_id].__iter__(), None)
if master is None:
_LOGGER.warning(
"Unable to find master with entity_id:" + str(master_device_id))
elif not slaves:
_LOGGER.warning("Unable to create zone without slaves")
else:
_LOGGER.info(
"Creating zone with master " + str(master.device.config.name))
master.device.create_zone([slave.device for slave in slaves])
def create_zone_service(service):
"""
Create a zone (multi-room) on a master and play on specified slaves.
At least one master and one slave must be specified
:param service: Home Assistant service with 'master' and 'slaves' data set
:Example:
- service: media_player.soundtouch_create_zone
data:
master: media_player.soundtouch_living_room
slaves:
- media_player.soundtouch_room
- media_player.soundtouch_kitchen
"""
master_device_id = service.data.get('master')
slaves_ids = service.data.get('slaves')
slaves = [device for device in DEVICES if device.entity_id in slaves_ids]
master = next([device for device in DEVICES if
device.entity_id == master_device_id].__iter__(), None)
if master is None:
_LOGGER.warning(
"Unable to find master with entity_id:" + master_device_id)
elif not slaves:
_LOGGER.warning("Unable to create zone without slaves")
else:
_LOGGER.info(
"Creating zone with master " + str(master.device.config.name))
master.device.create_zone([slave.device for slave in slaves])
def add_zone_slave(service):
"""
Add slave(s) to and existing zone (multi-room).
Zone must already exist and slaves array can not be empty.
:param service: Home Assistant service with 'master' and 'slaves' data set
:Example:
- service: media_player.soundtouch_add_zone_slave
data:
master: media_player.soundtouch_living_room
slaves:
- media_player.soundtouch_room
"""
master_device_id = service.data.get('master')
slaves_ids = service.data.get('slaves')
slaves = [device for device in DEVICES if device.entity_id in slaves_ids]
master = next([device for device in DEVICES if
device.entity_id == master_device_id].__iter__(), None)
if master is None:
_LOGGER.warning(
"Unable to find master with entity_id:" + str(master_device_id))
elif not slaves:
_LOGGER.warning("Unable to find slaves to add")
else:
_LOGGER.info(
"Adding slaves to zone with master " + str(
master.device.config.name))
master.device.add_zone_slave([slave.device for slave in slaves])
def remove_zone_slave(service):
"""
Remove slave(s) from and existing zone (multi-room).
Zone must already exist and slaves array can not be empty.
Note: If removing last slave, the zone will be deleted and you'll have to
create a new one. You will not be able to add a new slave anymore
:param service: Home Assistant service with 'master' and 'slaves' data set
:Example:
- service: media_player.soundtouch_remove_zone_slave
data:
master: media_player.soundtouch_living_room
slaves:
- media_player.soundtouch_room
"""
master_device_id = service.data.get('master')
slaves_ids = service.data.get('slaves')
slaves = [device for device in DEVICES if device.entity_id in slaves_ids]
master = next([device for device in DEVICES if
device.entity_id == master_device_id].__iter__(), None)
if master is None:
_LOGGER.warning(
"Unable to find master with entity_id:" + master_device_id)
elif not slaves:
_LOGGER.warning("Unable to find slaves to remove")
else:
_LOGGER.info("Removing slaves from zone with master " +
str(master.device.config.name))
master.device.remove_zone_slave([slave.device for slave in slaves])
class SoundTouchDevice(MediaPlayerDevice): class SoundTouchDevice(MediaPlayerDevice):
"""Representation of a SoundTouch Bose device.""" """Representation of a SoundTouch Bose device."""
def __init__(self, name, config): def __init__(self, name, config):
"""Create Soundtouch Entity.""" """Create Soundtouch Entity."""
from libsoundtouch import soundtouch_device from libsoundtouch import soundtouch_device
self._name = name
self._device = soundtouch_device(config['host'], config['port']) self._device = soundtouch_device(config['host'], config['port'])
if name is None:
self._name = self._device.config.name
else:
self._name = name
self._status = self._device.status() self._status = self._device.status()
self._volume = self._device.volume() self._volume = self._device.volume()
self._config = config self._config = config
@ -297,7 +216,7 @@ class SoundTouchDevice(MediaPlayerDevice):
self._status = self._device.status() self._status = self._device.status()
def turn_on(self): def turn_on(self):
"""Turn the media player on.""" """Turn on media player."""
self._device.power_on() self._device.power_on()
self._status = self._device.status() self._status = self._device.status()
@ -392,3 +311,52 @@ class SoundTouchDevice(MediaPlayerDevice):
self._device.select_preset(preset) self._device.select_preset(preset)
else: else:
_LOGGER.warning("Unable to find preset with id " + str(media_id)) _LOGGER.warning("Unable to find preset with id " + str(media_id))
def create_zone(self, slaves):
"""
Create a zone (multi-room) and play on selected devices.
:param slaves: slaves on which to play
"""
if not slaves:
_LOGGER.warning("Unable to create zone without slaves")
else:
_LOGGER.info(
"Creating zone with master " + str(self.device.config.name))
self.device.create_zone([slave.device for slave in slaves])
def remove_zone_slave(self, slaves):
"""
Remove slave(s) from and existing zone (multi-room).
Zone must already exist and slaves array can not be empty.
Note: If removing last slave, the zone will be deleted and you'll have
to create a new one. You will not be able to add a new slave anymore
:param slaves: slaves to remove from the zone
"""
if not slaves:
_LOGGER.warning("Unable to find slaves to remove")
else:
_LOGGER.info("Removing slaves from zone with master " +
str(self.device.config.name))
self.device.remove_zone_slave([slave.device for slave in slaves])
def add_zone_slave(self, slaves):
"""
Add slave(s) to and existing zone (multi-room).
Zone must already exist and slaves array can not be empty.
:param slaves:slaves to add
"""
if not slaves:
_LOGGER.warning("Unable to find slaves to add")
else:
_LOGGER.info(
"Adding slaves to zone with master " + str(
self.device.config.name))
self.device.add_zone_slave([slave.device for slave in slaves])

View File

@ -358,7 +358,7 @@ knxip==0.3.3
libnacl==1.5.0 libnacl==1.5.0
# homeassistant.components.media_player.soundtouch # homeassistant.components.media_player.soundtouch
libsoundtouch==0.1.0 libsoundtouch==0.3.0
# homeassistant.components.light.lifx_legacy # homeassistant.components.light.lifx_legacy
liffylights==0.9.4 liffylights==0.9.4

View File

@ -155,21 +155,67 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
def tearDown(self): # pylint: disable=invalid-name def tearDown(self): # pylint: disable=invalid-name
"""Stop everything that was started.""" """Stop everything that was started."""
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
soundtouch.DEVICES = []
self.hass.stop() self.hass.stop()
@mock.patch('libsoundtouch.soundtouch_device', side_effect=None) @mock.patch('libsoundtouch.soundtouch_device', side_effect=None)
def test_ensure_setup_config(self, mocked_sountouch_device): def test_ensure_setup_config(self, mocked_sountouch_device):
"""Test setup OK.""" """Test setup OK with custom config."""
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
# soundtouch.DEVICES[0].entity_id = 'entity_1' all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(len(soundtouch.DEVICES), 1) self.assertEqual(len(all_devices), 1)
self.assertEqual(soundtouch.DEVICES[0].name, 'soundtouch') self.assertEqual(all_devices[0].name, 'soundtouch')
self.assertEqual(soundtouch.DEVICES[0].config['port'], 8090) self.assertEqual(all_devices[0].config['port'], 8090)
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
@mock.patch('libsoundtouch.soundtouch_device', side_effect=None)
def test_ensure_setup_discovery(self, mocked_sountouch_device):
"""Test setup with discovery."""
new_device = {"port": "8090",
"host": "192.168.1.1",
"properties": {},
"hostname": "hostname.local"}
soundtouch.setup_platform(self.hass,
None,
mock.MagicMock(),
new_device)
all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(len(all_devices), 1)
self.assertEqual(all_devices[0].config['port'], 8090)
self.assertEqual(all_devices[0].config['host'], '192.168.1.1')
self.assertEqual(mocked_sountouch_device.call_count, 1)
@mock.patch('libsoundtouch.soundtouch_device', side_effect=None)
def test_ensure_setup_discovery_no_duplicate(self,
mocked_sountouch_device):
"""Test setup OK if device already exists."""
soundtouch.setup_platform(self.hass,
default_component(),
mock.MagicMock())
self.assertEqual(len(self.hass.data[soundtouch.DATA_SOUNDTOUCH]), 1)
new_device = {"port": "8090",
"host": "192.168.1.1",
"properties": {},
"hostname": "hostname.local"}
soundtouch.setup_platform(self.hass,
None,
mock.MagicMock(),
new_device # New device
)
self.assertEqual(len(self.hass.data[soundtouch.DATA_SOUNDTOUCH]), 2)
existing_device = {"port": "8090",
"host": "192.168.0.1",
"properties": {},
"hostname": "hostname.local"}
soundtouch.setup_platform(self.hass,
None,
mock.MagicMock(),
existing_device # Existing device
)
self.assertEqual(mocked_sountouch_device.call_count, 2)
self.assertEqual(len(self.hass.data[soundtouch.DATA_SOUNDTOUCH]), 2)
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume') @mock.patch('libsoundtouch.device.SoundTouchDevice.volume')
@mock.patch('libsoundtouch.device.SoundTouchDevice.status') @mock.patch('libsoundtouch.device.SoundTouchDevice.status')
@mock.patch('libsoundtouch.soundtouch_device', @mock.patch('libsoundtouch.soundtouch_device',
@ -183,7 +229,7 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
soundtouch.DEVICES[0].update() self.hass.data[soundtouch.DATA_SOUNDTOUCH][0].update()
self.assertEqual(mocked_status.call_count, 2) self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 2) self.assertEqual(mocked_volume.call_count, 2)
@ -201,13 +247,14 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
self.assertEqual(soundtouch.DEVICES[0].state, STATE_PLAYING) all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(soundtouch.DEVICES[0].media_image_url, "image.url") self.assertEqual(all_devices[0].state, STATE_PLAYING)
self.assertEqual(soundtouch.DEVICES[0].media_title, "artist - track") self.assertEqual(all_devices[0].media_image_url, "image.url")
self.assertEqual(soundtouch.DEVICES[0].media_track, "track") self.assertEqual(all_devices[0].media_title, "artist - track")
self.assertEqual(soundtouch.DEVICES[0].media_artist, "artist") self.assertEqual(all_devices[0].media_track, "track")
self.assertEqual(soundtouch.DEVICES[0].media_album_name, "album") self.assertEqual(all_devices[0].media_artist, "artist")
self.assertEqual(soundtouch.DEVICES[0].media_duration, 1) self.assertEqual(all_devices[0].media_album_name, "album")
self.assertEqual(all_devices[0].media_duration, 1)
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume') @mock.patch('libsoundtouch.device.SoundTouchDevice.volume')
@mock.patch('libsoundtouch.device.SoundTouchDevice.status', @mock.patch('libsoundtouch.device.SoundTouchDevice.status',
@ -223,7 +270,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
self.assertEqual(soundtouch.DEVICES[0].media_title, None) all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(all_devices[0].media_title, None)
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume') @mock.patch('libsoundtouch.device.SoundTouchDevice.volume')
@mock.patch('libsoundtouch.device.SoundTouchDevice.status', @mock.patch('libsoundtouch.device.SoundTouchDevice.status',
@ -239,13 +287,14 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
self.assertEqual(soundtouch.DEVICES[0].state, STATE_PLAYING) all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(soundtouch.DEVICES[0].media_image_url, "image.url") self.assertEqual(all_devices[0].state, STATE_PLAYING)
self.assertEqual(soundtouch.DEVICES[0].media_title, "station") self.assertEqual(all_devices[0].media_image_url, "image.url")
self.assertEqual(soundtouch.DEVICES[0].media_track, None) self.assertEqual(all_devices[0].media_title, "station")
self.assertEqual(soundtouch.DEVICES[0].media_artist, None) self.assertEqual(all_devices[0].media_track, None)
self.assertEqual(soundtouch.DEVICES[0].media_album_name, None) self.assertEqual(all_devices[0].media_artist, None)
self.assertEqual(soundtouch.DEVICES[0].media_duration, None) self.assertEqual(all_devices[0].media_album_name, None)
self.assertEqual(all_devices[0].media_duration, None)
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume', @mock.patch('libsoundtouch.device.SoundTouchDevice.volume',
side_effect=MockVolume) side_effect=MockVolume)
@ -261,7 +310,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
self.assertEqual(soundtouch.DEVICES[0].volume_level, 0.12) all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(all_devices[0].volume_level, 0.12)
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume') @mock.patch('libsoundtouch.device.SoundTouchDevice.volume')
@mock.patch('libsoundtouch.device.SoundTouchDevice.status', @mock.patch('libsoundtouch.device.SoundTouchDevice.status',
@ -277,7 +327,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
self.assertEqual(soundtouch.DEVICES[0].state, STATE_OFF) all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(all_devices[0].state, STATE_OFF)
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume') @mock.patch('libsoundtouch.device.SoundTouchDevice.volume')
@mock.patch('libsoundtouch.device.SoundTouchDevice.status', @mock.patch('libsoundtouch.device.SoundTouchDevice.status',
@ -293,7 +344,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
self.assertEqual(soundtouch.DEVICES[0].state, STATE_PAUSED) all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(all_devices[0].state, STATE_PAUSED)
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume', @mock.patch('libsoundtouch.device.SoundTouchDevice.volume',
side_effect=MockVolumeMuted) side_effect=MockVolumeMuted)
@ -309,7 +361,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
self.assertEqual(soundtouch.DEVICES[0].is_volume_muted, True) all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(all_devices[0].is_volume_muted, True)
@mock.patch('libsoundtouch.soundtouch_device') @mock.patch('libsoundtouch.soundtouch_device')
def test_media_commands(self, mocked_sountouch_device): def test_media_commands(self, mocked_sountouch_device):
@ -318,7 +371,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(soundtouch.DEVICES[0].supported_features, 17853) all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(all_devices[0].supported_features, 17853)
@mock.patch('libsoundtouch.device.SoundTouchDevice.power_off') @mock.patch('libsoundtouch.device.SoundTouchDevice.power_off')
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume') @mock.patch('libsoundtouch.device.SoundTouchDevice.volume')
@ -331,7 +385,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].turn_off() all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
all_devices[0].turn_off()
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 2) self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
@ -348,7 +403,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].turn_on() all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
all_devices[0].turn_on()
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 2) self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
@ -365,7 +421,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].volume_up() all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
all_devices[0].volume_up()
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 2) self.assertEqual(mocked_volume.call_count, 2)
@ -382,7 +439,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].volume_down() all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
all_devices[0].volume_down()
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 2) self.assertEqual(mocked_volume.call_count, 2)
@ -399,7 +457,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].set_volume_level(0.17) all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
all_devices[0].set_volume_level(0.17)
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 2) self.assertEqual(mocked_volume.call_count, 2)
@ -416,7 +475,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].mute_volume(None) all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
all_devices[0].mute_volume(None)
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 2) self.assertEqual(mocked_volume.call_count, 2)
@ -433,7 +493,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].media_play() all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
all_devices[0].media_play()
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 2) self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
@ -450,7 +511,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].media_pause() all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
all_devices[0].media_pause()
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 2) self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
@ -467,7 +529,8 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].media_play_pause() all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
all_devices[0].media_play_pause()
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 2) self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
@ -486,13 +549,14 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
soundtouch.DEVICES[0].media_next_track() all_devices[0].media_next_track()
self.assertEqual(mocked_status.call_count, 2) self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_next_track.call_count, 1) self.assertEqual(mocked_next_track.call_count, 1)
soundtouch.DEVICES[0].media_previous_track() all_devices[0].media_previous_track()
self.assertEqual(mocked_status.call_count, 3) self.assertEqual(mocked_status.call_count, 3)
self.assertEqual(mocked_previous_track.call_count, 1) self.assertEqual(mocked_previous_track.call_count, 1)
@ -509,13 +573,14 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
self.assertEqual(mocked_sountouch_device.call_count, 1) self.assertEqual(mocked_sountouch_device.call_count, 1)
self.assertEqual(mocked_status.call_count, 1) self.assertEqual(mocked_status.call_count, 1)
self.assertEqual(mocked_volume.call_count, 1) self.assertEqual(mocked_volume.call_count, 1)
soundtouch.DEVICES[0].play_media('PLAYLIST', 1) all_devices[0].play_media('PLAYLIST', 1)
self.assertEqual(mocked_presets.call_count, 1) self.assertEqual(mocked_presets.call_count, 1)
self.assertEqual(mocked_select_preset.call_count, 1) self.assertEqual(mocked_select_preset.call_count, 1)
soundtouch.DEVICES[0].play_media('PLAYLIST', 2) all_devices[0].play_media('PLAYLIST', 2)
self.assertEqual(mocked_presets.call_count, 2) self.assertEqual(mocked_presets.call_count, 2)
self.assertEqual(mocked_select_preset.call_count, 1) self.assertEqual(mocked_select_preset.call_count, 1)
@ -533,26 +598,30 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].entity_id = "entity_1" all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
soundtouch.DEVICES[1].entity_id = "entity_2" all_devices[0].entity_id = "media_player.entity_1"
all_devices[1].entity_id = "media_player.entity_2"
self.assertEqual(mocked_sountouch_device.call_count, 2) self.assertEqual(mocked_sountouch_device.call_count, 2)
self.assertEqual(mocked_status.call_count, 2) self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 2) self.assertEqual(mocked_volume.call_count, 2)
# one master, one slave => create zone # one master, one slave => create zone
service = MockService("entity_1", []) self.hass.services.call(soundtouch.DOMAIN,
soundtouch.play_everywhere_service(service) soundtouch.SERVICE_PLAY_EVERYWHERE,
{"master": "media_player.entity_1"}, True)
self.assertEqual(mocked_create_zone.call_count, 1) self.assertEqual(mocked_create_zone.call_count, 1)
# unknown master. create zone is must not be called # unknown master. create zone is must not be called
service = MockService("entity_X", []) self.hass.services.call(soundtouch.DOMAIN,
soundtouch.play_everywhere_service(service) soundtouch.SERVICE_PLAY_EVERYWHERE,
{"master": "media_player.entity_X"}, True)
self.assertEqual(mocked_create_zone.call_count, 1) self.assertEqual(mocked_create_zone.call_count, 1)
# no slaves, create zone must not be called # no slaves, create zone must not be called
soundtouch.DEVICES.pop(1) all_devices.pop(1)
service = MockService("entity_1", []) self.hass.services.call(soundtouch.DOMAIN,
soundtouch.play_everywhere_service(service) soundtouch.SERVICE_PLAY_EVERYWHERE,
{"master": "media_player.entity_1"}, True)
self.assertEqual(mocked_create_zone.call_count, 1) self.assertEqual(mocked_create_zone.call_count, 1)
@mock.patch('libsoundtouch.device.SoundTouchDevice.create_zone') @mock.patch('libsoundtouch.device.SoundTouchDevice.create_zone')
@ -569,63 +638,34 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].entity_id = "entity_1" all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
soundtouch.DEVICES[1].entity_id = "entity_2" all_devices[0].entity_id = "media_player.entity_1"
all_devices[1].entity_id = "media_player.entity_2"
self.assertEqual(mocked_sountouch_device.call_count, 2) self.assertEqual(mocked_sountouch_device.call_count, 2)
self.assertEqual(mocked_status.call_count, 2) self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 2) self.assertEqual(mocked_volume.call_count, 2)
# one master, one slave => create zone # one master, one slave => create zone
service = MockService("entity_1", ["entity_2"]) self.hass.services.call(soundtouch.DOMAIN,
soundtouch.create_zone_service(service) soundtouch.SERVICE_CREATE_ZONE,
{"master": "media_player.entity_1",
"slaves": ["media_player.entity_2"]}, True)
self.assertEqual(mocked_create_zone.call_count, 1) self.assertEqual(mocked_create_zone.call_count, 1)
# unknown master. create zone is must not be called # unknown master. create zone is must not be called
service = MockService("entity_X", []) self.hass.services.call(soundtouch.DOMAIN,
soundtouch.create_zone_service(service) soundtouch.SERVICE_CREATE_ZONE,
{"master": "media_player.entity_X",
"slaves": ["media_player.entity_2"]}, True)
self.assertEqual(mocked_create_zone.call_count, 1) self.assertEqual(mocked_create_zone.call_count, 1)
# no slaves, create zone must not be called # no slaves, create zone must not be called
soundtouch.DEVICES.pop(1) self.hass.services.call(soundtouch.DOMAIN,
service = MockService("entity_1", []) soundtouch.SERVICE_CREATE_ZONE,
soundtouch.create_zone_service(service) {"master": "media_player.entity_X",
"slaves": []}, True)
self.assertEqual(mocked_create_zone.call_count, 1) self.assertEqual(mocked_create_zone.call_count, 1)
@mock.patch('libsoundtouch.device.SoundTouchDevice.add_zone_slave')
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume')
@mock.patch('libsoundtouch.device.SoundTouchDevice.status')
@mock.patch('libsoundtouch.soundtouch_device',
side_effect=_mock_soundtouch_device)
def test_add_zone_slave(self, mocked_sountouch_device, mocked_status,
mocked_volume, mocked_add_zone_slave):
"""Test adding a slave to an existing zone."""
soundtouch.setup_platform(self.hass,
default_component(),
mock.MagicMock())
soundtouch.setup_platform(self.hass,
default_component(),
mock.MagicMock())
soundtouch.DEVICES[0].entity_id = "entity_1"
soundtouch.DEVICES[1].entity_id = "entity_2"
self.assertEqual(mocked_sountouch_device.call_count, 2)
self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 2)
# remove one slave
service = MockService("entity_1", ["entity_2"])
soundtouch.add_zone_slave(service)
self.assertEqual(mocked_add_zone_slave.call_count, 1)
# unknown master. add zone slave is not called
service = MockService("entity_X", ["entity_2"])
soundtouch.add_zone_slave(service)
self.assertEqual(mocked_add_zone_slave.call_count, 1)
# no slave to add, add zone slave is not called
service = MockService("entity_1", [])
soundtouch.add_zone_slave(service)
self.assertEqual(mocked_add_zone_slave.call_count, 1)
@mock.patch('libsoundtouch.device.SoundTouchDevice.remove_zone_slave') @mock.patch('libsoundtouch.device.SoundTouchDevice.remove_zone_slave')
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume') @mock.patch('libsoundtouch.device.SoundTouchDevice.volume')
@mock.patch('libsoundtouch.device.SoundTouchDevice.status') @mock.patch('libsoundtouch.device.SoundTouchDevice.status')
@ -633,6 +673,48 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
side_effect=_mock_soundtouch_device) side_effect=_mock_soundtouch_device)
def test_remove_zone_slave(self, mocked_sountouch_device, mocked_status, def test_remove_zone_slave(self, mocked_sountouch_device, mocked_status,
mocked_volume, mocked_remove_zone_slave): mocked_volume, mocked_remove_zone_slave):
"""Test adding a slave to an existing zone."""
soundtouch.setup_platform(self.hass,
default_component(),
mock.MagicMock())
soundtouch.setup_platform(self.hass,
default_component(),
mock.MagicMock())
all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
all_devices[0].entity_id = "media_player.entity_1"
all_devices[1].entity_id = "media_player.entity_2"
self.assertEqual(mocked_sountouch_device.call_count, 2)
self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 2)
# remove one slave
self.hass.services.call(soundtouch.DOMAIN,
soundtouch.SERVICE_REMOVE_ZONE_SLAVE,
{"master": "media_player.entity_1",
"slaves": ["media_player.entity_2"]}, True)
self.assertEqual(mocked_remove_zone_slave.call_count, 1)
# unknown master. add zone slave is not called
self.hass.services.call(soundtouch.DOMAIN,
soundtouch.SERVICE_REMOVE_ZONE_SLAVE,
{"master": "media_player.entity_X",
"slaves": ["media_player.entity_2"]}, True)
self.assertEqual(mocked_remove_zone_slave.call_count, 1)
# no slave to add, add zone slave is not called
self.hass.services.call(soundtouch.DOMAIN,
soundtouch.SERVICE_REMOVE_ZONE_SLAVE,
{"master": "media_player.entity_1",
"slaves": []}, True)
self.assertEqual(mocked_remove_zone_slave.call_count, 1)
@mock.patch('libsoundtouch.device.SoundTouchDevice.add_zone_slave')
@mock.patch('libsoundtouch.device.SoundTouchDevice.volume')
@mock.patch('libsoundtouch.device.SoundTouchDevice.status')
@mock.patch('libsoundtouch.soundtouch_device',
side_effect=_mock_soundtouch_device)
def test_add_zone_slave(self, mocked_sountouch_device, mocked_status,
mocked_volume, mocked_add_zone_slave):
"""Test removing a slave from a zone.""" """Test removing a slave from a zone."""
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
@ -640,23 +722,30 @@ class TestSoundtouchMediaPlayer(unittest.TestCase):
soundtouch.setup_platform(self.hass, soundtouch.setup_platform(self.hass,
default_component(), default_component(),
mock.MagicMock()) mock.MagicMock())
soundtouch.DEVICES[0].entity_id = "entity_1" all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH]
soundtouch.DEVICES[1].entity_id = "entity_2" all_devices[0].entity_id = "media_player.entity_1"
all_devices[1].entity_id = "media_player.entity_2"
self.assertEqual(mocked_sountouch_device.call_count, 2) self.assertEqual(mocked_sountouch_device.call_count, 2)
self.assertEqual(mocked_status.call_count, 2) self.assertEqual(mocked_status.call_count, 2)
self.assertEqual(mocked_volume.call_count, 2) self.assertEqual(mocked_volume.call_count, 2)
# remove one slave # add one slave
service = MockService("entity_1", ["entity_2"]) self.hass.services.call(soundtouch.DOMAIN,
soundtouch.remove_zone_slave(service) soundtouch.SERVICE_ADD_ZONE_SLAVE,
self.assertEqual(mocked_remove_zone_slave.call_count, 1) {"master": "media_player.entity_1",
"slaves": ["media_player.entity_2"]}, True)
self.assertEqual(mocked_add_zone_slave.call_count, 1)
# unknown master. remove zone slave is not called # unknown master. add zone slave is not called
service = MockService("entity_X", ["entity_2"]) self.hass.services.call(soundtouch.DOMAIN,
soundtouch.remove_zone_slave(service) soundtouch.SERVICE_ADD_ZONE_SLAVE,
self.assertEqual(mocked_remove_zone_slave.call_count, 1) {"master": "media_player.entity_X",
"slaves": ["media_player.entity_2"]}, True)
self.assertEqual(mocked_add_zone_slave.call_count, 1)
# no slave to add, add zone slave is not called # no slave to add, add zone slave is not called
service = MockService("entity_1", []) self.hass.services.call(soundtouch.DOMAIN,
soundtouch.remove_zone_slave(service) soundtouch.SERVICE_ADD_ZONE_SLAVE,
self.assertEqual(mocked_remove_zone_slave.call_count, 1) {"master": "media_player.entity_1",
"slaves": ["media_player.entity_X"]}, True)
self.assertEqual(mocked_add_zone_slave.call_count, 1)