Home Assistant Unofficial Reference 2024.12.1
media_player.py
Go to the documentation of this file.
1 """Support for System Bridge media players."""
2 
3 from __future__ import annotations
4 
5 import datetime as dt
6 from typing import Final
7 
8 from systembridgemodels.media_control import MediaAction, MediaControl
9 
11  MediaPlayerDeviceClass,
12  MediaPlayerEntity,
13  MediaPlayerEntityDescription,
14  MediaPlayerEntityFeature,
15  MediaPlayerState,
16  RepeatMode,
17 )
18 from homeassistant.config_entries import ConfigEntry
19 from homeassistant.const import CONF_PORT
20 from homeassistant.core import HomeAssistant
21 from homeassistant.helpers.entity_platform import AddEntitiesCallback
22 
23 from .const import DOMAIN
24 from .coordinator import SystemBridgeDataUpdateCoordinator
25 from .data import SystemBridgeData
26 from .entity import SystemBridgeEntity
27 
28 STATUS_CHANGING: Final[str] = "CHANGING"
29 STATUS_STOPPED: Final[str] = "STOPPED"
30 STATUS_PLAYING: Final[str] = "PLAYING"
31 STATUS_PAUSED: Final[str] = "PAUSED"
32 
33 REPEAT_NONE: Final[str] = "NONE"
34 REPEAT_TRACK: Final[str] = "TRACK"
35 REPEAT_LIST: Final[str] = "LIST"
36 
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,
42 }
43 
44 MEDIA_REPEAT_MAP: Final[dict[str, RepeatMode]] = {
45  REPEAT_NONE: RepeatMode.OFF,
46  REPEAT_TRACK: RepeatMode.ONE,
47  REPEAT_LIST: RepeatMode.ALL,
48 }
49 
50 MEDIA_SET_REPEAT_MAP: Final[dict[RepeatMode, int]] = {
51  RepeatMode.OFF: 0,
52  RepeatMode.ONE: 1,
53  RepeatMode.ALL: 2,
54 }
55 
56 MEDIA_PLAYER_DESCRIPTION: Final[MediaPlayerEntityDescription] = (
58  key="media",
59  translation_key="media",
60  icon="mdi:volume-high",
61  device_class=MediaPlayerDeviceClass.RECEIVER,
62  )
63 )
64 
65 
67  hass: HomeAssistant,
68  entry: ConfigEntry,
69  async_add_entities: AddEntitiesCallback,
70 ) -> None:
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
74 
75  if data.media is not None:
77  [
79  coordinator,
80  MEDIA_PLAYER_DESCRIPTION,
81  entry.data[CONF_PORT],
82  )
83  ]
84  )
85 
86 
88  """Define a System Bridge media player."""
89 
90  entity_description: MediaPlayerEntityDescription
91 
92  def __init__(
93  self,
94  coordinator: SystemBridgeDataUpdateCoordinator,
95  description: MediaPlayerEntityDescription,
96  api_port: int,
97  ) -> None:
98  """Initialize."""
99  super().__init__(
100  coordinator,
101  api_port,
102  description.key,
103  )
104  self.entity_descriptionentity_description = description
105 
106  @property
107  def available(self) -> bool:
108  """Return True if entity is available."""
109  return super().available and self.coordinator.data.media is not None
110 
111  @property
112  def supported_features(self) -> MediaPlayerEntityFeature:
113  """Flag media player features that are supported."""
114  features = (
115  MediaPlayerEntityFeature.REPEAT_SET | MediaPlayerEntityFeature.SHUFFLE_SET
116  )
117 
118  data = self._systembridge_data_systembridge_data
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
127 
128  return features
129 
130  @property
131  def _systembridge_data(self) -> SystemBridgeData:
132  """Return data for the entity."""
133  return self.coordinator.data
134 
135  @property
136  def state(self) -> MediaPlayerState | None:
137  """State of the player."""
138  if self._systembridge_data_systembridge_data.media.status is None:
139  return None
140  return MEDIA_STATUS_MAP.get(
141  self._systembridge_data_systembridge_data.media.status,
142  MediaPlayerState.IDLE,
143  )
144 
145  @property
146  def media_duration(self) -> int | None:
147  """Duration of current playing media in seconds."""
148  if self._systembridge_data_systembridge_data.media.duration is None:
149  return None
150  return int(self._systembridge_data_systembridge_data.media.duration)
151 
152  @property
153  def media_position(self) -> int | None:
154  """Position of current playing media in seconds."""
155  if self._systembridge_data_systembridge_data.media.position is None:
156  return None
157  return int(self._systembridge_data_systembridge_data.media.position)
158 
159  @property
160  def media_position_updated_at(self) -> dt.datetime | None:
161  """When was the position of the current playing media valid."""
162  if self._systembridge_data_systembridge_data.media.updated_at is None:
163  return None
164  return dt.datetime.fromtimestamp(self._systembridge_data_systembridge_data.media.updated_at)
165 
166  @property
167  def media_title(self) -> str | None:
168  """Title of current playing media."""
169  return self._systembridge_data_systembridge_data.media.title
170 
171  @property
172  def media_artist(self) -> str | None:
173  """Artist of current playing media, music track only."""
174  return self._systembridge_data_systembridge_data.media.artist
175 
176  @property
177  def media_album_name(self) -> str | None:
178  """Album name of current playing media, music track only."""
179  return self._systembridge_data_systembridge_data.media.album_title
180 
181  @property
182  def media_album_artist(self) -> str | None:
183  """Album artist of current playing media, music track only."""
184  return self._systembridge_data_systembridge_data.media.album_artist
185 
186  @property
187  def media_track(self) -> int | None:
188  """Track number of current playing media, music track only."""
189  return self._systembridge_data_systembridge_data.media.track_number
190 
191  @property
192  def shuffle(self) -> bool | None:
193  """Boolean if shuffle is enabled."""
194  return self._systembridge_data_systembridge_data.media.shuffle
195 
196  @property
197  def repeat(self) -> RepeatMode | None:
198  """Return current repeat mode."""
199  if self._systembridge_data_systembridge_data.media.repeat is None:
200  return RepeatMode.OFF
201  return MEDIA_REPEAT_MAP.get(self._systembridge_data_systembridge_data.media.repeat)
202 
203  async def async_media_play(self) -> None:
204  """Send play command."""
205  await self.coordinator.websocket_client.media_control(
206  MediaControl(
207  action=MediaAction.PLAY.value,
208  )
209  )
210 
211  async def async_media_pause(self) -> None:
212  """Send pause command."""
213  await self.coordinator.websocket_client.media_control(
214  MediaControl(
215  action=MediaAction.PAUSE.value,
216  )
217  )
218 
219  async def async_media_stop(self) -> None:
220  """Send stop command."""
221  await self.coordinator.websocket_client.media_control(
222  MediaControl(
223  action=MediaAction.STOP.value,
224  )
225  )
226 
227  async def async_media_previous_track(self) -> None:
228  """Send previous track command."""
229  await self.coordinator.websocket_client.media_control(
230  MediaControl(
231  action=MediaAction.PREVIOUS.value,
232  )
233  )
234 
235  async def async_media_next_track(self) -> None:
236  """Send next track command."""
237  await self.coordinator.websocket_client.media_control(
238  MediaControl(
239  action=MediaAction.NEXT.value,
240  )
241  )
242 
243  async def async_set_shuffle(
244  self,
245  shuffle: bool,
246  ) -> None:
247  """Enable/disable shuffle mode."""
248  await self.coordinator.websocket_client.media_control(
249  MediaControl(
250  action=MediaAction.SHUFFLE.value,
251  value=shuffle,
252  )
253  )
254 
255  async def async_set_repeat(
256  self,
257  repeat: RepeatMode,
258  ) -> None:
259  """Set repeat mode."""
260  await self.coordinator.websocket_client.media_control(
261  MediaControl(
262  action=MediaAction.REPEAT.value,
263  value=MEDIA_SET_REPEAT_MAP.get(repeat),
264  )
265  )
None __init__(self, SystemBridgeDataUpdateCoordinator coordinator, MediaPlayerEntityDescription description, int api_port)
Definition: media_player.py:97
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: media_player.py:70