-
-
Notifications
You must be signed in to change notification settings - Fork 37.4k
Sound mode support media_player general and denonavr #11764
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8437591
11963fc
75f5475
6dcafbc
b4b5c25
463e889
29d687c
c6ddfd6
95bab12
d3494bf
0903efb
c192350
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,15 +6,18 @@ | |
| """ | ||
|
|
||
| import logging | ||
| from collections import namedtuple | ||
| from collections import (namedtuple, OrderedDict) | ||
| import urllib | ||
| import xml.etree.ElementTree as ET | ||
| import voluptuous as vol | ||
|
|
||
| from homeassistant.components.media_player import ( | ||
| SUPPORT_PAUSE, SUPPORT_NEXT_TRACK, SUPPORT_PREVIOUS_TRACK, | ||
| SUPPORT_TURN_OFF, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_STEP, | ||
| SUPPORT_SELECT_SOURCE, SUPPORT_PLAY_MEDIA, MEDIA_TYPE_CHANNEL, | ||
| MediaPlayerDevice, PLATFORM_SCHEMA, SUPPORT_TURN_ON, | ||
| MEDIA_TYPE_MUSIC, SUPPORT_VOLUME_SET, SUPPORT_PLAY) | ||
| SUPPORT_SELECT_SOURCE, SUPPORT_SELECT_SOUND_MODE, | ||
| SUPPORT_PLAY_MEDIA, MEDIA_TYPE_CHANNEL, MediaPlayerDevice, | ||
| PLATFORM_SCHEMA, SUPPORT_TURN_ON, MEDIA_TYPE_MUSIC, | ||
| SUPPORT_VOLUME_SET, SUPPORT_PLAY) | ||
| from homeassistant.const import ( | ||
| CONF_HOST, STATE_OFF, STATE_PLAYING, STATE_PAUSED, | ||
| CONF_NAME, STATE_ON, CONF_ZONE, CONF_TIMEOUT) | ||
|
|
@@ -27,8 +30,19 @@ | |
| DEFAULT_NAME = None | ||
| DEFAULT_SHOW_SOURCES = False | ||
| DEFAULT_TIMEOUT = 2 | ||
| DEFAULT_SOUND_MODE = True | ||
| DEFAULT_SOUND_MODE_DICT = OrderedDict([('MUSIC', 'PLII MUSIC'), | ||
| ('MOVIE', 'PLII MOVIE'), | ||
| ('GAME', 'PLII GAME'), | ||
| ('PURE DIRECT', 'DIRECT'), | ||
| ('AUTO', 'None'), | ||
| ('DOLBY DIGITAL', 'DOLBY DIGITAL'), | ||
| ('MCH STEREO', 'MULTI CH STEREO'), | ||
| ('STEREO', 'STEREO')]) | ||
| CONF_SHOW_ALL_SOURCES = 'show_all_sources' | ||
| CONF_ZONES = 'zones' | ||
| CONF_SOUND_MODE = 'sound_mode' | ||
| CONF_SOUND_MODE_DICT = 'sound_mode_dict' | ||
| CONF_VALID_ZONES = ['Zone2', 'Zone3'] | ||
| CONF_INVALID_ZONES_ERR = 'Invalid Zone (expected Zone2 or Zone3)' | ||
| KEY_DENON_CACHE = 'denonavr_hosts' | ||
|
|
@@ -49,6 +63,9 @@ | |
| PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | ||
| vol.Optional(CONF_HOST): cv.string, | ||
| vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, | ||
| vol.Optional(CONF_SOUND_MODE, default=DEFAULT_SOUND_MODE): cv.boolean, | ||
| vol.Optional(CONF_SOUND_MODE_DICT, | ||
| default=DEFAULT_SOUND_MODE_DICT): vol.Schema({str: str}), | ||
| vol.Optional(CONF_SHOW_ALL_SOURCES, default=DEFAULT_SHOW_SOURCES): | ||
| cv.boolean, | ||
| vol.Optional(CONF_ZONES): | ||
|
|
@@ -74,6 +91,8 @@ def setup_platform(hass, config, add_devices, discovery_info=None): | |
| # Get config option for show_all_sources and timeout | ||
| show_all_sources = config.get(CONF_SHOW_ALL_SOURCES) | ||
| timeout = config.get(CONF_TIMEOUT) | ||
| sound_mode_support = config.get(CONF_SOUND_MODE) | ||
| sound_mode_dict = config.get(CONF_SOUND_MODE_DICT) | ||
|
|
||
| # Get config option for additional zones | ||
| zones = config.get(CONF_ZONES) | ||
|
|
@@ -117,7 +136,9 @@ def setup_platform(hass, config, add_devices, discovery_info=None): | |
| show_all_inputs=show_all_sources, timeout=timeout, | ||
| add_zones=add_zones) | ||
| for new_zone in new_device.zones.values(): | ||
| receivers.append(DenonDevice(new_zone)) | ||
| receivers.append(DenonDevice(new_zone, host, | ||
| sound_mode_support, | ||
| sound_mode_dict)) | ||
| cache.add(host) | ||
| _LOGGER.info("Denon receiver at host %s initialized", host) | ||
|
|
||
|
|
@@ -129,14 +150,19 @@ def setup_platform(hass, config, add_devices, discovery_info=None): | |
| class DenonDevice(MediaPlayerDevice): | ||
| """Representation of a Denon Media Player Device.""" | ||
|
|
||
| def __init__(self, receiver): | ||
| def __init__(self, receiver, host, sound_mode_support, sound_mode_dict): | ||
| """Initialize the device.""" | ||
| self._receiver = receiver | ||
| self._name = self._receiver.name | ||
| self._host = host | ||
| self._muted = self._receiver.muted | ||
| self._volume = self._receiver.volume | ||
| self._current_source = self._receiver.input_func | ||
| self._source_list = self._receiver.input_func_list | ||
| self._current_sound_mode = None | ||
| self._sound_mode_list = list(sound_mode_dict) | ||
| self._sound_mode_dict = sound_mode_dict | ||
| self._sound_mode_support = sound_mode_support | ||
| self._state = self._receiver.state | ||
| self._power = self._receiver.power | ||
| self._media_image_url = self._receiver.image_url | ||
|
|
@@ -147,6 +173,10 @@ def __init__(self, receiver): | |
| self._frequency = self._receiver.frequency | ||
| self._station = self._receiver.station | ||
|
|
||
| self._supported_features_base = SUPPORT_DENON | ||
| self._supported_features_base |= (sound_mode_support and | ||
| SUPPORT_SELECT_SOUND_MODE) | ||
|
|
||
| def update(self): | ||
| """Get the latest status information from device.""" | ||
| self._receiver.update() | ||
|
|
@@ -165,6 +195,26 @@ def update(self): | |
| self._frequency = self._receiver.frequency | ||
| self._station = self._receiver.station | ||
|
|
||
| if self._sound_mode_support: | ||
| try: | ||
| url = ('http://' + str(self._host) + | ||
| '/goform/formMainZone_MainZoneXml.xml') | ||
| xml_data = urllib.request.urlopen(url) | ||
| except urllib.error.URLError: | ||
| err = "Denon receiver failed to get sound mode, URL-Error" | ||
| _LOGGER.error(err) | ||
| return | ||
| parsed_data = ET.parse(xml_data).getroot() | ||
| sound_mode_raw = parsed_data.find('selectSurround/value') | ||
| sound_mode_raw = sound_mode_raw.text.rstrip() | ||
| try: | ||
| mode_list = list(self._sound_mode_dict.values()) | ||
| mode_index = mode_list.index(sound_mode_raw.upper()) | ||
| sound_mode = list(self._sound_mode_dict.keys())[mode_index] | ||
| self._current_sound_mode = sound_mode | ||
| except ValueError: | ||
| self._current_sound_mode = sound_mode_raw | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMHO protocol parsing should be done inside denonavr library and not here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The denonavr library does not support sound mode. I have looked at that before I started doing this code myself in Home Assistant. If anyone has the time and knowledge to implement this in denonavr library please do, you can use my code and I am willing to help. But it looked to complicated for me right now and I do not have the time at the moment. However this code does work and I have tested it. I propose we go with this for now and maybe someone has time to later implement this further in the denonavr library to get it a little neater.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you should try to get this merged to denonavr, that's the normal procedure for homeassistant libs anyway, and I think no HA developer is very eager to merge such directly. Maybe you could ask if the authors of that lib are willing to help you to get it included? I think that would be the best way to handle this. |
||
|
|
||
| @property | ||
| def name(self): | ||
| """Return the name of the device.""" | ||
|
|
@@ -197,12 +247,22 @@ def source_list(self): | |
| """Return a list of available input sources.""" | ||
| return self._source_list | ||
|
|
||
| @property | ||
| def sound_mode(self): | ||
| """Return the current sound mode.""" | ||
| return self._current_sound_mode | ||
|
|
||
| @property | ||
| def sound_mode_list(self): | ||
| """Return a list of available sound modes.""" | ||
| return self._sound_mode_list | ||
|
|
||
| @property | ||
| def supported_features(self): | ||
| """Flag media player features that are supported.""" | ||
| if self._current_source in self._receiver.netaudio_func_list: | ||
| return SUPPORT_DENON | SUPPORT_MEDIA_MODES | ||
| return SUPPORT_DENON | ||
| return self._supported_features_base | SUPPORT_MEDIA_MODES | ||
| return self._supported_features_base | ||
|
|
||
| @property | ||
| def media_content_id(self): | ||
|
|
@@ -292,6 +352,14 @@ def select_source(self, source): | |
| """Select input source.""" | ||
| return self._receiver.set_input_func(source) | ||
|
|
||
| def select_sound_mode(self, sound_mode): | ||
| """Select sound mode.""" | ||
| url = ('http://' + str(self._host) + | ||
| '/MainZone/index.put.asp?cmd0=PutSurroundMode%2F' | ||
| + sound_mode.upper().replace(" ", "+")) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above wrt denonavr lib.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See comment above |
||
| urllib.request.urlopen(url) | ||
| return sound_mode | ||
|
|
||
| def turn_on(self): | ||
| """Turn on media player.""" | ||
| if self._receiver.power_on(): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this something that needs to be configurable / statically defined, or could it be fetched from the device?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, for now it needs to be statically defined because I could not figure out how to get that data from the receiver. At least it is not in the XML file that you can request from the receiver.
However in the official phone aplication of Marantz you can also change the sound mode and their is a list of sound modes their and it nows wich sound mode is currently set. Since this phone application is generic for all Marantz Receivers (that support ethernet), their must be a way to get this information. I am pretty sure the phone application uses normal http requests just like the build in web server does.
Theirfor it is probably possible, I just do not know how.
And at the moment I do not have enough time to figure this out.
It was already fairly difficult to get the whole dictionary working as a configurable option, because the voluptuous checker was not to happy with the syntax.
So for now I think we have to settle for this, but in the future it would definetly be a greath improvement to get this working using some sort of request to the receiver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I think it is fine (for now) ho hardcode that, although I think that the proper place for this is also inside denonavr library rather than here.
I understand that it can be quite hard to decipher what is going on, but assuming you want to look into it you may want to run tcpdump on your router to capture the traffic for later analysis with wireshark.