Add seek, shuffle, and repeat controls to Cambridge Audio (#125758)

* Add advanced transport controls to Cambridge Audio

* Use TransportControl model for play/pause
pull/124650/head^2
Noah Husby 2024-09-11 10:09:22 -04:00 committed by GitHub
parent cee14afc03
commit 2db488b7a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 70 additions and 16 deletions

View File

@ -4,13 +4,20 @@ from __future__ import annotations
from datetime import datetime
from aiostreammagic import StreamMagicClient
from aiostreammagic import (
RepeatMode as CambridgeRepeatMode,
ShuffleMode,
StreamMagicClient,
TransportControl,
)
from homeassistant.components.media_player import (
MediaPlayerDeviceClass,
MediaPlayerEntity,
MediaPlayerEntityFeature,
MediaPlayerState,
MediaType,
RepeatMode,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
@ -30,6 +37,16 @@ PREAMP_FEATURES = (
| MediaPlayerEntityFeature.VOLUME_STEP
)
TRANSPORT_FEATURES: dict[TransportControl, MediaPlayerEntityFeature] = {
TransportControl.PLAY: MediaPlayerEntityFeature.PLAY,
TransportControl.PAUSE: MediaPlayerEntityFeature.PAUSE,
TransportControl.TRACK_NEXT: MediaPlayerEntityFeature.NEXT_TRACK,
TransportControl.TRACK_PREVIOUS: MediaPlayerEntityFeature.PREVIOUS_TRACK,
TransportControl.TOGGLE_REPEAT: MediaPlayerEntityFeature.REPEAT_SET,
TransportControl.TOGGLE_SHUFFLE: MediaPlayerEntityFeature.SHUFFLE_SET,
TransportControl.SEEK: MediaPlayerEntityFeature.SEEK,
}
async def async_setup_entry(
hass: HomeAssistant,
@ -46,6 +63,7 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
_attr_name = None
_attr_media_content_type = MediaType.MUSIC
_attr_device_class = MediaPlayerDeviceClass.RECEIVER
def __init__(self, client: StreamMagicClient) -> None:
"""Initialize an Cambridge Audio entity."""
@ -71,16 +89,12 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
features = BASE_FEATURES
if self.client.state.pre_amp_mode:
features |= PREAMP_FEATURES
if "play_pause" in controls:
if TransportControl.PLAY_PAUSE in controls:
features |= MediaPlayerEntityFeature.PLAY | MediaPlayerEntityFeature.PAUSE
if "play" in controls:
features |= MediaPlayerEntityFeature.PLAY
if "pause" in controls:
features |= MediaPlayerEntityFeature.PAUSE
if "track_next" in controls:
features |= MediaPlayerEntityFeature.NEXT_TRACK
if "track_previous" in controls:
features |= MediaPlayerEntityFeature.PREVIOUS_TRACK
for control in controls:
feature = TRANSPORT_FEATURES.get(control)
if feature:
features |= feature
return features
@property
@ -164,6 +178,22 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
volume = self.client.state.volume_percent or 0
return volume / 100
@property
def shuffle(self) -> bool | None:
"""Current shuffle configuration."""
mode_shuffle = self.client.play_state.mode_shuffle
if not mode_shuffle:
return False
return mode_shuffle != ShuffleMode.OFF
@property
def repeat(self) -> RepeatMode | None:
"""Current repeat configuration."""
mode_repeat = RepeatMode.OFF
if self.client.play_state.mode_repeat == CambridgeRepeatMode.ALL:
mode_repeat = RepeatMode.ALL
return mode_repeat
async def async_media_play_pause(self) -> None:
"""Toggle play/pause the current media."""
await self.client.play_pause()
@ -171,7 +201,10 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
async def async_media_pause(self) -> None:
"""Pause the current media."""
controls = self.client.now_playing.controls
if "pause" not in controls and "play_pause" in controls:
if (
TransportControl.PAUSE not in controls
and TransportControl.PLAY_PAUSE in controls
):
await self.client.play_pause()
else:
await self.client.pause()
@ -182,8 +215,14 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
async def async_media_play(self) -> None:
"""Play the current media."""
if self.state == MediaPlayerState.PAUSED:
controls = self.client.now_playing.controls
if (
TransportControl.PLAY not in controls
and TransportControl.PLAY_PAUSE in controls
):
await self.client.play_pause()
else:
await self.client.play()
async def async_media_next_track(self) -> None:
"""Skip to the next track."""
@ -222,7 +261,22 @@ class CambridgeAudioDevice(CambridgeAudioEntity, MediaPlayerEntity):
async def async_mute_volume(self, mute: bool) -> None:
"""Set the mute state."""
if mute:
await self.client.mute()
else:
await self.client.unmute()
await self.client.set_mute(mute)
async def async_media_seek(self, position: float) -> None:
"""Seek to a position in the current media."""
await self.client.media_seek(int(position))
async def async_set_shuffle(self, shuffle: bool) -> None:
"""Set the shuffle mode for the current queue."""
shuffle_mode = ShuffleMode.OFF
if shuffle:
shuffle_mode = ShuffleMode.ALL
await self.client.set_shuffle(shuffle_mode)
async def async_set_repeat(self, repeat: RepeatMode) -> None:
"""Set the repeat mode for the current queue."""
repeat_mode = CambridgeRepeatMode.OFF
if repeat:
repeat_mode = CambridgeRepeatMode.ALL
await self.client.set_repeat(repeat_mode)