From 68ea6d3a8e82dbacbfd075b325de4de3fe965d24 Mon Sep 17 00:00:00 2001 From: Sean Dague Date: Sun, 13 Nov 2016 07:03:59 -0500 Subject: [PATCH] make get_playback_support dynamic 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. --- rxv/rxv.py | 61 +++--- tests/samples/rx-v675-inputs-resp.xml | 273 ++++++++++++++++++++++++++ tests/test_feature_support.py | 27 +++ 3 files changed, 334 insertions(+), 27 deletions(-) create mode 100644 tests/samples/rx-v675-inputs-resp.xml diff --git a/rxv/rxv.py b/rxv/rxv.py index 1c85374..c19c705 100644 --- a/rxv/rxv.py +++ b/rxv/rxv.py @@ -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") @@ -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') diff --git a/tests/samples/rx-v675-inputs-resp.xml b/tests/samples/rx-v675-inputs-resp.xml new file mode 100644 index 0000000..527e852 --- /dev/null +++ b/tests/samples/rx-v675-inputs-resp.xml @@ -0,0 +1,273 @@ + + + + + + + Rhapsody + RW + Rhapsody + + /YamahaRemoteControl/Icons/icon076.png + + + Rhapsody + 1 + + + SiriusXM + RW + SiriusXM + + /YamahaRemoteControl/Icons/icon078.png + + + SiriusXM + 1 + + + Pandora + RW + Pandora + + /YamahaRemoteControl/Icons/icon075.png + + + Pandora + 1 + + + Spotify + RW + Spotify + + /YamahaRemoteControl/Icons/icon102.png + + + Spotify + 1 + + + NET RADIO + RW + NET RADIO + + /YamahaRemoteControl/Icons/icon005.png + + + NET_RADIO + 1 + + + SERVER + RW + SERVER + + /YamahaRemoteControl/Icons/icon006.png + + + SERVER + 1 + + + AirPlay + RW + AirPlay + + /YamahaRemoteControl/Icons/icon067.png + + + AirPlay + 1 + + + USB + RW + USB + + /YamahaRemoteControl/Icons/icon009.png + + + USB + 1 + + + iPod (USB) + R + USB + + /YamahaRemoteControl/Icons/icon011.png + + + iPod_USB + 1 + + + TUNER + RW + TUNER + + /YamahaRemoteControl/Icons/icon008.png + + + Tuner + 1 + + + HDMI1 + RW + HDMI1 + + /YamahaRemoteControl/Icons/icon004.png + + + + 1 + + + HDMI2 + RW + HDMI2 + + /YamahaRemoteControl/Icons/icon004.png + + + + 1 + + + HDMI3 + RW + HDMI3 + + /YamahaRemoteControl/Icons/icon004.png + + + + 1 + + + HDMI4 + RW + HDMI4 + + /YamahaRemoteControl/Icons/icon004.png + + + + 1 + + + HDMI5 + RW + HDMI5 + + /YamahaRemoteControl/Icons/icon004.png + + + + 1 + + + AV1 + RW + AV1 + + /YamahaRemoteControl/Icons/icon003.png + + + + 1 + + + AV2 + RW + AV2 + + /YamahaRemoteControl/Icons/icon003.png + + + + 1 + + + AV3 + RW + AV3 + + /YamahaRemoteControl/Icons/icon003.png + + + + 1 + + + AV4 + RW + AV4 + + /YamahaRemoteControl/Icons/icon003.png + + + + 1 + + + AV5 + RW + AV5 + + /YamahaRemoteControl/Icons/icon003.png + + + + 1 + + + AV6 + RW + AV6 + + /YamahaRemoteControl/Icons/icon003.png + + + + 1 + + + AUDIO1 + RW + AUDIO1 + + /YamahaRemoteControl/Icons/icon002.png + + + + 1 + + + AUDIO2 + RW + AUDIO2 + + /YamahaRemoteControl/Icons/icon002.png + + + + 1 + + + V-AUX + RW + V-AUX + + /YamahaRemoteControl/Icons/icon010.png + + + + 1 + + + + + diff --git a/tests/test_feature_support.py b/tests/test_feature_support.py index c1c8194..44909bc 100644 --- a/tests/test_feature_support.py +++ b/tests/test_feature_support.py @@ -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)