mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 13:47:35 +00:00
Move imports to top (#24108)
This commit is contained in:
parent
25505dc1d4
commit
0194905e97
@ -4,6 +4,7 @@ from datetime import timedelta
|
||||
import logging
|
||||
from typing import Dict
|
||||
|
||||
from pyheos import CommandError, Heos, const as heos_const
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.media_player.const import (
|
||||
@ -57,7 +58,6 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType):
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry):
|
||||
"""Initialize config entry which represents the HEOS controller."""
|
||||
from pyheos import Heos, CommandError
|
||||
host = entry.data[CONF_HOST]
|
||||
# Setting all_progress_events=False ensures that we only receive a
|
||||
# media position update upon start of playback or when media changes
|
||||
@ -137,16 +137,15 @@ class ControllerManager:
|
||||
|
||||
async def connect_listeners(self):
|
||||
"""Subscribe to events of interest."""
|
||||
from pyheos import const
|
||||
self._device_registry, self._entity_registry = await asyncio.gather(
|
||||
self._hass.helpers.device_registry.async_get_registry(),
|
||||
self._hass.helpers.entity_registry.async_get_registry())
|
||||
# Handle controller events
|
||||
self._signals.append(self.controller.dispatcher.connect(
|
||||
const.SIGNAL_CONTROLLER_EVENT, self._controller_event))
|
||||
heos_const.SIGNAL_CONTROLLER_EVENT, self._controller_event))
|
||||
# Handle connection-related events
|
||||
self._signals.append(self.controller.dispatcher.connect(
|
||||
const.SIGNAL_HEOS_EVENT, self._heos_event))
|
||||
heos_const.SIGNAL_HEOS_EVENT, self._heos_event))
|
||||
|
||||
async def disconnect(self):
|
||||
"""Disconnect subscriptions."""
|
||||
@ -158,21 +157,19 @@ class ControllerManager:
|
||||
|
||||
async def _controller_event(self, event, data):
|
||||
"""Handle controller event."""
|
||||
from pyheos import const
|
||||
if event == const.EVENT_PLAYERS_CHANGED:
|
||||
self.update_ids(data[const.DATA_MAPPED_IDS])
|
||||
if event == heos_const.EVENT_PLAYERS_CHANGED:
|
||||
self.update_ids(data[heos_const.DATA_MAPPED_IDS])
|
||||
# Update players
|
||||
self._hass.helpers.dispatcher.async_dispatcher_send(
|
||||
SIGNAL_HEOS_UPDATED)
|
||||
|
||||
async def _heos_event(self, event):
|
||||
"""Handle connection event."""
|
||||
from pyheos import CommandError, const
|
||||
if event == const.EVENT_CONNECTED:
|
||||
if event == heos_const.EVENT_CONNECTED:
|
||||
try:
|
||||
# Retrieve latest players and refresh status
|
||||
data = await self.controller.load_players()
|
||||
self.update_ids(data[const.DATA_MAPPED_IDS])
|
||||
self.update_ids(data[heos_const.DATA_MAPPED_IDS])
|
||||
except (CommandError, asyncio.TimeoutError, ConnectionError) as ex:
|
||||
_LOGGER.error("Unable to refresh players: %s", ex)
|
||||
# Update players
|
||||
@ -241,9 +238,8 @@ class SourceManager:
|
||||
|
||||
def get_current_source(self, now_playing_media):
|
||||
"""Determine current source from now playing media."""
|
||||
from pyheos import const
|
||||
# Match input by input_name:media_id
|
||||
if now_playing_media.source_id == const.MUSIC_SOURCE_AUX_INPUT:
|
||||
if now_playing_media.source_id == heos_const.MUSIC_SOURCE_AUX_INPUT:
|
||||
return next((input_source.name for input_source in self.inputs
|
||||
if input_source.input_name ==
|
||||
now_playing_media.media_id), None)
|
||||
@ -260,8 +256,6 @@ class SourceManager:
|
||||
physical event therefore throttle it. Retrieving sources immediately
|
||||
after the event may fail so retry.
|
||||
"""
|
||||
from pyheos import CommandError, const
|
||||
|
||||
@Throttle(MIN_UPDATE_SOURCES)
|
||||
async def get_sources():
|
||||
retry_attempts = 0
|
||||
@ -286,9 +280,9 @@ class SourceManager:
|
||||
return
|
||||
|
||||
async def update_sources(event, data=None):
|
||||
if event in (const.EVENT_SOURCES_CHANGED,
|
||||
const.EVENT_USER_CHANGED,
|
||||
const.EVENT_CONNECTED):
|
||||
if event in (heos_const.EVENT_SOURCES_CHANGED,
|
||||
heos_const.EVENT_USER_CHANGED,
|
||||
heos_const.EVENT_CONNECTED):
|
||||
sources = await get_sources()
|
||||
# If throttled, it will return None
|
||||
if sources:
|
||||
@ -300,6 +294,6 @@ class SourceManager:
|
||||
SIGNAL_HEOS_UPDATED)
|
||||
|
||||
controller.dispatcher.connect(
|
||||
const.SIGNAL_CONTROLLER_EVENT, update_sources)
|
||||
heos_const.SIGNAL_CONTROLLER_EVENT, update_sources)
|
||||
controller.dispatcher.connect(
|
||||
const.SIGNAL_HEOS_EVENT, update_sources)
|
||||
heos_const.SIGNAL_HEOS_EVENT, update_sources)
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""Config flow to configure Heos."""
|
||||
import asyncio
|
||||
|
||||
from pyheos import Heos
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
@ -44,7 +45,6 @@ class HeosFlowHandler(config_entries.ConfigFlow):
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Obtain host and validate connection."""
|
||||
from pyheos import Heos
|
||||
self.hass.data.setdefault(DATA_DISCOVERED_HOSTS, {})
|
||||
# Only a single entry is needed for all devices
|
||||
if self._async_current_entries():
|
||||
|
@ -5,6 +5,8 @@ import logging
|
||||
from operator import ior
|
||||
from typing import Sequence
|
||||
|
||||
from pyheos import CommandError, const as heos_const
|
||||
|
||||
from homeassistant.components.media_player import MediaPlayerDevice
|
||||
from homeassistant.components.media_player.const import (
|
||||
ATTR_MEDIA_ENQUEUE, DOMAIN, MEDIA_TYPE_MUSIC, MEDIA_TYPE_PLAYLIST,
|
||||
@ -25,6 +27,20 @@ BASE_SUPPORTED_FEATURES = SUPPORT_VOLUME_MUTE | SUPPORT_VOLUME_SET | \
|
||||
SUPPORT_SHUFFLE_SET | SUPPORT_SELECT_SOURCE | \
|
||||
SUPPORT_PLAY_MEDIA
|
||||
|
||||
PLAY_STATE_TO_STATE = {
|
||||
heos_const.PLAY_STATE_PLAY: STATE_PLAYING,
|
||||
heos_const.PLAY_STATE_STOP: STATE_IDLE,
|
||||
heos_const.PLAY_STATE_PAUSE: STATE_PAUSED
|
||||
}
|
||||
|
||||
CONTROL_TO_SUPPORT = {
|
||||
heos_const.CONTROL_PLAY: SUPPORT_PLAY,
|
||||
heos_const.CONTROL_PAUSE: SUPPORT_PAUSE,
|
||||
heos_const.CONTROL_STOP: SUPPORT_STOP,
|
||||
heos_const.CONTROL_PLAY_PREVIOUS: SUPPORT_PREVIOUS_TRACK,
|
||||
heos_const.CONTROL_PLAY_NEXT: SUPPORT_NEXT_TRACK
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@ -47,7 +63,6 @@ def log_command_error(command: str):
|
||||
def decorator(func):
|
||||
@wraps(func)
|
||||
async def wrapper(*args, **kwargs):
|
||||
from pyheos import CommandError
|
||||
try:
|
||||
await func(*args, **kwargs)
|
||||
except (CommandError, asyncio.TimeoutError, ConnectionError,
|
||||
@ -62,31 +77,17 @@ class HeosMediaPlayer(MediaPlayerDevice):
|
||||
|
||||
def __init__(self, player):
|
||||
"""Initialize."""
|
||||
from pyheos import const
|
||||
self._media_position_updated_at = None
|
||||
self._player = player
|
||||
self._signals = []
|
||||
self._supported_features = BASE_SUPPORTED_FEATURES
|
||||
self._source_manager = None
|
||||
self._play_state_to_state = {
|
||||
const.PLAY_STATE_PLAY: STATE_PLAYING,
|
||||
const.PLAY_STATE_STOP: STATE_IDLE,
|
||||
const.PLAY_STATE_PAUSE: STATE_PAUSED
|
||||
}
|
||||
self._control_to_support = {
|
||||
const.CONTROL_PLAY: SUPPORT_PLAY,
|
||||
const.CONTROL_PAUSE: SUPPORT_PAUSE,
|
||||
const.CONTROL_STOP: SUPPORT_STOP,
|
||||
const.CONTROL_PLAY_PREVIOUS: SUPPORT_PREVIOUS_TRACK,
|
||||
const.CONTROL_PLAY_NEXT: SUPPORT_NEXT_TRACK
|
||||
}
|
||||
|
||||
async def _player_update(self, player_id, event):
|
||||
"""Handle player attribute updated."""
|
||||
from pyheos import const
|
||||
if self._player.player_id != player_id:
|
||||
return
|
||||
if event == const.EVENT_PLAYER_NOW_PLAYING_PROGRESS:
|
||||
if event == heos_const.EVENT_PLAYER_NOW_PLAYING_PROGRESS:
|
||||
self._media_position_updated_at = utcnow()
|
||||
await self.async_update_ha_state(True)
|
||||
|
||||
@ -96,11 +97,10 @@ class HeosMediaPlayer(MediaPlayerDevice):
|
||||
|
||||
async def async_added_to_hass(self):
|
||||
"""Device added to hass."""
|
||||
from pyheos import const
|
||||
self._source_manager = self.hass.data[HEOS_DOMAIN][DATA_SOURCE_MANAGER]
|
||||
# Update state when attributes of the player change
|
||||
self._signals.append(self._player.heos.dispatcher.connect(
|
||||
const.SIGNAL_PLAYER_EVENT, self._player_update))
|
||||
heos_const.SIGNAL_PLAYER_EVENT, self._player_update))
|
||||
# Update state when heos changes
|
||||
self._signals.append(
|
||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
||||
@ -163,14 +163,13 @@ class HeosMediaPlayer(MediaPlayerDevice):
|
||||
return
|
||||
|
||||
if media_type == MEDIA_TYPE_PLAYLIST:
|
||||
from pyheos import const
|
||||
playlists = await self._player.heos.get_playlists()
|
||||
playlist = next((p for p in playlists if p.name == media_id), None)
|
||||
if not playlist:
|
||||
raise ValueError("Invalid playlist '{}'".format(media_id))
|
||||
add_queue_option = const.ADD_QUEUE_ADD_TO_END \
|
||||
add_queue_option = heos_const.ADD_QUEUE_ADD_TO_END \
|
||||
if kwargs.get(ATTR_MEDIA_ENQUEUE) \
|
||||
else const.ADD_QUEUE_REPLACE_AND_PLAY
|
||||
else heos_const.ADD_QUEUE_REPLACE_AND_PLAY
|
||||
await self._player.add_to_queue(playlist, add_queue_option)
|
||||
return
|
||||
|
||||
@ -208,7 +207,7 @@ class HeosMediaPlayer(MediaPlayerDevice):
|
||||
async def async_update(self):
|
||||
"""Update supported features of the player."""
|
||||
controls = self._player.now_playing_media.supported_controls
|
||||
current_support = [self._control_to_support[control]
|
||||
current_support = [CONTROL_TO_SUPPORT[control]
|
||||
for control in controls]
|
||||
self._supported_features = reduce(ior, current_support,
|
||||
BASE_SUPPORTED_FEATURES)
|
||||
@ -343,7 +342,7 @@ class HeosMediaPlayer(MediaPlayerDevice):
|
||||
@property
|
||||
def state(self) -> str:
|
||||
"""State of the player."""
|
||||
return self._play_state_to_state[self._player.state]
|
||||
return PLAY_STATE_TO_STATE[self._player.state]
|
||||
|
||||
@property
|
||||
def supported_features(self) -> int:
|
||||
|
@ -2,7 +2,7 @@
|
||||
from typing import Dict, Sequence
|
||||
|
||||
from asynctest.mock import Mock, patch as patch
|
||||
from pyheos import Dispatcher, HeosPlayer, HeosSource, InputSource, const
|
||||
from pyheos import Dispatcher, Heos, HeosPlayer, HeosSource, InputSource, const
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.heos import DOMAIN
|
||||
@ -22,20 +22,23 @@ def config_entry_fixture():
|
||||
def controller_fixture(
|
||||
players, favorites, input_sources, playlists, change_data, dispatcher):
|
||||
"""Create a mock Heos controller fixture."""
|
||||
with patch("pyheos.Heos", autospec=True) as mock:
|
||||
mock_heos = mock.return_value
|
||||
for player in players.values():
|
||||
player.heos = mock_heos
|
||||
mock_heos.dispatcher = dispatcher
|
||||
mock_heos.get_players.return_value = players
|
||||
mock_heos.players = players
|
||||
mock_heos.get_favorites.return_value = favorites
|
||||
mock_heos.get_input_sources.return_value = input_sources
|
||||
mock_heos.get_playlists.return_value = playlists
|
||||
mock_heos.load_players.return_value = change_data
|
||||
mock_heos.is_signed_in = True
|
||||
mock_heos.signed_in_username = "user@user.com"
|
||||
mock_heos.connection_state = const.STATE_CONNECTED
|
||||
mock_heos = Mock(Heos)
|
||||
for player in players.values():
|
||||
player.heos = mock_heos
|
||||
mock_heos.dispatcher = dispatcher
|
||||
mock_heos.get_players.return_value = players
|
||||
mock_heos.players = players
|
||||
mock_heos.get_favorites.return_value = favorites
|
||||
mock_heos.get_input_sources.return_value = input_sources
|
||||
mock_heos.get_playlists.return_value = playlists
|
||||
mock_heos.load_players.return_value = change_data
|
||||
mock_heos.is_signed_in = True
|
||||
mock_heos.signed_in_username = "user@user.com"
|
||||
mock_heos.connection_state = const.STATE_CONNECTED
|
||||
mock = Mock(return_value=mock_heos)
|
||||
|
||||
with patch("homeassistant.components.heos.Heos", new=mock), \
|
||||
patch("homeassistant.components.heos.config_flow.Heos", new=mock):
|
||||
yield mock_heos
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user