2019-04-03 15:40:03 +00:00
|
|
|
"""Support for Yamaha Receivers."""
|
2016-03-23 22:29:21 +00:00
|
|
|
import logging
|
|
|
|
|
2018-06-07 18:25:26 +00:00
|
|
|
import requests
|
2016-09-14 04:39:03 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
from homeassistant.components.media_player import MediaPlayerDevice, PLATFORM_SCHEMA
|
2019-02-08 22:18:18 +00:00
|
|
|
from homeassistant.components.media_player.const import (
|
2019-07-31 19:25:30 +00:00
|
|
|
DOMAIN,
|
|
|
|
MEDIA_TYPE_MUSIC,
|
|
|
|
SUPPORT_NEXT_TRACK,
|
|
|
|
SUPPORT_PAUSE,
|
|
|
|
SUPPORT_PLAY,
|
|
|
|
SUPPORT_PLAY_MEDIA,
|
|
|
|
SUPPORT_PREVIOUS_TRACK,
|
|
|
|
SUPPORT_SELECT_SOURCE,
|
|
|
|
SUPPORT_STOP,
|
|
|
|
SUPPORT_TURN_OFF,
|
|
|
|
SUPPORT_TURN_ON,
|
|
|
|
SUPPORT_VOLUME_MUTE,
|
|
|
|
SUPPORT_VOLUME_SET,
|
|
|
|
SUPPORT_SELECT_SOUND_MODE,
|
|
|
|
)
|
2018-10-10 12:07:33 +00:00
|
|
|
|
2018-06-07 18:25:26 +00:00
|
|
|
from homeassistant.const import (
|
2019-07-31 19:25:30 +00:00
|
|
|
ATTR_ENTITY_ID,
|
|
|
|
CONF_HOST,
|
|
|
|
CONF_NAME,
|
|
|
|
STATE_IDLE,
|
|
|
|
STATE_OFF,
|
|
|
|
STATE_ON,
|
|
|
|
STATE_PLAYING,
|
|
|
|
)
|
2016-09-14 04:39:03 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
2016-04-14 04:13:12 +00:00
|
|
|
|
2016-03-23 22:29:21 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
ATTR_ENABLED = "enabled"
|
|
|
|
ATTR_PORT = "port"
|
2016-10-22 07:11:50 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
CONF_SOURCE_IGNORE = "source_ignore"
|
|
|
|
CONF_SOURCE_NAMES = "source_names"
|
|
|
|
CONF_ZONE_IGNORE = "zone_ignore"
|
|
|
|
CONF_ZONE_NAMES = "zone_names"
|
2016-03-23 22:29:21 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
DATA_YAMAHA = "yamaha_known_receivers"
|
2018-06-07 18:25:26 +00:00
|
|
|
DEFAULT_NAME = "Yamaha Receiver"
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
MEDIA_PLAYER_SCHEMA = vol.Schema({ATTR_ENTITY_ID: cv.comp_entity_ids})
|
2019-07-24 00:54:59 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
ENABLE_OUTPUT_SCHEMA = MEDIA_PLAYER_SCHEMA.extend(
|
|
|
|
{vol.Required(ATTR_ENABLED): cv.boolean, vol.Required(ATTR_PORT): cv.string}
|
|
|
|
)
|
2018-06-07 18:25:26 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
SERVICE_ENABLE_OUTPUT = "yamaha_enable_output"
|
2018-06-07 18:25:26 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
SUPPORT_YAMAHA = (
|
|
|
|
SUPPORT_VOLUME_SET
|
|
|
|
| SUPPORT_VOLUME_MUTE
|
|
|
|
| SUPPORT_TURN_ON
|
|
|
|
| SUPPORT_TURN_OFF
|
|
|
|
| SUPPORT_SELECT_SOURCE
|
|
|
|
| SUPPORT_PLAY
|
2018-09-01 21:34:38 +00:00
|
|
|
| SUPPORT_SELECT_SOUND_MODE
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|
|
|
{
|
|
|
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
|
|
vol.Optional(CONF_HOST): cv.string,
|
|
|
|
vol.Optional(CONF_SOURCE_IGNORE, default=[]): vol.All(
|
|
|
|
cv.ensure_list, [cv.string]
|
|
|
|
),
|
|
|
|
vol.Optional(CONF_ZONE_IGNORE, default=[]): vol.All(
|
|
|
|
cv.ensure_list, [cv.string]
|
|
|
|
),
|
|
|
|
vol.Optional(CONF_SOURCE_NAMES, default={}): {cv.string: cv.string},
|
|
|
|
vol.Optional(CONF_ZONE_NAMES, default={}): {cv.string: cv.string},
|
|
|
|
}
|
|
|
|
)
|
2016-09-14 04:39:03 +00:00
|
|
|
|
2016-03-23 22:29:21 +00:00
|
|
|
|
2018-08-24 14:37:30 +00:00
|
|
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
2017-05-02 16:18:47 +00:00
|
|
|
"""Set up the Yamaha platform."""
|
2016-03-23 22:29:21 +00:00
|
|
|
import rxv
|
2019-07-31 19:25:30 +00:00
|
|
|
|
2018-01-17 18:34:21 +00:00
|
|
|
# Keep track of configured receivers so that we don't end up
|
2016-11-11 04:44:38 +00:00
|
|
|
# discovering a receiver dynamically that we have static config
|
2018-02-13 22:24:03 +00:00
|
|
|
# for. Map each device from its zone_id to an instance since
|
2018-01-17 18:34:21 +00:00
|
|
|
# YamahaDevice is not hashable (thus not possible to add to a set).
|
|
|
|
if hass.data.get(DATA_YAMAHA) is None:
|
|
|
|
hass.data[DATA_YAMAHA] = {}
|
2016-04-28 10:03:24 +00:00
|
|
|
|
2016-09-14 04:39:03 +00:00
|
|
|
name = config.get(CONF_NAME)
|
2016-09-21 05:26:43 +00:00
|
|
|
host = config.get(CONF_HOST)
|
2016-09-14 04:39:03 +00:00
|
|
|
source_ignore = config.get(CONF_SOURCE_IGNORE)
|
|
|
|
source_names = config.get(CONF_SOURCE_NAMES)
|
2016-10-29 02:18:31 +00:00
|
|
|
zone_ignore = config.get(CONF_ZONE_IGNORE)
|
2018-01-03 18:25:16 +00:00
|
|
|
zone_names = config.get(CONF_ZONE_NAMES)
|
2016-04-28 10:03:24 +00:00
|
|
|
|
2016-10-27 06:46:44 +00:00
|
|
|
if discovery_info is not None:
|
2019-07-31 19:25:30 +00:00
|
|
|
name = discovery_info.get("name")
|
|
|
|
model = discovery_info.get("model_name")
|
|
|
|
ctrl_url = discovery_info.get("control_url")
|
|
|
|
desc_url = discovery_info.get("description_url")
|
2016-10-27 06:46:44 +00:00
|
|
|
receivers = rxv.RXV(
|
2019-07-31 19:25:30 +00:00
|
|
|
ctrl_url, model_name=model, friendly_name=name, unit_desc_url=desc_url
|
|
|
|
).zone_controllers()
|
2018-06-07 18:25:26 +00:00
|
|
|
_LOGGER.debug("Receivers: %s", receivers)
|
2016-11-11 04:44:38 +00:00
|
|
|
# when we are dynamically discovered config is empty
|
|
|
|
zone_ignore = []
|
2016-10-27 06:46:44 +00:00
|
|
|
elif host is None:
|
2016-10-19 01:04:15 +00:00
|
|
|
receivers = []
|
|
|
|
for recv in rxv.find():
|
|
|
|
receivers.extend(recv.zone_controllers())
|
2016-09-21 05:26:43 +00:00
|
|
|
else:
|
2016-10-19 01:04:15 +00:00
|
|
|
ctrl_url = "http://{}:80/YamahaRemoteControl/ctrl".format(host)
|
|
|
|
receivers = rxv.RXV(ctrl_url, name).zone_controllers()
|
2016-09-21 05:26:43 +00:00
|
|
|
|
2018-01-17 18:34:21 +00:00
|
|
|
devices = []
|
2016-10-29 02:18:31 +00:00
|
|
|
for receiver in receivers:
|
2018-01-17 18:34:21 +00:00
|
|
|
if receiver.zone in zone_ignore:
|
|
|
|
continue
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
device = YamahaDevice(name, receiver, source_ignore, source_names, zone_names)
|
2018-01-17 18:34:21 +00:00
|
|
|
|
|
|
|
# Only add device if it's not already added
|
2018-02-13 22:24:03 +00:00
|
|
|
if device.zone_id not in hass.data[DATA_YAMAHA]:
|
|
|
|
hass.data[DATA_YAMAHA][device.zone_id] = device
|
2018-01-17 18:34:21 +00:00
|
|
|
devices.append(device)
|
|
|
|
else:
|
2018-06-07 18:25:26 +00:00
|
|
|
_LOGGER.debug("Ignoring duplicate receiver: %s", name)
|
2018-01-17 18:34:21 +00:00
|
|
|
|
|
|
|
def service_handler(service):
|
|
|
|
"""Handle for services."""
|
|
|
|
entity_ids = service.data.get(ATTR_ENTITY_ID)
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
devices = [
|
|
|
|
device
|
|
|
|
for device in hass.data[DATA_YAMAHA].values()
|
|
|
|
if not entity_ids or device.entity_id in entity_ids
|
|
|
|
]
|
2018-01-17 18:34:21 +00:00
|
|
|
|
|
|
|
for device in devices:
|
|
|
|
port = service.data[ATTR_PORT]
|
|
|
|
enabled = service.data[ATTR_ENABLED]
|
|
|
|
|
|
|
|
device.enable_output(port, enabled)
|
|
|
|
device.schedule_update_ha_state(True)
|
|
|
|
|
|
|
|
hass.services.register(
|
2019-07-31 19:25:30 +00:00
|
|
|
DOMAIN, SERVICE_ENABLE_OUTPUT, service_handler, schema=ENABLE_OUTPUT_SCHEMA
|
|
|
|
)
|
2018-01-17 18:34:21 +00:00
|
|
|
|
2018-08-24 14:37:30 +00:00
|
|
|
add_entities(devices)
|
2016-03-23 22:29:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
class YamahaDevice(MediaPlayerDevice):
|
|
|
|
"""Representation of a Yamaha device."""
|
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
def __init__(self, name, receiver, source_ignore, source_names, zone_names):
|
2016-03-23 22:29:21 +00:00
|
|
|
"""Initialize the Yamaha Receiver."""
|
2018-01-17 18:34:21 +00:00
|
|
|
self.receiver = receiver
|
2016-03-23 22:29:21 +00:00
|
|
|
self._muted = False
|
|
|
|
self._volume = 0
|
|
|
|
self._pwstate = STATE_OFF
|
2016-04-14 04:13:12 +00:00
|
|
|
self._current_source = None
|
2018-09-01 21:34:38 +00:00
|
|
|
self._sound_mode = None
|
|
|
|
self._sound_mode_list = None
|
2016-04-14 04:13:12 +00:00
|
|
|
self._source_list = None
|
2016-10-27 06:46:44 +00:00
|
|
|
self._source_ignore = source_ignore or []
|
|
|
|
self._source_names = source_names or {}
|
2018-01-03 18:25:16 +00:00
|
|
|
self._zone_names = zone_names or {}
|
2016-04-28 10:03:24 +00:00
|
|
|
self._reverse_mapping = None
|
2017-01-18 05:53:03 +00:00
|
|
|
self._playback_support = None
|
2016-10-22 07:11:50 +00:00
|
|
|
self._is_playback_supported = False
|
|
|
|
self._play_status = None
|
2016-03-23 22:29:21 +00:00
|
|
|
self._name = name
|
2016-10-19 01:04:15 +00:00
|
|
|
self._zone = receiver.zone
|
2016-03-23 22:29:21 +00:00
|
|
|
|
|
|
|
def update(self):
|
|
|
|
"""Get the latest details from the device."""
|
2018-06-07 18:25:26 +00:00
|
|
|
try:
|
|
|
|
self._play_status = self.receiver.play_status()
|
|
|
|
except requests.exceptions.ConnectionError:
|
|
|
|
_LOGGER.info("Receiver is offline: %s", self._name)
|
|
|
|
return
|
|
|
|
|
2018-01-17 18:34:21 +00:00
|
|
|
if self.receiver.on:
|
2016-10-22 07:11:50 +00:00
|
|
|
if self._play_status is None:
|
|
|
|
self._pwstate = STATE_ON
|
|
|
|
elif self._play_status.playing:
|
|
|
|
self._pwstate = STATE_PLAYING
|
|
|
|
else:
|
|
|
|
self._pwstate = STATE_IDLE
|
2016-03-23 22:29:21 +00:00
|
|
|
else:
|
|
|
|
self._pwstate = STATE_OFF
|
2016-10-22 07:11:50 +00:00
|
|
|
|
2018-01-17 18:34:21 +00:00
|
|
|
self._muted = self.receiver.mute
|
|
|
|
self._volume = (self.receiver.volume / 100) + 1
|
2016-04-28 10:03:24 +00:00
|
|
|
|
|
|
|
if self.source_list is None:
|
|
|
|
self.build_source_list()
|
|
|
|
|
2018-01-17 18:34:21 +00:00
|
|
|
current_source = self.receiver.input
|
2019-07-31 19:25:30 +00:00
|
|
|
self._current_source = self._source_names.get(current_source, current_source)
|
2018-01-17 18:34:21 +00:00
|
|
|
self._playback_support = self.receiver.get_playback_support()
|
|
|
|
self._is_playback_supported = self.receiver.is_playback_supported(
|
2019-07-31 19:25:30 +00:00
|
|
|
self._current_source
|
|
|
|
)
|
2018-11-01 20:26:53 +00:00
|
|
|
surround_programs = self.receiver.surround_programs()
|
|
|
|
if surround_programs:
|
2018-10-10 12:07:33 +00:00
|
|
|
self._sound_mode = self.receiver.surround_program
|
2018-11-01 20:26:53 +00:00
|
|
|
self._sound_mode_list = surround_programs
|
2018-10-10 12:07:33 +00:00
|
|
|
else:
|
|
|
|
self._sound_mode = None
|
|
|
|
self._sound_mode_list = None
|
2016-04-28 10:03:24 +00:00
|
|
|
|
|
|
|
def build_source_list(self):
|
|
|
|
"""Build the source list."""
|
2019-07-31 19:25:30 +00:00
|
|
|
self._reverse_mapping = {
|
|
|
|
alias: source for source, alias in self._source_names.items()
|
|
|
|
}
|
2016-04-28 10:03:24 +00:00
|
|
|
|
|
|
|
self._source_list = sorted(
|
2019-07-31 19:25:30 +00:00
|
|
|
self._source_names.get(source, source)
|
|
|
|
for source in self.receiver.inputs()
|
|
|
|
if source not in self._source_ignore
|
|
|
|
)
|
2016-03-23 22:29:21 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
"""Return the name of the device."""
|
2016-10-19 01:04:15 +00:00
|
|
|
name = self._name
|
2018-01-03 18:25:16 +00:00
|
|
|
zone_name = self._zone_names.get(self._zone, self._zone)
|
|
|
|
if zone_name != "Main_Zone":
|
2016-10-19 01:04:15 +00:00
|
|
|
# Zone will be one of Main_Zone, Zone_2, Zone_3
|
2019-07-31 19:25:30 +00:00
|
|
|
name += " " + zone_name.replace("_", " ")
|
2016-10-19 01:04:15 +00:00
|
|
|
return name
|
2016-03-23 22:29:21 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def state(self):
|
|
|
|
"""Return the state of the device."""
|
|
|
|
return self._pwstate
|
|
|
|
|
|
|
|
@property
|
|
|
|
def volume_level(self):
|
|
|
|
"""Volume level of the media player (0..1)."""
|
|
|
|
return self._volume
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_volume_muted(self):
|
|
|
|
"""Boolean if volume is currently muted."""
|
|
|
|
return self._muted
|
|
|
|
|
2016-04-14 04:13:12 +00:00
|
|
|
@property
|
|
|
|
def source(self):
|
|
|
|
"""Return the current input source."""
|
|
|
|
return self._current_source
|
|
|
|
|
2018-09-01 21:34:38 +00:00
|
|
|
@property
|
|
|
|
def sound_mode(self):
|
|
|
|
"""Return the current sound mode."""
|
|
|
|
return self._sound_mode
|
|
|
|
|
|
|
|
@property
|
|
|
|
def sound_mode_list(self):
|
|
|
|
"""Return the current sound mode."""
|
|
|
|
return self._sound_mode_list
|
|
|
|
|
2016-04-14 04:13:12 +00:00
|
|
|
@property
|
|
|
|
def source_list(self):
|
|
|
|
"""List of available input sources."""
|
|
|
|
return self._source_list
|
|
|
|
|
2018-02-13 22:24:03 +00:00
|
|
|
@property
|
|
|
|
def zone_id(self):
|
2018-05-13 10:09:28 +00:00
|
|
|
"""Return a zone_id to ensure 1 media player per zone."""
|
2019-07-31 19:25:30 +00:00
|
|
|
return "{0}:{1}".format(self.receiver.ctrl_url, self._zone)
|
2018-02-13 22:24:03 +00:00
|
|
|
|
2016-03-23 22:29:21 +00:00
|
|
|
@property
|
2017-02-08 04:42:45 +00:00
|
|
|
def supported_features(self):
|
|
|
|
"""Flag media player features that are supported."""
|
|
|
|
supported_features = SUPPORT_YAMAHA
|
2016-11-16 05:56:40 +00:00
|
|
|
|
2017-01-18 05:53:03 +00:00
|
|
|
supports = self._playback_support
|
2018-06-07 18:25:26 +00:00
|
|
|
mapping = {
|
2019-07-31 19:25:30 +00:00
|
|
|
"play": (SUPPORT_PLAY | SUPPORT_PLAY_MEDIA),
|
|
|
|
"pause": SUPPORT_PAUSE,
|
|
|
|
"stop": SUPPORT_STOP,
|
|
|
|
"skip_f": SUPPORT_NEXT_TRACK,
|
|
|
|
"skip_r": SUPPORT_PREVIOUS_TRACK,
|
2018-06-07 18:25:26 +00:00
|
|
|
}
|
2016-11-16 05:56:40 +00:00
|
|
|
for attr, feature in mapping.items():
|
|
|
|
if getattr(supports, attr, False):
|
2017-02-08 04:42:45 +00:00
|
|
|
supported_features |= feature
|
|
|
|
return supported_features
|
2016-03-23 22:29:21 +00:00
|
|
|
|
|
|
|
def turn_off(self):
|
|
|
|
"""Turn off media player."""
|
2018-01-17 18:34:21 +00:00
|
|
|
self.receiver.on = False
|
2016-03-23 22:29:21 +00:00
|
|
|
|
|
|
|
def set_volume_level(self, volume):
|
|
|
|
"""Set volume level, range 0..1."""
|
2016-04-28 10:03:24 +00:00
|
|
|
receiver_vol = 100 - (volume * 100)
|
2016-03-23 22:29:21 +00:00
|
|
|
negative_receiver_vol = -receiver_vol
|
2018-01-17 18:34:21 +00:00
|
|
|
self.receiver.volume = negative_receiver_vol
|
2016-03-23 22:29:21 +00:00
|
|
|
|
|
|
|
def mute_volume(self, mute):
|
|
|
|
"""Mute (true) or unmute (false) media player."""
|
2018-01-17 18:34:21 +00:00
|
|
|
self.receiver.mute = mute
|
2016-03-23 22:29:21 +00:00
|
|
|
|
|
|
|
def turn_on(self):
|
|
|
|
"""Turn the media player on."""
|
2018-01-17 18:34:21 +00:00
|
|
|
self.receiver.on = True
|
|
|
|
self._volume = (self.receiver.volume / 100) + 1
|
2016-04-14 04:13:12 +00:00
|
|
|
|
2016-10-22 07:11:50 +00:00
|
|
|
def media_play(self):
|
2017-09-23 15:15:46 +00:00
|
|
|
"""Send play command."""
|
2018-01-17 18:34:21 +00:00
|
|
|
self._call_playback_function(self.receiver.play, "play")
|
2016-10-22 07:11:50 +00:00
|
|
|
|
|
|
|
def media_pause(self):
|
|
|
|
"""Send pause command."""
|
2018-01-17 18:34:21 +00:00
|
|
|
self._call_playback_function(self.receiver.pause, "pause")
|
2016-10-22 07:11:50 +00:00
|
|
|
|
|
|
|
def media_stop(self):
|
|
|
|
"""Send stop command."""
|
2018-01-17 18:34:21 +00:00
|
|
|
self._call_playback_function(self.receiver.stop, "stop")
|
2016-10-22 07:11:50 +00:00
|
|
|
|
|
|
|
def media_previous_track(self):
|
|
|
|
"""Send previous track command."""
|
2018-01-17 18:34:21 +00:00
|
|
|
self._call_playback_function(self.receiver.previous, "previous track")
|
2016-10-22 07:11:50 +00:00
|
|
|
|
|
|
|
def media_next_track(self):
|
|
|
|
"""Send next track command."""
|
2018-01-17 18:34:21 +00:00
|
|
|
self._call_playback_function(self.receiver.next, "next track")
|
2016-10-22 07:11:50 +00:00
|
|
|
|
|
|
|
def _call_playback_function(self, function, function_text):
|
|
|
|
import rxv
|
2019-07-31 19:25:30 +00:00
|
|
|
|
2016-10-22 07:11:50 +00:00
|
|
|
try:
|
|
|
|
function()
|
|
|
|
except rxv.exceptions.ResponseException:
|
2019-07-31 19:25:30 +00:00
|
|
|
_LOGGER.warning("Failed to execute %s on %s", function_text, self._name)
|
2016-10-22 07:11:50 +00:00
|
|
|
|
2016-04-14 04:13:12 +00:00
|
|
|
def select_source(self, source):
|
|
|
|
"""Select input source."""
|
2018-01-17 18:34:21 +00:00
|
|
|
self.receiver.input = self._reverse_mapping.get(source, source)
|
2016-10-19 01:04:15 +00:00
|
|
|
|
|
|
|
def play_media(self, media_type, media_id, **kwargs):
|
|
|
|
"""Play media from an ID.
|
|
|
|
|
|
|
|
This exposes a pass through for various input sources in the
|
|
|
|
Yamaha to direct play certain kinds of media. media_type is
|
|
|
|
treated as the input type that we are setting, and media id is
|
|
|
|
specific to it.
|
2017-10-30 20:38:52 +00:00
|
|
|
|
|
|
|
For the NET RADIO mediatype the format for ``media_id`` is a
|
|
|
|
"path" in your vtuner hierarchy. For instance:
|
|
|
|
``Bookmarks>Internet>Radio Paradise``. The separators are
|
|
|
|
``>`` and the parts of this are navigated by name behind the
|
|
|
|
scenes. There is a looping construct built into the yamaha
|
|
|
|
library to do this with a fallback timeout if the vtuner
|
|
|
|
service is unresponsive.
|
|
|
|
|
|
|
|
NOTE: this might take a while, because the only API interface
|
|
|
|
for setting the net radio station emulates button pressing and
|
2018-01-29 22:37:19 +00:00
|
|
|
navigating through the net radio menu hierarchy. And each sub
|
2017-10-30 20:38:52 +00:00
|
|
|
menu must be fetched by the receiver from the vtuner service.
|
|
|
|
|
2016-10-19 01:04:15 +00:00
|
|
|
"""
|
|
|
|
if media_type == "NET RADIO":
|
2018-01-17 18:34:21 +00:00
|
|
|
self.receiver.net_radio(media_id)
|
|
|
|
|
|
|
|
def enable_output(self, port, enabled):
|
|
|
|
"""Enable or disable an output port.."""
|
|
|
|
self.receiver.enable_output(port, enabled)
|
2016-10-19 01:04:15 +00:00
|
|
|
|
2018-09-01 21:34:38 +00:00
|
|
|
def select_sound_mode(self, sound_mode):
|
|
|
|
"""Set Sound Mode for Receiver.."""
|
|
|
|
self.receiver.surround_program = sound_mode
|
|
|
|
|
2016-10-22 07:11:50 +00:00
|
|
|
@property
|
|
|
|
def media_artist(self):
|
|
|
|
"""Artist of current playing media."""
|
|
|
|
if self._play_status is not None:
|
|
|
|
return self._play_status.artist
|
|
|
|
|
|
|
|
@property
|
|
|
|
def media_album_name(self):
|
|
|
|
"""Album of current playing media."""
|
|
|
|
if self._play_status is not None:
|
|
|
|
return self._play_status.album
|
|
|
|
|
2016-10-19 01:04:15 +00:00
|
|
|
@property
|
|
|
|
def media_content_type(self):
|
2016-10-22 07:11:50 +00:00
|
|
|
"""Content type of current playing media."""
|
|
|
|
# Loose assumption that if playback is supported, we are playing music
|
|
|
|
if self._is_playback_supported:
|
2016-10-19 01:04:15 +00:00
|
|
|
return MEDIA_TYPE_MUSIC
|
2016-10-22 07:11:50 +00:00
|
|
|
return None
|
2016-10-19 01:04:15 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def media_title(self):
|
2016-10-22 07:11:50 +00:00
|
|
|
"""Artist of current playing media."""
|
|
|
|
if self._play_status is not None:
|
|
|
|
song = self._play_status.song
|
|
|
|
station = self._play_status.station
|
|
|
|
|
|
|
|
# If both song and station is available, print both, otherwise
|
|
|
|
# just the one we have.
|
|
|
|
if song and station:
|
2019-07-31 19:25:30 +00:00
|
|
|
return "{}: {}".format(station, song)
|
2017-07-06 06:30:01 +00:00
|
|
|
|
|
|
|
return song or station
|