mirror of
https://github.com/home-assistant/core.git
synced 2025-07-08 13:57:10 +00:00
Add HEOS media player component (#21721)
## Description: Denon HEOS media player. **Pull request in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) with documentation (if applicable):** home-assistant/home-assistant.io#8848 ## Example entry for `configuration.yaml` (if applicable): ```yaml heos: host: HEOS-1 ``` ## Checklist: - [X] The code change is tested and works locally. - [X] Local tests pass with `tox`. **Your PR cannot be merged unless tests pass** - [X] There is no commented out code in this PR. If user exposed functionality or configuration variables are added/changed: - [X] Documentation added/updated in [home-assistant.io](https://github.com/home-assistant/home-assistant.io) If the code communicates with devices, web services, or third-party tools: - [X] New dependencies have been added to the `REQUIREMENTS` variable ([example][ex-requir]). - [X] New dependencies are only imported inside functions that use them ([example][ex-import]). - [X] New or updated dependencies have been added to `requirements_all.txt` by running `script/gen_requirements_all.py`. - [X] New files were added to `.coveragerc`. If the code does not interact with devices: - [ ] Tests have been added to verify that the new code works. [ex-requir]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L14 [ex-import]: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/keyboard/__init__.py#L23 Co-authored-by: Andrew Sayre <6730289+andrewsayre@users.noreply.github.com>
This commit is contained in:
parent
709419e465
commit
01052f516b
@ -235,11 +235,15 @@ omit =
|
|||||||
homeassistant/components/harmony/remote.py
|
homeassistant/components/harmony/remote.py
|
||||||
homeassistant/components/haveibeenpwned/sensor.py
|
homeassistant/components/haveibeenpwned/sensor.py
|
||||||
homeassistant/components/hdmi_cec/*
|
homeassistant/components/hdmi_cec/*
|
||||||
|
<<<<<<< HEAD
|
||||||
homeassistant/components/heatmiser/climate.py
|
homeassistant/components/heatmiser/climate.py
|
||||||
homeassistant/components/hikvision/binary_sensor.py
|
homeassistant/components/hikvision/binary_sensor.py
|
||||||
homeassistant/components/hikvisioncam/switch.py
|
homeassistant/components/hikvisioncam/switch.py
|
||||||
homeassistant/components/hipchat/notify.py
|
homeassistant/components/hipchat/notify.py
|
||||||
homeassistant/components/hitron_coda/device_tracker.py
|
homeassistant/components/hitron_coda/device_tracker.py
|
||||||
|
=======
|
||||||
|
homeassistant/components/heos/*
|
||||||
|
>>>>>>> Update HEOS to support multiple speaker and conformance.
|
||||||
homeassistant/components/hive/*
|
homeassistant/components/hive/*
|
||||||
homeassistant/components/hlk_sw16/*
|
homeassistant/components/hlk_sw16/*
|
||||||
homeassistant/components/homekit_controller/*
|
homeassistant/components/homekit_controller/*
|
||||||
|
52
homeassistant/components/heos/__init__.py
Normal file
52
homeassistant/components/heos/__init__.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
"""Denon HEOS Media Player."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.components.media_player.const import (
|
||||||
|
DOMAIN as MEDIA_PLAYER_DOMAIN)
|
||||||
|
from homeassistant.const import CONF_HOST, EVENT_HOMEASSISTANT_STOP
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from homeassistant.helpers.discovery import async_load_platform
|
||||||
|
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
||||||
|
|
||||||
|
DOMAIN = 'heos'
|
||||||
|
REQUIREMENTS = ['aioheos==0.4.0']
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = vol.Schema({
|
||||||
|
DOMAIN: vol.Schema({
|
||||||
|
vol.Required(CONF_HOST): cv.string
|
||||||
|
})
|
||||||
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup(hass: HomeAssistantType, config: ConfigType):
|
||||||
|
"""Set up the HEOS component."""
|
||||||
|
from aioheos import AioHeosController
|
||||||
|
|
||||||
|
host = config[DOMAIN][CONF_HOST]
|
||||||
|
controller = AioHeosController(hass.loop, host)
|
||||||
|
|
||||||
|
try:
|
||||||
|
await asyncio.wait_for(controller.connect(), timeout=5.0)
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
_LOGGER.error('Timeout during setup.')
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def controller_close(event):
|
||||||
|
"""Close connection when HASS shutsdown."""
|
||||||
|
await controller.close()
|
||||||
|
|
||||||
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, controller_close)
|
||||||
|
|
||||||
|
hass.data.setdefault(DOMAIN, {})
|
||||||
|
hass.data[DOMAIN][MEDIA_PLAYER_DOMAIN] = controller
|
||||||
|
|
||||||
|
hass.async_create_task(async_load_platform(
|
||||||
|
hass, MEDIA_PLAYER_DOMAIN, DOMAIN, {}, config))
|
||||||
|
|
||||||
|
return True
|
152
homeassistant/components/heos/media_player.py
Normal file
152
homeassistant/components/heos/media_player.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
"""Denon HEOS Media Player."""
|
||||||
|
|
||||||
|
from homeassistant.components.media_player import MediaPlayerDevice
|
||||||
|
from homeassistant.components.media_player.const import (
|
||||||
|
DOMAIN, MEDIA_TYPE_MUSIC, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PLAY,
|
||||||
|
SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, SUPPORT_STOP,
|
||||||
|
SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET, SUPPORT_VOLUME_STEP)
|
||||||
|
from homeassistant.const import STATE_IDLE, STATE_PAUSED, STATE_PLAYING
|
||||||
|
|
||||||
|
from . import DOMAIN as HEOS_DOMAIN
|
||||||
|
|
||||||
|
DEPENDENCIES = ["heos"]
|
||||||
|
|
||||||
|
SUPPORT_HEOS = (
|
||||||
|
SUPPORT_PLAY
|
||||||
|
| SUPPORT_STOP
|
||||||
|
| SUPPORT_PAUSE
|
||||||
|
| SUPPORT_PLAY_MEDIA
|
||||||
|
| SUPPORT_PREVIOUS_TRACK
|
||||||
|
| SUPPORT_NEXT_TRACK
|
||||||
|
| SUPPORT_VOLUME_MUTE
|
||||||
|
| SUPPORT_VOLUME_SET
|
||||||
|
| SUPPORT_VOLUME_STEP
|
||||||
|
)
|
||||||
|
|
||||||
|
PLAY_STATE_TO_STATE = {
|
||||||
|
"play": STATE_PLAYING,
|
||||||
|
"pause": STATE_PAUSED,
|
||||||
|
"stop": STATE_IDLE,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(hass, config, async_add_devices,
|
||||||
|
discover_info=None):
|
||||||
|
"""Set up the HEOS platform."""
|
||||||
|
controller = hass.data[HEOS_DOMAIN][DOMAIN]
|
||||||
|
players = controller.get_players()
|
||||||
|
devices = [HeosMediaPlayer(p) for p in players]
|
||||||
|
async_add_devices(devices, True)
|
||||||
|
|
||||||
|
|
||||||
|
class HeosMediaPlayer(MediaPlayerDevice):
|
||||||
|
"""The HEOS player."""
|
||||||
|
|
||||||
|
def __init__(self, player):
|
||||||
|
"""Initialize."""
|
||||||
|
self._player = player
|
||||||
|
|
||||||
|
def _update_state(self):
|
||||||
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
|
async def async_update(self):
|
||||||
|
"""Update the player."""
|
||||||
|
self._player.request_update()
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""Device added to hass."""
|
||||||
|
self._player.state_change_callback = self._update_state
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self):
|
||||||
|
"""Get unique id of the player."""
|
||||||
|
return self._player.player_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the device."""
|
||||||
|
return self._player.name
|
||||||
|
|
||||||
|
@property
|
||||||
|
def volume_level(self):
|
||||||
|
"""Volume level of the device (0..1)."""
|
||||||
|
volume = self._player.volume
|
||||||
|
return float(volume) / 100
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Get state."""
|
||||||
|
return PLAY_STATE_TO_STATE.get(self._player.play_state)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def should_poll(self):
|
||||||
|
"""No polling needed."""
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def media_content_type(self):
|
||||||
|
"""Content type of current playing media."""
|
||||||
|
return MEDIA_TYPE_MUSIC
|
||||||
|
|
||||||
|
@property
|
||||||
|
def media_artist(self):
|
||||||
|
"""Artist of current playing media."""
|
||||||
|
return self._player.media_artist
|
||||||
|
|
||||||
|
@property
|
||||||
|
def media_title(self):
|
||||||
|
"""Album name of current playing media."""
|
||||||
|
return self._player.media_title
|
||||||
|
|
||||||
|
@property
|
||||||
|
def media_album_name(self):
|
||||||
|
"""Album name of current playing media."""
|
||||||
|
return self._player.media_album
|
||||||
|
|
||||||
|
@property
|
||||||
|
def media_image_url(self):
|
||||||
|
"""Return the image url of current playing media."""
|
||||||
|
return self._player.media_image_url
|
||||||
|
|
||||||
|
@property
|
||||||
|
def media_content_id(self):
|
||||||
|
"""Return the content ID of current playing media."""
|
||||||
|
return self._player.media_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_volume_muted(self):
|
||||||
|
"""Boolean if volume is currently muted."""
|
||||||
|
return self._player.mute == "on"
|
||||||
|
|
||||||
|
async def async_mute_volume(self, mute):
|
||||||
|
"""Mute volume."""
|
||||||
|
self._player.set_mute(mute)
|
||||||
|
|
||||||
|
async def async_media_next_track(self):
|
||||||
|
"""Go TO next track."""
|
||||||
|
self._player.play_next()
|
||||||
|
|
||||||
|
async def async_media_previous_track(self):
|
||||||
|
"""Go TO previous track."""
|
||||||
|
self._player.play_previous()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supported_features(self):
|
||||||
|
"""Flag of media commands that are supported."""
|
||||||
|
return SUPPORT_HEOS
|
||||||
|
|
||||||
|
async def async_set_volume_level(self, volume):
|
||||||
|
"""Set volume level, range 0..1."""
|
||||||
|
self._player.set_volume(volume * 100)
|
||||||
|
|
||||||
|
async def async_media_play(self):
|
||||||
|
"""Play media player."""
|
||||||
|
self._player.play()
|
||||||
|
|
||||||
|
async def async_media_stop(self):
|
||||||
|
"""Stop media player."""
|
||||||
|
self._player.stop()
|
||||||
|
|
||||||
|
async def async_media_pause(self):
|
||||||
|
"""Pause media player."""
|
||||||
|
self._player.pause()
|
@ -123,6 +123,9 @@ aioftp==0.12.0
|
|||||||
# homeassistant.components.harmony.remote
|
# homeassistant.components.harmony.remote
|
||||||
aioharmony==0.1.8
|
aioharmony==0.1.8
|
||||||
|
|
||||||
|
# homeassistant.components.heos
|
||||||
|
aioheos==0.4.0
|
||||||
|
|
||||||
# homeassistant.components.emulated_hue
|
# homeassistant.components.emulated_hue
|
||||||
# homeassistant.components.http
|
# homeassistant.components.http
|
||||||
aiohttp_cors==0.7.0
|
aiohttp_cors==0.7.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user