Skip to content

Commit

Permalink
Merge a737af3 into 6417a99
Browse files Browse the repository at this point in the history
  • Loading branch information
simonalpha committed Oct 18, 2014
2 parents 6417a99 + a737af3 commit 0ffc0ef
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 26 deletions.
62 changes: 42 additions & 20 deletions soco/core.py
Expand Up @@ -800,6 +800,31 @@ def _parse_zone_group_state(self):
# </ZoneGroups>
#

def parse_zone_group_member(member_element):
""" Parse a ZoneGroupMember or Satellite element from Zone Group
State, create a SoCo instance for the member, set basic attributes
and return it. """
# Create a SoCo instance for each member. Because SoCo
# instances are singletons, this is cheap if they have already
# been created, and useful if they haven't. We can then
# update various properties for that instance.
member_attribs = member_element.attrib
ip_addr = member_attribs['Location'].\
split('//')[1].split(':')[0]
zone = config.SOCO_CLASS(ip_addr)
# uid doesn't change, but it's not harmful to (re)set it, in case
# the zone is as yet unseen.
zone._uid = member_attribs['UUID']
zone._player_name = member_attribs['ZoneName']
# add the zone to the set of all members, and to the set
# of visible members if appropriate
is_visible = False if member_attribs.get(
'Invisible') == '1' else True
if is_visible:
self._visible_zones.add(zone)
self._all_zones.add(zone)
return zone

# This is called quite frequently, so it is worth optimising it.
# Maintain a private cache. If the zgt has not changed, there is no
# need to repeat all the XML parsing. In addition, switch on network
Expand All @@ -822,36 +847,33 @@ def _parse_zone_group_state(self):
group_coordinator = None
members = set()
for member_element in group_element.findall('ZoneGroupMember'):
# Create a SoCo instance for each member. Because SoCo
# instances are singletons, this is cheap if they have already
# been created, and useful if they haven't. We can then
# update various properties for that instance.
member_attribs = member_element.attrib
ip_addr = member_attribs['Location'].\
split('//')[1].split(':')[0]
zone = config.SOCO_CLASS(ip_addr)
zone._uid = member_attribs['UUID']
zone = parse_zone_group_member(member_element)
# Perform extra processing relevant to direct zone group
# members
#
# If this element has the same UUID as the coordinator, it is
# the coordinator
if zone._uid == coordinator_uid:
group_coordinator = zone
zone._is_coordinator = True
else:
zone._is_coordinator = False
zone._player_name = member_attribs['ZoneName']
# uid and is_bridge do not change, but it does no real harm to
# set/reset them here, just in case the zone has not been seen
# is_bridge doesn't change, but it does no real harm to
# set/reset it here, just in case the zone has not been seen
# before
zone._is_bridge = True if member_attribs.get(
zone._is_bridge = True if member_element.attrib.get(
'IsZoneBridge') == '1' else False
is_visible = False if member_attribs.get(
'Invisible') == '1' else True
# add the zone to the members for this group, and to the set of
# all members, and to the set of visible members if appropriate
# add the zone to the members for this group
members.add(zone)
self._all_zones.add(zone)
if is_visible:
self._visible_zones.add(zone)
# Loop over Satellite elements if present, and process as for
# ZoneGroup elements
for satellite_element in member_element.findall('Satellite'):
zone = parse_zone_group_member(satellite_element)
# Assume a satellite can't be a bridge or coordinator, so
# no need to check.
#
# Add the zone to the members for this group.
members.add(zone)
# Now create a ZoneGroup with this info and add it to the list
# of groups
self._groups.add(ZoneGroup(group_uid, group_coordinator, members))
Expand Down
58 changes: 52 additions & 6 deletions unittest/test_core.py
Expand Up @@ -63,6 +63,52 @@ def moco():
UUID="RINCON_000YYY1400"
ZoneName="Kitchen"/>
</ZoneGroup>
<ZoneGroup Coordinator="RINCON_000PPP1400" ID="RINCON_000PPP1400:49">
<ZoneGroupMember
BootSeq="8"
Configuration="1"
HTSatChanMapSet="RINCON_000PPP1400:LF,RF;RINCON_000RRR1400:RR;RINCON_000SSS1400:LR;RINCON_000QQQ1400:SW"
Icon="x-rincon-roomicon:living"
Location="http://192.168.1.103:1400/xml/device_description.xml"
MinCompatibleVersion="22.0-00000"
SoftwareVersion="24.0-71060"
UUID="RINCON_000PPP1400"
ZoneName="Home Theatre">
<Satellite
BootSeq="4"
Configuration="1"
HTSatChanMapSet="RINCON_000PPP1400:LF,RF;RINCON_000QQQ1400:SW"
Icon="x-rincon-roomicon:living"
Invisible="1"
Location="http://192.168.1.104:1400/xml/device_description.xml"
MinCompatibleVersion="22.0-00000"
SoftwareVersion="24.0-71060"
UUID="RINCON_000QQQ1400"
ZoneName="Home Theatre"/>
<Satellite
BootSeq="6"
Configuration="1"
HTSatChanMapSet="RINCON_000PPP1400:LF,RF;RINCON_000RRR1400:RR"
Icon="x-rincon-roomicon:living"
Invisible="1"
Location="http://192.168.1.105:1400/xml/device_description.xml"
MinCompatibleVersion="22.0-00000"
SoftwareVersion="24.0-71060"
UUID="RINCON_000RRR1400"
ZoneName="Home Theatre"/>
<Satellite
BootSeq="4"
Configuration="1"
HTSatChanMapSet="RINCON_000PPP1400:LF,RF;RINCON_000SSS1400:LR"
Icon="x-rincon-roomicon:living"
Invisible="1"
Location="http://192.168.1.106:1400/xml/device_description.xml"
MinCompatibleVersion="22.0-00000"
SoftwareVersion="24.0-71060"
UUID="RINCON_000SSS1400"
ZoneName="Home Theatre"/>
</ZoneGroupMember>
</ZoneGroup>
</ZoneGroups>"""

@pytest.yield_fixture
Expand Down Expand Up @@ -480,9 +526,9 @@ def test_soco_is_coordinator(self, moco_zgs):

def test_all_groups(self, moco_zgs):
groups = moco_zgs.all_groups
assert len(groups) == 2
assert len(groups) == 3
# Check 3 unique groups
assert len(set(groups)) == 2
assert len(set(groups)) == 3
for group in groups:
assert isinstance(group, ZoneGroup)

Expand All @@ -496,16 +542,16 @@ def test_group(self, moco_zgs):

def test_all_zones(selfself, moco_zgs):
zones = moco_zgs.all_zones
assert len(zones) == 3
assert len(set(zones)) == 3
assert len(zones) == 7
assert len(set(zones)) == 7
for zone in zones:
assert isinstance(zone, SoCo)
assert moco_zgs in zones

def test_visible_zones(selfself, moco_zgs):
zones = moco_zgs.visible_zones
assert len(zones) == 2
assert len(set(zones)) == 2
assert len(zones) == 3
assert len(set(zones)) == 3
for zone in zones:
assert isinstance(zone, SoCo)
assert moco_zgs in zones
Expand Down

0 comments on commit 0ffc0ef

Please sign in to comment.