Use DataUpdateCoordinator for Spotify devices (#66314)

This commit is contained in:
Franck Nijhof 2022-02-11 18:04:49 +01:00 committed by GitHub
parent 57624347e6
commit acf2033734
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 15 deletions

View File

@ -1,9 +1,12 @@
"""The spotify integration."""
from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from typing import Any
import aiohttp
import requests
from spotipy import Spotify, SpotifyException
import voluptuous as vol
@ -22,10 +25,11 @@ from homeassistant.helpers.config_entry_oauth2_flow import (
async_get_config_entry_implementation,
)
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from . import config_flow
from .browse_media import async_browse_media
from .const import DOMAIN, SPOTIFY_SCOPES
from .const import DOMAIN, LOGGER, SPOTIFY_SCOPES
from .util import is_spotify_media_type, resolve_spotify_media_type
CONFIG_SCHEMA = vol.Schema(
@ -57,6 +61,7 @@ class HomeAssistantSpotifyData:
client: Spotify
current_user: dict[str, Any]
devices: DataUpdateCoordinator
session: OAuth2Session
@ -101,10 +106,35 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
if not current_user:
raise ConfigEntryNotReady
async def _update_devices() -> list[dict[str, Any]]:
try:
devices: dict[str, Any] | None = await hass.async_add_executor_job(
spotify.devices
)
except (requests.RequestException, SpotifyException) as err:
raise UpdateFailed from err
if devices is None:
return []
return devices.get("devices", [])
device_coordinator: DataUpdateCoordinator[
list[dict[str, Any]]
] = DataUpdateCoordinator(
hass,
LOGGER,
name=f"{entry.title} Devices",
update_interval=timedelta(minutes=5),
update_method=_update_devices,
)
await device_coordinator.async_config_entry_first_refresh()
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = HomeAssistantSpotifyData(
client=spotify,
current_user=current_user,
devices=device_coordinator,
session=session,
)

View File

@ -1,4 +1,7 @@
"""Define constants for the Spotify integration."""
import logging
from homeassistant.components.media_player.const import (
MEDIA_TYPE_ALBUM,
MEDIA_TYPE_ARTIST,
@ -9,6 +12,8 @@ from homeassistant.components.media_player.const import (
DOMAIN = "spotify"
LOGGER = logging.getLogger(__package__)
SPOTIFY_SCOPES = [
# Needed to be able to control playback
"user-modify-playback-state",

View File

@ -33,7 +33,7 @@ from homeassistant.components.media_player.const import (
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_ID, STATE_IDLE, STATE_PAUSED, STATE_PLAYING
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
@ -147,7 +147,6 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
SPOTIFY_SCOPES
)
self._currently_playing: dict | None = {}
self._devices: list[dict] | None = []
self._playlist: dict | None = None
@property
@ -258,9 +257,7 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
@property
def source_list(self) -> list[str] | None:
"""Return a list of source devices."""
if not self._devices:
return None
return [device["name"] for device in self._devices]
return [device["name"] for device in self.data.devices.data]
@property
def shuffle(self) -> bool | None:
@ -332,19 +329,16 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
if (
self._currently_playing
and not self._currently_playing.get("device")
and self._devices
and self.data.devices.data
):
kwargs["device_id"] = self._devices[0].get("id")
kwargs["device_id"] = self.data.devices.data[0].get("id")
self.data.client.start_playback(**kwargs)
@spotify_exception_handler
def select_source(self, source: str) -> None:
"""Select playback device."""
if not self._devices:
return
for device in self._devices:
for device in self.data.devices.data:
if device["name"] == source:
self.data.client.transfer_playback(
device["id"], self.state == STATE_PLAYING
@ -386,9 +380,6 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
if context["type"] == MEDIA_TYPE_PLAYLIST:
self._playlist = self.data.client.playlist(current["context"]["uri"])
devices = self.data.client.devices() or {}
self._devices = devices.get("devices", [])
async def async_browse_media(
self, media_content_type: str | None = None, media_content_id: str | None = None
) -> BrowseMedia:
@ -408,3 +399,17 @@ class SpotifyMediaPlayer(MediaPlayerEntity):
media_content_type,
media_content_id,
)
@callback
def _handle_devices_update(self) -> None:
"""Handle updated data from the coordinator."""
if not self.enabled:
return
self.async_write_ha_state()
async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
self.async_on_remove(
self.data.devices.async_add_listener(self._handle_devices_update)
)