Home Assistant Unofficial Reference 2024.12.1
media_player.py
Go to the documentation of this file.
1 """Dune HD implementation of the media player."""
2 
3 from __future__ import annotations
4 
5 from typing import Any, Final
6 
7 from pdunehd import DuneHDPlayer
8 
9 from homeassistant.components import media_source
11  BrowseMedia,
12  MediaPlayerEntity,
13  MediaPlayerEntityFeature,
14  MediaPlayerState,
15  MediaType,
16  async_process_play_media_url,
17 )
18 from homeassistant.config_entries import ConfigEntry
19 from homeassistant.core import HomeAssistant
20 from homeassistant.helpers.device_registry import DeviceInfo
21 from homeassistant.helpers.entity_platform import AddEntitiesCallback
22 
23 from .const import ATTR_MANUFACTURER, DEFAULT_NAME, DOMAIN
24 
25 CONF_SOURCES: Final = "sources"
26 
27 DUNEHD_PLAYER_SUPPORT: Final[MediaPlayerEntityFeature] = (
28  MediaPlayerEntityFeature.PAUSE
29  | MediaPlayerEntityFeature.TURN_ON
30  | MediaPlayerEntityFeature.TURN_OFF
31  | MediaPlayerEntityFeature.PREVIOUS_TRACK
32  | MediaPlayerEntityFeature.NEXT_TRACK
33  | MediaPlayerEntityFeature.PLAY
34  | MediaPlayerEntityFeature.PLAY_MEDIA
35  | MediaPlayerEntityFeature.BROWSE_MEDIA
36 )
37 
38 
40  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
41 ) -> None:
42  """Add Dune HD entities from a config_entry."""
43  unique_id = entry.entry_id
44 
45  player: DuneHDPlayer = hass.data[DOMAIN][entry.entry_id]
46 
47  async_add_entities([DuneHDPlayerEntity(player, DEFAULT_NAME, unique_id)], True)
48 
49 
51  """Implementation of the Dune HD player."""
52 
53  _attr_has_entity_name = True
54  _attr_name = None
55 
56  def __init__(self, player: DuneHDPlayer, name: str, unique_id: str) -> None:
57  """Initialize entity to control Dune HD."""
58  self._player_player = player
59  self._media_title_media_title: str | None = None
60  self._state_state: dict[str, Any] = {}
61  self._attr_unique_id_attr_unique_id = unique_id
62  self._attr_device_info_attr_device_info = DeviceInfo(
63  identifiers={(DOMAIN, unique_id)},
64  manufacturer=ATTR_MANUFACTURER,
65  name=name,
66  )
67 
68  def update(self) -> None:
69  """Update internal status of the entity."""
70  self._state_state = self._player_player.update_state()
71  self.__update_title__update_title()
72 
73  @property
74  def state(self) -> MediaPlayerState:
75  """Return player state."""
76  state = MediaPlayerState.OFF
77  if "playback_position" in self._state_state:
78  state = MediaPlayerState.PLAYING
79  if self._state_state.get("player_state") in ("playing", "buffering", "photo_viewer"):
80  state = MediaPlayerState.PLAYING
81  if int(self._state_state.get("playback_speed", 1234)) == 0:
82  state = MediaPlayerState.PAUSED
83  if self._state_state.get("player_state") == "navigator":
84  state = MediaPlayerState.ON
85  return state
86 
87  @property
88  def available(self) -> bool:
89  """Return True if entity is available."""
90  return len(self._state_state) > 0
91 
92  @property
93  def volume_level(self) -> float:
94  """Return the volume level of the media player (0..1)."""
95  return int(self._state_state.get("playback_volume", 0)) / 100
96 
97  @property
98  def is_volume_muted(self) -> bool:
99  """Return a boolean if volume is currently muted."""
100  return int(self._state_state.get("playback_mute", 0)) == 1
101 
102  @property
103  def supported_features(self) -> MediaPlayerEntityFeature:
104  """Flag media player features that are supported."""
105  return DUNEHD_PLAYER_SUPPORT
106 
107  def volume_up(self) -> None:
108  """Volume up media player."""
109  self._state_state = self._player_player.volume_up()
110 
111  def volume_down(self) -> None:
112  """Volume down media player."""
113  self._state_state = self._player_player.volume_down()
114 
115  def mute_volume(self, mute: bool) -> None:
116  """Mute/unmute player volume."""
117  self._state_state = self._player_player.mute(mute)
118 
119  def turn_off(self) -> None:
120  """Turn off media player."""
121  self._media_title_media_title = None
122  self._state_state = self._player_player.turn_off()
123 
124  def turn_on(self) -> None:
125  """Turn on media player."""
126  self._state_state = self._player_player.turn_on()
127 
128  def media_play(self) -> None:
129  """Play media player."""
130  self._state_state = self._player_player.play()
131 
132  def media_pause(self) -> None:
133  """Pause media player."""
134  self._state_state = self._player_player.pause()
135 
136  async def async_play_media(
137  self, media_type: MediaType | str, media_id: str, **kwargs: Any
138  ) -> None:
139  """Play media from a URL or file."""
140  # Handle media_source
141  if media_source.is_media_source_id(media_id):
142  sourced_media = await media_source.async_resolve_media(
143  self.hasshass, media_id, self.entity_identity_id
144  )
145  media_id = sourced_media.url
146 
147  # If media ID is a relative URL, we serve it from HA.
148  media_id = async_process_play_media_url(self.hasshass, media_id)
149 
150  self._state_state = await self.hasshass.async_add_executor_job(
151  self._player_player.launch_media_url, media_id
152  )
153 
155  self,
156  media_content_type: MediaType | str | None = None,
157  media_content_id: str | None = None,
158  ) -> BrowseMedia:
159  """Implement the websocket media browsing helper."""
160  return await media_source.async_browse_media(self.hasshass, media_content_id)
161 
162  @property
163  def media_title(self) -> str | None:
164  """Return the current media source."""
165  self.__update_title__update_title()
166  if self._media_title_media_title:
167  return self._media_title_media_title
168  return None
169 
170  def __update_title(self) -> None:
171  if self._state_state.get("player_state") == "bluray_playback":
172  self._media_title_media_title = "Blu-Ray"
173  elif self._state_state.get("player_state") == "photo_viewer":
174  self._media_title_media_title = "Photo Viewer"
175  elif self._state_state.get("playback_url"):
176  self._media_title_media_title = self._state_state["playback_url"].split("/")[-1]
177  else:
178  self._media_title_media_title = None
179 
180  def media_previous_track(self) -> None:
181  """Send previous track command."""
182  self._state_state = self._player_player.previous_track()
183 
184  def media_next_track(self) -> None:
185  """Send next track command."""
186  self._state_state = self._player_player.next_track()
None __init__(self, DuneHDPlayer player, str name, str unique_id)
Definition: media_player.py:56
BrowseMedia async_browse_media(self, MediaType|str|None media_content_type=None, str|None media_content_id=None)
None async_play_media(self, MediaType|str media_type, str media_id, **Any kwargs)
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: media_player.py:41
str async_process_play_media_url(HomeAssistant hass, str media_content_id, *bool allow_relative_url=False, bool for_supervisor_network=False)
Definition: browse_media.py:36