Home Assistant Unofficial Reference 2024.12.1
media_player.py
Go to the documentation of this file.
1 """Support for Clementine Music Player as media player."""
2 
3 from __future__ import annotations
4 
5 from datetime import timedelta
6 import time
7 
8 from clementineremote import ClementineRemote
9 import voluptuous as vol
10 
12  PLATFORM_SCHEMA as MEDIA_PLAYER_PLATFORM_SCHEMA,
13  MediaPlayerEntity,
14  MediaPlayerEntityFeature,
15  MediaPlayerState,
16  MediaType,
17 )
18 from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST, CONF_NAME, CONF_PORT
19 from homeassistant.core import HomeAssistant
21 from homeassistant.helpers.entity_platform import AddEntitiesCallback
22 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
23 
24 DEFAULT_NAME = "Clementine Remote"
25 DEFAULT_PORT = 5500
26 
27 SCAN_INTERVAL = timedelta(seconds=5)
28 
29 PLATFORM_SCHEMA = MEDIA_PLAYER_PLATFORM_SCHEMA.extend(
30  {
31  vol.Required(CONF_HOST): cv.string,
32  vol.Optional(CONF_ACCESS_TOKEN): cv.positive_int,
33  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
34  vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
35  }
36 )
37 
38 
40  hass: HomeAssistant,
41  config: ConfigType,
42  add_entities: AddEntitiesCallback,
43  discovery_info: DiscoveryInfoType | None = None,
44 ) -> None:
45  """Set up the Clementine platform."""
46 
47  host = config[CONF_HOST]
48  port = config[CONF_PORT]
49  token = config.get(CONF_ACCESS_TOKEN)
50 
51  client = ClementineRemote(host, port, token, reconnect=True)
52 
53  add_entities([ClementineDevice(client, config[CONF_NAME])])
54 
55 
57  """Representation of Clementine Player."""
58 
59  _attr_media_content_type = MediaType.MUSIC
60  _attr_supported_features = (
61  MediaPlayerEntityFeature.PAUSE
62  | MediaPlayerEntityFeature.VOLUME_STEP
63  | MediaPlayerEntityFeature.PREVIOUS_TRACK
64  | MediaPlayerEntityFeature.VOLUME_SET
65  | MediaPlayerEntityFeature.NEXT_TRACK
66  | MediaPlayerEntityFeature.SELECT_SOURCE
67  | MediaPlayerEntityFeature.PLAY
68  )
69 
70  def __init__(self, client, name):
71  """Initialize the Clementine device."""
72  self._client_client = client
73  self._attr_name_attr_name = name
74 
75  def update(self) -> None:
76  """Retrieve the latest data from the Clementine Player."""
77  try:
78  client = self._client_client
79 
80  if client.state == "Playing":
81  self._attr_state_attr_state = MediaPlayerState.PLAYING
82  elif client.state == "Paused":
83  self._attr_state_attr_state = MediaPlayerState.PAUSED
84  elif client.state == "Disconnected":
85  self._attr_state_attr_state = MediaPlayerState.OFF
86  else:
87  self._attr_state_attr_state = MediaPlayerState.PAUSED
88 
89  if client.last_update and (time.time() - client.last_update > 40):
90  self._attr_state_attr_state = MediaPlayerState.OFF
91 
92  volume = float(client.volume) if client.volume else 0.0
93  self._attr_volume_level_attr_volume_level = volume / 100.0
94  if client.active_playlist_id in client.playlists:
95  self._attr_source_attr_source = client.playlists[client.active_playlist_id]["name"]
96  else:
97  self._attr_source_attr_source = "Unknown"
98  self._attr_source_list_attr_source_list = [s["name"] for s in client.playlists.values()]
99 
100  if client.current_track:
101  self._attr_media_title_attr_media_title = client.current_track["title"]
102  self._attr_media_artist_attr_media_artist = client.current_track["track_artist"]
103  self._attr_media_album_name_attr_media_album_name = client.current_track["track_album"]
104  self._attr_media_image_hash_attr_media_image_hash = client.current_track["track_id"]
105  else:
106  self._attr_media_image_hash_attr_media_image_hash = None
107 
108  except Exception:
109  self._attr_state_attr_state = MediaPlayerState.OFF
110  raise
111 
112  def select_source(self, source: str) -> None:
113  """Select input source."""
114  client = self._client_client
115  sources = [s for s in client.playlists.values() if s["name"] == source]
116  if len(sources) == 1:
117  client.change_song(sources[0]["id"], 0)
118 
119  async def async_get_media_image(self) -> tuple[bytes | None, str | None]:
120  """Fetch media image of current playing image."""
121  if self._client_client.current_track:
122  image = bytes(self._client_client.current_track["art"])
123  return (image, "image/png")
124 
125  return None, None
126 
127  def volume_up(self) -> None:
128  """Volume up the media player."""
129  newvolume = min(self._client_client.volume + 4, 100)
130  self._client_client.set_volume(newvolume)
131 
132  def volume_down(self) -> None:
133  """Volume down media player."""
134  newvolume = max(self._client_client.volume - 4, 0)
135  self._client_client.set_volume(newvolume)
136 
137  def mute_volume(self, mute: bool) -> None:
138  """Send mute command."""
139  self._client_client.set_volume(0)
140 
141  def set_volume_level(self, volume: float) -> None:
142  """Set volume level."""
143  self._client_client.set_volume(int(100 * volume))
144 
145  def media_play_pause(self) -> None:
146  """Simulate play pause media player."""
147  if self.statestatestatestatestate == MediaPlayerState.PLAYING:
148  self.media_pausemedia_pausemedia_pause()
149  else:
150  self.media_playmedia_playmedia_play()
151 
152  def media_play(self) -> None:
153  """Send play command."""
154  self._attr_state_attr_state = MediaPlayerState.PLAYING
155  self._client_client.play()
156 
157  def media_pause(self) -> None:
158  """Send media pause command to media player."""
159  self._attr_state_attr_state = MediaPlayerState.PAUSED
160  self._client_client.pause()
161 
162  def media_next_track(self) -> None:
163  """Send next track command."""
164  self._client_client.next()
165 
166  def media_previous_track(self) -> None:
167  """Send the previous track command."""
168  self._client_client.previous()
None add_entities(AsusWrtRouter router, AddEntitiesCallback async_add_entities, set[str] tracked)
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: media_player.py:44