Skip to content

Commit

Permalink
make get_playback_support dynamic
Browse files Browse the repository at this point in the history
This moves get_playback_support from static definitions, to dynamic
based parsing desc.xml. The PlaybackSupport object is changed from
enum to a set of boolean attributes, for making it easier to convert
to equivalent structures at higher levels.
  • Loading branch information
sdague committed Nov 14, 2016
1 parent 1bff467 commit 68ea6d3
Show file tree
Hide file tree
Showing 3 changed files with 334 additions and 27 deletions.
61 changes: 34 additions & 27 deletions rxv/rxv.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,23 @@

logger = logging.getLogger('rxv')

# Used as an enum to indicate support for individual playback controls

class PlaybackSupport:
NONE = 0

PLAY = (1 << 0)
STOP = (1 << 1)
PAUSE = (1 << 2)
NEXT = (1 << 3)
PREV = (1 << 4)

BASIC = (PLAY | STOP | PAUSE)
NAVIGATION = (NEXT | PREV)
ALL = (BASIC | NAVIGATION)

# Add sources that support playback and what they support
SOURCES_SUPPORTING_PLAYBACK = {
'SERVER': PlaybackSupport.ALL,
'USB': PlaybackSupport.ALL,
'NET RADIO': PlaybackSupport.BASIC,
'NAPSTER': PlaybackSupport.ALL,
'TUNER': PlaybackSupport.ALL,
'iPod (USB)': PlaybackSupport.ALL,
'AirPlay': PlaybackSupport.ALL
}
"""Container for Playback support.
This stores a set of booleans so that they are easy to turn into
whatever format the support needs to be specified at a higher
level.
"""
def __init__(self, play=False, stop=False, pause=False,
skip_f=False, skip_r=False):
self.play = play
self.stop = stop
self.pause = pause
self.skip_f = skip_f
self.skip_r = skip_r


BasicStatus = namedtuple("BasicStatus", "on volume mute input")
PlayStatus = namedtuple("PlayStatus", "playing artist album song station")
Expand Down Expand Up @@ -178,16 +171,30 @@ def off(self):
return self.on(False)

def get_playback_support(self, input_source=None):
"""Get playback support as bit vector.
In order to expose features correctly in Home Assistant, we
need to make it possible to understand what play operations a
source supports. This builds us a Home Assistant compatible
bit vector from the desc.xml for the specified source.
"""

if input_source is None:
input_source = self.input
if input_source not in SOURCES_SUPPORTING_PLAYBACK:
return PlaybackSupport.NONE
return SOURCES_SUPPORTING_PLAYBACK[input_source]
src_name = self._src_name(input_source)

return PlaybackSupport(
play=self.supports_play_method(src_name, 'Play'),
pause=self.supports_play_method(src_name, 'Pause'),
stop=self.supports_play_method(src_name, 'Stop'),
skip_f=self.supports_play_method(src_name, 'Skip Fwd'),
skip_r=self.supports_play_method(src_name, 'Skip Rev'))

def is_playback_supported(self, input_source=None):
if input_source is None:
input_source = self.input
return input_source in SOURCES_SUPPORTING_PLAYBACK
support = self.get_playback_support(input_source)
return support.play

def play(self):
self._playback_control('Play')
Expand Down
273 changes: 273 additions & 0 deletions tests/samples/rx-v675-inputs-resp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
<?xml version="1.0"?>
<YAMAHA_AV rsp="GET" RC="0">
<Main_Zone>
<Input>
<Input_Sel_Item>
<Item_1>
<Param>Rhapsody</Param>
<RW>RW</RW>
<Title>Rhapsody</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon076.png</On>
<Off/>
</Icon>
<Src_Name>Rhapsody</Src_Name>
<Src_Number>1</Src_Number>
</Item_1>
<Item_2>
<Param>SiriusXM</Param>
<RW>RW</RW>
<Title>SiriusXM</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon078.png</On>
<Off/>
</Icon>
<Src_Name>SiriusXM</Src_Name>
<Src_Number>1</Src_Number>
</Item_2>
<Item_3>
<Param>Pandora</Param>
<RW>RW</RW>
<Title>Pandora</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon075.png</On>
<Off/>
</Icon>
<Src_Name>Pandora</Src_Name>
<Src_Number>1</Src_Number>
</Item_3>
<Item_4>
<Param>Spotify</Param>
<RW>RW</RW>
<Title>Spotify</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon102.png</On>
<Off/>
</Icon>
<Src_Name>Spotify</Src_Name>
<Src_Number>1</Src_Number>
</Item_4>
<Item_5>
<Param>NET RADIO</Param>
<RW>RW</RW>
<Title>NET RADIO</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon005.png</On>
<Off/>
</Icon>
<Src_Name>NET_RADIO</Src_Name>
<Src_Number>1</Src_Number>
</Item_5>
<Item_6>
<Param>SERVER</Param>
<RW>RW</RW>
<Title>SERVER</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon006.png</On>
<Off/>
</Icon>
<Src_Name>SERVER</Src_Name>
<Src_Number>1</Src_Number>
</Item_6>
<Item_7>
<Param>AirPlay</Param>
<RW>RW</RW>
<Title>AirPlay</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon067.png</On>
<Off/>
</Icon>
<Src_Name>AirPlay</Src_Name>
<Src_Number>1</Src_Number>
</Item_7>
<Item_8>
<Param>USB</Param>
<RW>RW</RW>
<Title>USB</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon009.png</On>
<Off/>
</Icon>
<Src_Name>USB</Src_Name>
<Src_Number>1</Src_Number>
</Item_8>
<Item_9>
<Param>iPod (USB)</Param>
<RW>R</RW>
<Title>USB</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon011.png</On>
<Off/>
</Icon>
<Src_Name>iPod_USB</Src_Name>
<Src_Number>1</Src_Number>
</Item_9>
<Item_10>
<Param>TUNER</Param>
<RW>RW</RW>
<Title>TUNER</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon008.png</On>
<Off/>
</Icon>
<Src_Name>Tuner</Src_Name>
<Src_Number>1</Src_Number>
</Item_10>
<Item_11>
<Param>HDMI1</Param>
<RW>RW</RW>
<Title>HDMI1</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon004.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_11>
<Item_12>
<Param>HDMI2</Param>
<RW>RW</RW>
<Title>HDMI2</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon004.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_12>
<Item_13>
<Param>HDMI3</Param>
<RW>RW</RW>
<Title>HDMI3</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon004.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_13>
<Item_14>
<Param>HDMI4</Param>
<RW>RW</RW>
<Title>HDMI4</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon004.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_14>
<Item_15>
<Param>HDMI5</Param>
<RW>RW</RW>
<Title>HDMI5</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon004.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_15>
<Item_16>
<Param>AV1</Param>
<RW>RW</RW>
<Title>AV1</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon003.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_16>
<Item_17>
<Param>AV2</Param>
<RW>RW</RW>
<Title>AV2</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon003.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_17>
<Item_18>
<Param>AV3</Param>
<RW>RW</RW>
<Title>AV3</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon003.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_18>
<Item_19>
<Param>AV4</Param>
<RW>RW</RW>
<Title>AV4</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon003.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_19>
<Item_20>
<Param>AV5</Param>
<RW>RW</RW>
<Title>AV5</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon003.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_20>
<Item_21>
<Param>AV6</Param>
<RW>RW</RW>
<Title>AV6</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon003.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_21>
<Item_22>
<Param>AUDIO1</Param>
<RW>RW</RW>
<Title>AUDIO1</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon002.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_22>
<Item_23>
<Param>AUDIO2</Param>
<RW>RW</RW>
<Title>AUDIO2</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon002.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_23>
<Item_24>
<Param>V-AUX</Param>
<RW>RW</RW>
<Title>V-AUX</Title>
<Icon>
<On>/YamahaRemoteControl/Icons/icon010.png</On>
<Off/>
</Icon>
<Src_Name/>
<Src_Number>1</Src_Number>
</Item_24>
</Input_Sel_Item>
</Input>
</Main_Zone>
</YAMAHA_AV>
27 changes: 27 additions & 0 deletions tests/test_feature_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,30 @@ def test_supports_play_method(self):
self.assertTrue(rec.supports_play_method("SERVER", "Stop"))
self.assertTrue(rec.supports_play_method("SERVER", "Skip Fwd"))
self.assertTrue(rec.supports_play_method("SERVER", "Skip Rev"))

@requests_mock.mock()
def test_playback_support(self, m):
rec = self.rec
# we need to mock this out so that .inputs() work
m.post(rec.ctrl_url, text=sample_content('rx-v675-inputs-resp.xml'))

support = rec.get_playback_support("NET RADIO")
self.assertTrue(support.play)
self.assertTrue(support.stop)
self.assertFalse(support.pause)
self.assertFalse(support.skip_f)
self.assertFalse(support.skip_r)

support = rec.get_playback_support("HDMI1")
self.assertFalse(support.play)
self.assertFalse(support.stop)
self.assertFalse(support.pause)
self.assertFalse(support.skip_f)
self.assertFalse(support.skip_r)

support = rec.get_playback_support("SERVER")
self.assertTrue(support.play)
self.assertTrue(support.stop)
self.assertTrue(support.pause)
self.assertTrue(support.skip_f)
self.assertTrue(support.skip_r)

0 comments on commit 68ea6d3

Please sign in to comment.