mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Make Spotify polling interval dynamic (#136461)
This commit is contained in:
parent
7363413d3d
commit
f5fc46a7be
@ -31,6 +31,9 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
type SpotifyConfigEntry = ConfigEntry[SpotifyData]
|
type SpotifyConfigEntry = ConfigEntry[SpotifyData]
|
||||||
|
|
||||||
|
|
||||||
|
UPDATE_INTERVAL = timedelta(seconds=30)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SpotifyCoordinatorData:
|
class SpotifyCoordinatorData:
|
||||||
"""Class to hold Spotify data."""
|
"""Class to hold Spotify data."""
|
||||||
@ -59,7 +62,7 @@ class SpotifyCoordinator(DataUpdateCoordinator[SpotifyCoordinatorData]):
|
|||||||
hass,
|
hass,
|
||||||
_LOGGER,
|
_LOGGER,
|
||||||
name=DOMAIN,
|
name=DOMAIN,
|
||||||
update_interval=timedelta(seconds=30),
|
update_interval=UPDATE_INTERVAL,
|
||||||
)
|
)
|
||||||
self.client = client
|
self.client = client
|
||||||
self._playlist: Playlist | None = None
|
self._playlist: Playlist | None = None
|
||||||
@ -73,6 +76,7 @@ class SpotifyCoordinator(DataUpdateCoordinator[SpotifyCoordinatorData]):
|
|||||||
raise UpdateFailed("Error communicating with Spotify API") from err
|
raise UpdateFailed("Error communicating with Spotify API") from err
|
||||||
|
|
||||||
async def _async_update_data(self) -> SpotifyCoordinatorData:
|
async def _async_update_data(self) -> SpotifyCoordinatorData:
|
||||||
|
self.update_interval = UPDATE_INTERVAL
|
||||||
try:
|
try:
|
||||||
current = await self.client.get_playback()
|
current = await self.client.get_playback()
|
||||||
except SpotifyConnectionError as err:
|
except SpotifyConnectionError as err:
|
||||||
@ -120,6 +124,13 @@ class SpotifyCoordinator(DataUpdateCoordinator[SpotifyCoordinatorData]):
|
|||||||
)
|
)
|
||||||
self._playlist = None
|
self._playlist = None
|
||||||
self._checked_playlist_id = None
|
self._checked_playlist_id = None
|
||||||
|
if current.is_playing and current.progress_ms is not None:
|
||||||
|
assert current.item is not None
|
||||||
|
time_left = timedelta(
|
||||||
|
milliseconds=current.item.duration_ms - current.progress_ms
|
||||||
|
)
|
||||||
|
if time_left < UPDATE_INTERVAL:
|
||||||
|
self.update_interval = time_left + timedelta(seconds=1)
|
||||||
return SpotifyCoordinatorData(
|
return SpotifyCoordinatorData(
|
||||||
current_playback=current,
|
current_playback=current,
|
||||||
position_updated_at=position_updated_at,
|
position_updated_at=position_updated_at,
|
||||||
|
@ -641,3 +641,146 @@ async def test_no_album_images(
|
|||||||
state = hass.states.get("media_player.spotify_spotify_1")
|
state = hass.states.get("media_player.spotify_spotify_1")
|
||||||
assert state
|
assert state
|
||||||
assert ATTR_ENTITY_PICTURE not in state.attributes
|
assert ATTR_ENTITY_PICTURE not in state.attributes
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("setup_credentials")
|
||||||
|
async def test_normal_polling_interval(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_spotify: MagicMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
) -> None:
|
||||||
|
"""Test the Spotify media player polling interval."""
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
assert mock_spotify.return_value.get_playback.return_value.is_playing is True
|
||||||
|
assert (
|
||||||
|
mock_spotify.return_value.get_playback.return_value.progress_ms
|
||||||
|
- mock_spotify.return_value.get_playback.return_value.item.duration_ms
|
||||||
|
< 30000
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_called_once()
|
||||||
|
mock_spotify.return_value.get_playback.reset_mock()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=30))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("setup_credentials")
|
||||||
|
async def test_smart_polling_interval(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_spotify: MagicMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
) -> None:
|
||||||
|
"""Test the Spotify media player polling interval."""
|
||||||
|
mock_spotify.return_value.get_playback.return_value.progress_ms = 10000
|
||||||
|
mock_spotify.return_value.get_playback.return_value.item.duration_ms = 30000
|
||||||
|
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_called_once()
|
||||||
|
mock_spotify.return_value.get_playback.reset_mock()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=20))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_not_called()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.return_value.progress_ms = 10000
|
||||||
|
mock_spotify.return_value.get_playback.return_value.item.duration_ms = 50000
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=1))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_called_once()
|
||||||
|
mock_spotify.return_value.get_playback.reset_mock()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=21))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_not_called()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=9))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_called_once()
|
||||||
|
mock_spotify.return_value.get_playback.reset_mock()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("setup_credentials")
|
||||||
|
async def test_smart_polling_interval_handles_errors(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_spotify: MagicMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
) -> None:
|
||||||
|
"""Test the Spotify media player polling interval."""
|
||||||
|
mock_spotify.return_value.get_playback.return_value.progress_ms = 10000
|
||||||
|
mock_spotify.return_value.get_playback.return_value.item.duration_ms = 30000
|
||||||
|
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_called_once()
|
||||||
|
mock_spotify.return_value.get_playback.reset_mock()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.side_effect = SpotifyConnectionError
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=21))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_called_once()
|
||||||
|
mock_spotify.return_value.get_playback.reset_mock()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=21))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_not_called()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=9))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_called_once()
|
||||||
|
mock_spotify.return_value.get_playback.reset_mock()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("setup_credentials")
|
||||||
|
async def test_smart_polling_interval_handles_paused(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_spotify: MagicMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
) -> None:
|
||||||
|
"""Test the Spotify media player polling interval."""
|
||||||
|
mock_spotify.return_value.get_playback.return_value.progress_ms = 10000
|
||||||
|
mock_spotify.return_value.get_playback.return_value.item.duration_ms = 30000
|
||||||
|
mock_spotify.return_value.get_playback.return_value.is_playing = False
|
||||||
|
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_called_once()
|
||||||
|
mock_spotify.return_value.get_playback.reset_mock()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=21))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_not_called()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=9))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
mock_spotify.return_value.get_playback.assert_called_once()
|
||||||
|
mock_spotify.return_value.get_playback.reset_mock()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user