1 """Support for System Bridge media players."""
3 from __future__
import annotations
6 from typing
import Final
8 from systembridgemodels.media_control
import MediaAction, MediaControl
11 MediaPlayerDeviceClass,
13 MediaPlayerEntityDescription,
14 MediaPlayerEntityFeature,
23 from .const
import DOMAIN
24 from .coordinator
import SystemBridgeDataUpdateCoordinator
25 from .data
import SystemBridgeData
26 from .entity
import SystemBridgeEntity
28 STATUS_CHANGING: Final[str] =
"CHANGING"
29 STATUS_STOPPED: Final[str] =
"STOPPED"
30 STATUS_PLAYING: Final[str] =
"PLAYING"
31 STATUS_PAUSED: Final[str] =
"PAUSED"
33 REPEAT_NONE: Final[str] =
"NONE"
34 REPEAT_TRACK: Final[str] =
"TRACK"
35 REPEAT_LIST: Final[str] =
"LIST"
37 MEDIA_STATUS_MAP: Final[dict[str, MediaPlayerState]] = {
38 STATUS_CHANGING: MediaPlayerState.IDLE,
39 STATUS_STOPPED: MediaPlayerState.IDLE,
40 STATUS_PLAYING: MediaPlayerState.PLAYING,
41 STATUS_PAUSED: MediaPlayerState.PAUSED,
44 MEDIA_REPEAT_MAP: Final[dict[str, RepeatMode]] = {
45 REPEAT_NONE: RepeatMode.OFF,
46 REPEAT_TRACK: RepeatMode.ONE,
47 REPEAT_LIST: RepeatMode.ALL,
50 MEDIA_SET_REPEAT_MAP: Final[dict[RepeatMode, int]] = {
56 MEDIA_PLAYER_DESCRIPTION: Final[MediaPlayerEntityDescription] = (
59 translation_key=
"media",
60 icon=
"mdi:volume-high",
61 device_class=MediaPlayerDeviceClass.RECEIVER,
69 async_add_entities: AddEntitiesCallback,
71 """Set up System Bridge media players based on a config entry."""
72 coordinator: SystemBridgeDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
73 data = coordinator.data
75 if data.media
is not None:
80 MEDIA_PLAYER_DESCRIPTION,
81 entry.data[CONF_PORT],
88 """Define a System Bridge media player."""
90 entity_description: MediaPlayerEntityDescription
94 coordinator: SystemBridgeDataUpdateCoordinator,
95 description: MediaPlayerEntityDescription,
108 """Return True if entity is available."""
109 return super().available
and self.coordinator.data.media
is not None
113 """Flag media player features that are supported."""
115 MediaPlayerEntityFeature.REPEAT_SET | MediaPlayerEntityFeature.SHUFFLE_SET
119 if data.media.is_previous_enabled:
120 features |= MediaPlayerEntityFeature.PREVIOUS_TRACK
121 if data.media.is_next_enabled:
122 features |= MediaPlayerEntityFeature.NEXT_TRACK
123 if data.media.is_pause_enabled
or data.media.is_play_enabled:
124 features |= MediaPlayerEntityFeature.PAUSE | MediaPlayerEntityFeature.PLAY
125 if data.media.is_stop_enabled:
126 features |= MediaPlayerEntityFeature.STOP
132 """Return data for the entity."""
133 return self.coordinator.data
136 def state(self) -> MediaPlayerState | None:
137 """State of the player."""
140 return MEDIA_STATUS_MAP.get(
142 MediaPlayerState.IDLE,
147 """Duration of current playing media in seconds."""
154 """Position of current playing media in seconds."""
161 """When was the position of the current playing media valid."""
164 return dt.datetime.fromtimestamp(self.
_systembridge_data_systembridge_data.media.updated_at)
168 """Title of current playing media."""
173 """Artist of current playing media, music track only."""
178 """Album name of current playing media, music track only."""
183 """Album artist of current playing media, music track only."""
188 """Track number of current playing media, music track only."""
193 """Boolean if shuffle is enabled."""
198 """Return current repeat mode."""
200 return RepeatMode.OFF
204 """Send play command."""
205 await self.coordinator.websocket_client.media_control(
207 action=MediaAction.PLAY.value,
212 """Send pause command."""
213 await self.coordinator.websocket_client.media_control(
215 action=MediaAction.PAUSE.value,
220 """Send stop command."""
221 await self.coordinator.websocket_client.media_control(
223 action=MediaAction.STOP.value,
228 """Send previous track command."""
229 await self.coordinator.websocket_client.media_control(
231 action=MediaAction.PREVIOUS.value,
236 """Send next track command."""
237 await self.coordinator.websocket_client.media_control(
239 action=MediaAction.NEXT.value,
247 """Enable/disable shuffle mode."""
248 await self.coordinator.websocket_client.media_control(
250 action=MediaAction.SHUFFLE.value,
259 """Set repeat mode."""
260 await self.coordinator.websocket_client.media_control(
262 action=MediaAction.REPEAT.value,
263 value=MEDIA_SET_REPEAT_MAP.get(repeat),