2016-03-27 18:41:52 +00:00
|
|
|
"""
|
|
|
|
Support for Onkyo Receivers.
|
|
|
|
|
|
|
|
For more details about this platform, please refer to the documentation at
|
|
|
|
https://home-assistant.io/components/media_player.onkyo/
|
|
|
|
"""
|
|
|
|
import logging
|
|
|
|
|
2018-01-29 08:24:08 +00:00
|
|
|
# pylint: disable=unused-import
|
|
|
|
from typing import List # noqa: F401
|
|
|
|
|
2016-09-05 16:01:50 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
2016-03-27 18:41:52 +00:00
|
|
|
from homeassistant.components.media_player import (
|
|
|
|
SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET,
|
2017-01-09 00:09:30 +00:00
|
|
|
SUPPORT_SELECT_SOURCE, SUPPORT_PLAY, MediaPlayerDevice, PLATFORM_SCHEMA)
|
2016-09-05 16:01:50 +00:00
|
|
|
from homeassistant.const import (STATE_OFF, STATE_ON, CONF_HOST, CONF_NAME)
|
|
|
|
import homeassistant.helpers.config_validation as cv
|
2016-03-27 18:41:52 +00:00
|
|
|
|
2017-08-21 09:25:34 +00:00
|
|
|
REQUIREMENTS = ['onkyo-eiscp==1.2.4']
|
2016-09-05 16:01:50 +00:00
|
|
|
|
2016-03-27 18:41:52 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2016-09-05 16:01:50 +00:00
|
|
|
CONF_SOURCES = 'sources'
|
|
|
|
|
|
|
|
DEFAULT_NAME = 'Onkyo Receiver'
|
|
|
|
|
2016-03-27 18:41:52 +00:00
|
|
|
SUPPORT_ONKYO = SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
|
2017-01-09 00:09:30 +00:00
|
|
|
SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_SELECT_SOURCE | SUPPORT_PLAY
|
2016-09-05 16:01:50 +00:00
|
|
|
|
2016-09-15 01:21:01 +00:00
|
|
|
KNOWN_HOSTS = [] # type: List[str]
|
2016-09-05 16:01:50 +00:00
|
|
|
DEFAULT_SOURCES = {'tv': 'TV', 'bd': 'Bluray', 'game': 'Game', 'aux1': 'Aux1',
|
|
|
|
'video1': 'Video 1', 'video2': 'Video 2',
|
|
|
|
'video3': 'Video 3', 'video4': 'Video 4',
|
|
|
|
'video5': 'Video 5', 'video6': 'Video 6',
|
|
|
|
'video7': 'Video 7'}
|
|
|
|
|
|
|
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
2016-10-27 08:33:35 +00:00
|
|
|
vol.Optional(CONF_HOST): cv.string,
|
2016-09-05 16:01:50 +00:00
|
|
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
|
|
|
vol.Optional(CONF_SOURCES, default=DEFAULT_SOURCES):
|
|
|
|
{cv.string: cv.string},
|
|
|
|
})
|
2016-03-27 18:41:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
def setup_platform(hass, config, add_devices, discovery_info=None):
|
2017-05-02 16:18:47 +00:00
|
|
|
"""Set up the Onkyo platform."""
|
2016-05-21 17:04:08 +00:00
|
|
|
import eiscp
|
2016-03-27 18:41:52 +00:00
|
|
|
from eiscp import eISCP
|
2016-09-05 16:01:50 +00:00
|
|
|
|
|
|
|
host = config.get(CONF_HOST)
|
2016-05-21 17:04:08 +00:00
|
|
|
hosts = []
|
|
|
|
|
2016-09-05 16:01:50 +00:00
|
|
|
if CONF_HOST in config and host not in KNOWN_HOSTS:
|
2016-05-21 17:04:08 +00:00
|
|
|
try:
|
2017-05-02 16:18:47 +00:00
|
|
|
hosts.append(OnkyoDevice(
|
|
|
|
eiscp.eISCP(host), config.get(CONF_SOURCES),
|
|
|
|
name=config.get(CONF_NAME)))
|
2016-09-05 16:01:50 +00:00
|
|
|
KNOWN_HOSTS.append(host)
|
2016-05-21 17:04:08 +00:00
|
|
|
except OSError:
|
2017-05-02 16:18:47 +00:00
|
|
|
_LOGGER.error("Unable to connect to receiver at %s", host)
|
2016-05-21 17:04:08 +00:00
|
|
|
else:
|
|
|
|
for receiver in eISCP.discover():
|
|
|
|
if receiver.host not in KNOWN_HOSTS:
|
2016-09-05 16:01:50 +00:00
|
|
|
hosts.append(OnkyoDevice(receiver, config.get(CONF_SOURCES)))
|
2016-05-21 17:04:08 +00:00
|
|
|
KNOWN_HOSTS.append(receiver.host)
|
2017-08-08 18:21:33 +00:00
|
|
|
add_devices(hosts, True)
|
2016-05-21 17:04:08 +00:00
|
|
|
|
|
|
|
|
2016-03-27 18:41:52 +00:00
|
|
|
class OnkyoDevice(MediaPlayerDevice):
|
2016-09-05 16:01:50 +00:00
|
|
|
"""Representation of an Onkyo device."""
|
2016-03-27 18:41:52 +00:00
|
|
|
|
2016-05-21 17:04:08 +00:00
|
|
|
def __init__(self, receiver, sources, name=None):
|
2016-03-27 18:41:52 +00:00
|
|
|
"""Initialize the Onkyo Receiver."""
|
|
|
|
self._receiver = receiver
|
|
|
|
self._muted = False
|
|
|
|
self._volume = 0
|
|
|
|
self._pwstate = STATE_OFF
|
2016-05-21 17:04:08 +00:00
|
|
|
self._name = name or '{}_{}'.format(
|
2016-03-27 18:41:52 +00:00
|
|
|
receiver.info['model_name'], receiver.info['identifier'])
|
|
|
|
self._current_source = None
|
2016-05-21 17:04:08 +00:00
|
|
|
self._source_list = list(sources.values())
|
|
|
|
self._source_mapping = sources
|
|
|
|
self._reverse_mapping = {value: key for key, value in sources.items()}
|
2016-03-27 18:41:52 +00:00
|
|
|
|
2016-09-15 01:21:01 +00:00
|
|
|
def command(self, command):
|
|
|
|
"""Run an eiscp command and catch connection errors."""
|
|
|
|
try:
|
|
|
|
result = self._receiver.command(command)
|
|
|
|
except (ValueError, OSError, AttributeError, AssertionError):
|
|
|
|
if self._receiver.command_socket:
|
|
|
|
self._receiver.command_socket = None
|
2017-05-02 16:18:47 +00:00
|
|
|
_LOGGER.info("Resetting connection to %s", self._name)
|
2016-09-15 01:21:01 +00:00
|
|
|
else:
|
2017-05-02 16:18:47 +00:00
|
|
|
_LOGGER.info("%s is disconnected. Attempting to reconnect",
|
2016-09-15 01:21:01 +00:00
|
|
|
self._name)
|
|
|
|
return False
|
|
|
|
return result
|
|
|
|
|
2016-03-27 18:41:52 +00:00
|
|
|
def update(self):
|
|
|
|
"""Get the latest details from the device."""
|
2016-09-15 01:21:01 +00:00
|
|
|
status = self.command('system-power query')
|
|
|
|
if not status:
|
|
|
|
return
|
2016-03-27 18:41:52 +00:00
|
|
|
if status[1] == 'on':
|
|
|
|
self._pwstate = STATE_ON
|
|
|
|
else:
|
|
|
|
self._pwstate = STATE_OFF
|
|
|
|
return
|
2016-09-15 01:21:01 +00:00
|
|
|
volume_raw = self.command('volume query')
|
|
|
|
mute_raw = self.command('audio-muting query')
|
|
|
|
current_source_raw = self.command('input-selector query')
|
|
|
|
if not (volume_raw and mute_raw and current_source_raw):
|
|
|
|
return
|
2017-01-08 22:59:26 +00:00
|
|
|
|
|
|
|
# eiscp can return string or tuple. Make everything tuples.
|
|
|
|
if isinstance(current_source_raw[1], str):
|
|
|
|
current_source_tuples = \
|
|
|
|
(current_source_raw[0], (current_source_raw[1],))
|
|
|
|
else:
|
|
|
|
current_source_tuples = current_source_raw
|
|
|
|
|
|
|
|
for source in current_source_tuples[1]:
|
2016-05-21 17:04:08 +00:00
|
|
|
if source in self._source_mapping:
|
|
|
|
self._current_source = self._source_mapping[source]
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
self._current_source = '_'.join(
|
2017-01-08 22:59:26 +00:00
|
|
|
[i for i in current_source_tuples[1]])
|
2016-03-27 18:41:52 +00:00
|
|
|
self._muted = bool(mute_raw[1] == 'on')
|
2017-04-03 07:35:36 +00:00
|
|
|
self._volume = volume_raw[1] / 80.0
|
2016-03-27 18:41:52 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
"""Return the name of the device."""
|
|
|
|
return self._name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def state(self):
|
|
|
|
"""Return the state of the device."""
|
|
|
|
return self._pwstate
|
|
|
|
|
|
|
|
@property
|
|
|
|
def volume_level(self):
|
2017-05-02 16:18:47 +00:00
|
|
|
"""Return the volume level of the media player (0..1)."""
|
2016-03-27 18:41:52 +00:00
|
|
|
return self._volume
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_volume_muted(self):
|
|
|
|
"""Boolean if volume is currently muted."""
|
|
|
|
return self._muted
|
|
|
|
|
|
|
|
@property
|
2017-02-08 04:42:45 +00:00
|
|
|
def supported_features(self):
|
|
|
|
"""Flag media player features that are supported."""
|
2016-03-27 18:41:52 +00:00
|
|
|
return SUPPORT_ONKYO
|
|
|
|
|
|
|
|
@property
|
|
|
|
def source(self):
|
2017-05-02 16:18:47 +00:00
|
|
|
"""Return the current input source of the device."""
|
2016-03-27 18:41:52 +00:00
|
|
|
return self._current_source
|
|
|
|
|
2016-05-21 17:04:08 +00:00
|
|
|
@property
|
|
|
|
def source_list(self):
|
|
|
|
"""List of available input sources."""
|
|
|
|
return self._source_list
|
|
|
|
|
2016-03-27 18:41:52 +00:00
|
|
|
def turn_off(self):
|
|
|
|
"""Turn off media player."""
|
2016-09-15 01:21:01 +00:00
|
|
|
self.command('system-power standby')
|
2016-03-27 18:41:52 +00:00
|
|
|
|
|
|
|
def set_volume_level(self, volume):
|
|
|
|
"""Set volume level, input is range 0..1. Onkyo ranges from 1-80."""
|
2016-09-15 01:21:01 +00:00
|
|
|
self.command('volume {}'.format(int(volume*80)))
|
2016-03-27 18:41:52 +00:00
|
|
|
|
|
|
|
def mute_volume(self, mute):
|
|
|
|
"""Mute (true) or unmute (false) media player."""
|
|
|
|
if mute:
|
2016-09-15 01:21:01 +00:00
|
|
|
self.command('audio-muting on')
|
2016-03-27 18:41:52 +00:00
|
|
|
else:
|
2016-09-15 01:21:01 +00:00
|
|
|
self.command('audio-muting off')
|
2016-03-27 18:41:52 +00:00
|
|
|
|
|
|
|
def turn_on(self):
|
|
|
|
"""Turn the media player on."""
|
2016-12-08 05:46:42 +00:00
|
|
|
self.command('system-power on')
|
2016-03-27 18:41:52 +00:00
|
|
|
|
|
|
|
def select_source(self, source):
|
|
|
|
"""Set the input source."""
|
2016-05-21 17:04:08 +00:00
|
|
|
if source in self._source_list:
|
|
|
|
source = self._reverse_mapping[source]
|
2016-09-15 01:21:01 +00:00
|
|
|
self.command('input-selector {}'.format(source))
|