mirror of https://github.com/home-assistant/core
Add new media_player platform: Volumio Media Player (#6556)
* Add new media_player platform: Volumio Media Player Volumio media player is a rpi music player, this platfor adds http based control of the player. * Modify mute command to accept boolean * Adjust mute call to reset volume after unmute Remove references to volimi"a" * Use yield from calls in mute and volume calls Trying to speed up the indication of mute and volume level changes in UI, but doesn't seem to do much. * Adjust async_add_devices call
This commit is contained in:
parent
b5149dfba6
commit
9778000e9a
|
@ -271,6 +271,7 @@ omit =
|
|||
homeassistant/components/media_player/sonos.py
|
||||
homeassistant/components/media_player/squeezebox.py
|
||||
homeassistant/components/media_player/vlc.py
|
||||
homeassistant/components/media_player/volumio.py
|
||||
homeassistant/components/media_player/yamaha.py
|
||||
homeassistant/components/notify/aws_lambda.py
|
||||
homeassistant/components/notify/aws_sns.py
|
||||
|
|
|
@ -0,0 +1,237 @@
|
|||
"""
|
||||
Volumio Platform.
|
||||
|
||||
The volumio platform allows you to control a Volumio media player
|
||||
from Home Assistant.
|
||||
|
||||
|
||||
To add a Volumio player to your installation, add the following to
|
||||
your configuration.yaml file.
|
||||
|
||||
# Example configuration.yaml entry
|
||||
media_player:
|
||||
- platform: volumio
|
||||
name: 'Volumio Home Audio'
|
||||
host: homeaudio.local
|
||||
port: 3000
|
||||
Configuration variables:
|
||||
|
||||
- **name** (*Optional*): Name of the device
|
||||
- **host** (*Required*): IP address or hostname of the device
|
||||
- **port** (*Required*): Port number of Volumio service
|
||||
"""
|
||||
import logging
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.media_player import (
|
||||
SUPPORT_NEXT_TRACK, SUPPORT_PAUSE,
|
||||
SUPPORT_PREVIOUS_TRACK, SUPPORT_SEEK,
|
||||
SUPPORT_PLAY_MEDIA, SUPPORT_VOLUME_MUTE,
|
||||
SUPPORT_VOLUME_SET, SUPPORT_STOP,
|
||||
SUPPORT_PLAY, MediaPlayerDevice,
|
||||
PLATFORM_SCHEMA, MEDIA_TYPE_MUSIC)
|
||||
from homeassistant.const import (
|
||||
STATE_PLAYING, STATE_PAUSED, STATE_IDLE, CONF_HOST, CONF_PORT, CONF_NAME)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
|
||||
_CONFIGURING = {}
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_HOST = 'localhost'
|
||||
DEFAULT_NAME = 'Volumio'
|
||||
DEFAULT_PORT = 3000
|
||||
TIMEOUT = 10
|
||||
|
||||
SUPPORT_VOLUMIO = SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
|
||||
SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | SUPPORT_SEEK | \
|
||||
SUPPORT_PLAY_MEDIA | SUPPORT_STOP | SUPPORT_PLAY
|
||||
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
|
||||
})
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
"""Setup the Volumio platform."""
|
||||
host = config.get(CONF_HOST)
|
||||
port = config.get(CONF_PORT)
|
||||
name = config.get(CONF_NAME)
|
||||
async_add_devices([Volumio(name, host, port, hass)])
|
||||
|
||||
|
||||
class Volumio(MediaPlayerDevice):
|
||||
"""Volumio Player Object."""
|
||||
|
||||
def __init__(self, name, host, port, hass):
|
||||
"""Initialize the media player."""
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.hass = hass
|
||||
self._url = host + ":" + str(port)
|
||||
self._name = name
|
||||
self._state = {}
|
||||
self.async_update()
|
||||
self._lastvol = self._state.get('volume', 0)
|
||||
|
||||
@asyncio.coroutine
|
||||
def send_volumio_msg(self, method, params=None):
|
||||
"""Send message."""
|
||||
url = "http://{}:{}/api/v1/{}/".format(
|
||||
self.host, self.port, method)
|
||||
response = None
|
||||
|
||||
_LOGGER.debug("URL: %s params: %s", url, params)
|
||||
|
||||
try:
|
||||
websession = async_get_clientsession(self.hass)
|
||||
response = yield from websession.get(url, params=params)
|
||||
if response.status == 200:
|
||||
data = yield from response.json()
|
||||
else:
|
||||
_LOGGER.error(
|
||||
"Query failed, response code: %s Full message: %s",
|
||||
response.status, response)
|
||||
return False
|
||||
|
||||
except (asyncio.TimeoutError,
|
||||
aiohttp.errors.ClientError,
|
||||
aiohttp.errors.ClientDisconnectedError) as error:
|
||||
_LOGGER.error("Failed communicating with Volumio: %s", type(error))
|
||||
return False
|
||||
finally:
|
||||
if response is not None:
|
||||
yield from response.release()
|
||||
|
||||
try:
|
||||
return data
|
||||
except AttributeError:
|
||||
_LOGGER.error("Received invalid response: %s", data)
|
||||
return False
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_update(self):
|
||||
"""Update state."""
|
||||
resp = yield from self.send_volumio_msg('getState')
|
||||
if resp is False:
|
||||
return
|
||||
self._state = resp.copy()
|
||||
|
||||
@property
|
||||
def media_content_type(self):
|
||||
"""Content type of current playing media."""
|
||||
return MEDIA_TYPE_MUSIC
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the device."""
|
||||
status = self._state.get('status', None)
|
||||
if status == 'pause':
|
||||
return STATE_PAUSED
|
||||
elif status == 'play':
|
||||
return STATE_PLAYING
|
||||
else:
|
||||
return STATE_IDLE
|
||||
|
||||
@property
|
||||
def media_title(self):
|
||||
"""Title of current playing media."""
|
||||
return self._state.get('title', None)
|
||||
|
||||
@property
|
||||
def media_artist(self):
|
||||
"""Artist of current playing media (Music track only)."""
|
||||
return self._state.get('artist', None)
|
||||
|
||||
@property
|
||||
def media_album_name(self):
|
||||
"""Artist of current playing media (Music track only)."""
|
||||
return self._state.get('album', None)
|
||||
|
||||
@property
|
||||
def media_image_url(self):
|
||||
"""Image url of current playing media."""
|
||||
url = self._state.get('albumart', None)
|
||||
if url is None:
|
||||
return
|
||||
if str(url[0:2]).lower() == 'ht':
|
||||
mediaurl = url
|
||||
else:
|
||||
mediaurl = "http://" + self.host + ":" + str(self.port) + url
|
||||
return mediaurl
|
||||
|
||||
@property
|
||||
def media_seek_position(self):
|
||||
"""Time in seconds of current seek position."""
|
||||
return self._state.get('seek', None)
|
||||
|
||||
@property
|
||||
def media_duration(self):
|
||||
"""Time in seconds of current song duration."""
|
||||
return self._state.get('duration', None)
|
||||
|
||||
@property
|
||||
def volume_level(self):
|
||||
"""Volume level of the media player (0..1)."""
|
||||
volume = self._state.get('volume', None)
|
||||
if volume is not None:
|
||||
volume = volume / 100
|
||||
return volume
|
||||
|
||||
@property
|
||||
def is_volume_muted(self):
|
||||
"""Boolean if volume is currently muted."""
|
||||
return self._state.get('mute', None)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def supported_features(self):
|
||||
"""Flag of media commands that are supported."""
|
||||
return SUPPORT_VOLUMIO
|
||||
|
||||
def async_media_next_track(self):
|
||||
"""Send media_next command to media player."""
|
||||
return self.send_volumio_msg('commands', params={'cmd': 'next'})
|
||||
|
||||
def async_media_previous_track(self):
|
||||
"""Send media_previous command to media player."""
|
||||
return self.send_volumio_msg('commands', params={'cmd': 'prev'})
|
||||
|
||||
def async_media_play(self):
|
||||
"""Send media_play command to media player."""
|
||||
return self.send_volumio_msg('commands', params={'cmd': 'play'})
|
||||
|
||||
def async_media_pause(self):
|
||||
"""Send media_pause command to media player."""
|
||||
return self.send_volumio_msg('commands', params={'cmd': 'pause'})
|
||||
|
||||
def async_set_volume_level(self, volume):
|
||||
"""Send volume_up command to media player."""
|
||||
return self.send_volumio_msg('commands',
|
||||
params={'cmd': 'volume',
|
||||
'volume': int(volume * 100)})
|
||||
|
||||
def async_mute_volume(self, mute):
|
||||
"""Send mute command to media player."""
|
||||
mutecmd = 'mute' if mute else 'unmute'
|
||||
if mute:
|
||||
# mute is implemenhted as 0 volume, do save last volume level
|
||||
self._lastvol = self._state['volume']
|
||||
return self.send_volumio_msg('commands',
|
||||
params={'cmd': 'volume',
|
||||
'volume': mutecmd})
|
||||
else:
|
||||
return self.send_volumio_msg('commands',
|
||||
params={'cmd': 'volume',
|
||||
'volume': self._lastvol})
|
Loading…
Reference in New Issue