Home Assistant Unofficial Reference 2024.12.1
media_player.py
Go to the documentation of this file.
1 """Support for the Unitymedia Horizon HD Recorder."""
2 
3 from __future__ import annotations
4 
5 from datetime import timedelta
6 import logging
7 from typing import Any
8 
9 from horimote import Client, keys
10 from horimote.exceptions import AuthenticationError
11 import voluptuous as vol
12 
13 from homeassistant import util
15  PLATFORM_SCHEMA as MEDIA_PLAYER_PLATFORM_SCHEMA,
16  MediaPlayerEntity,
17  MediaPlayerEntityFeature,
18  MediaPlayerState,
19  MediaType,
20 )
21 from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
22 from homeassistant.core import HomeAssistant
23 from homeassistant.exceptions import PlatformNotReady
25 from homeassistant.helpers.entity_platform import AddEntitiesCallback
26 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
27 
28 _LOGGER = logging.getLogger(__name__)
29 
30 DEFAULT_NAME = "Horizon"
31 DEFAULT_PORT = 5900
32 
33 MIN_TIME_BETWEEN_FORCED_SCANS = timedelta(seconds=1)
34 MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
35 
36 
37 PLATFORM_SCHEMA = MEDIA_PLAYER_PLATFORM_SCHEMA.extend(
38  {
39  vol.Required(CONF_HOST): cv.string,
40  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
41  vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
42  }
43 )
44 
45 
47  hass: HomeAssistant,
48  config: ConfigType,
49  add_entities: AddEntitiesCallback,
50  discovery_info: DiscoveryInfoType | None = None,
51 ) -> None:
52  """Set up the Horizon platform."""
53 
54  host = config[CONF_HOST]
55  name = config[CONF_NAME]
56  port = config[CONF_PORT]
57 
58  try:
59  client = Client(host, port=port)
60  except AuthenticationError as msg:
61  _LOGGER.error("Authentication to %s at %s failed: %s", name, host, msg)
62  return
63  except OSError as msg:
64  # occurs if horizon box is offline
65  _LOGGER.error("Connection to %s at %s failed: %s", name, host, msg)
66  raise PlatformNotReady from msg
67 
68  _LOGGER.debug("Connection to %s at %s established", name, host)
69 
70  add_entities([HorizonDevice(client, name, keys)], True)
71 
72 
74  """Representation of a Horizon HD Recorder."""
75 
76  _attr_supported_features = (
77  MediaPlayerEntityFeature.NEXT_TRACK
78  | MediaPlayerEntityFeature.PAUSE
79  | MediaPlayerEntityFeature.PLAY
80  | MediaPlayerEntityFeature.PLAY_MEDIA
81  | MediaPlayerEntityFeature.PREVIOUS_TRACK
82  | MediaPlayerEntityFeature.TURN_ON
83  | MediaPlayerEntityFeature.TURN_OFF
84  )
85 
86  def __init__(self, client, name, remote_keys):
87  """Initialize the remote."""
88  self._client_client = client
89  self._name_name = name
90  self._keys_keys = remote_keys
91 
92  @property
93  def name(self):
94  """Return the name of the remote."""
95  return self._name_name
96 
97  @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS)
98  def update(self) -> None:
99  """Update State using the media server running on the Horizon."""
100  try:
101  if self._client_client.is_powered_on():
102  self._attr_state_attr_state = MediaPlayerState.PLAYING
103  else:
104  self._attr_state_attr_state = MediaPlayerState.OFF
105  except OSError:
106  self._attr_state_attr_state = MediaPlayerState.OFF
107 
108  def turn_on(self) -> None:
109  """Turn the device on."""
110  if self.statestatestatestatestate == MediaPlayerState.OFF:
111  self._send_key_send_key(self._keys_keys.POWER)
112 
113  def turn_off(self) -> None:
114  """Turn the device off."""
115  if self.statestatestatestatestate != MediaPlayerState.OFF:
116  self._send_key_send_key(self._keys_keys.POWER)
117 
118  def media_previous_track(self) -> None:
119  """Channel down."""
120  self._send_key_send_key(self._keys_keys.CHAN_DOWN)
121  self._attr_state_attr_state = MediaPlayerState.PLAYING
122 
123  def media_next_track(self) -> None:
124  """Channel up."""
125  self._send_key_send_key(self._keys_keys.CHAN_UP)
126  self._attr_state_attr_state = MediaPlayerState.PLAYING
127 
128  def media_play(self) -> None:
129  """Send play command."""
130  self._send_key_send_key(self._keys_keys.PAUSE)
131  self._attr_state_attr_state = MediaPlayerState.PLAYING
132 
133  def media_pause(self) -> None:
134  """Send pause command."""
135  self._send_key_send_key(self._keys_keys.PAUSE)
136  self._attr_state_attr_state = MediaPlayerState.PAUSED
137 
138  def media_play_pause(self) -> None:
139  """Send play/pause command."""
140  self._send_key_send_key(self._keys_keys.PAUSE)
141  if self.statestatestatestatestate == MediaPlayerState.PAUSED:
142  self._attr_state_attr_state = MediaPlayerState.PLAYING
143  else:
144  self._attr_state_attr_state = MediaPlayerState.PAUSED
145 
147  self, media_type: MediaType | str, media_id: str, **kwargs: Any
148  ) -> None:
149  """Play media / switch to channel."""
150  if media_type == MediaType.CHANNEL:
151  try:
152  self._select_channel_select_channel(int(media_id))
153  self._attr_state_attr_state = MediaPlayerState.PLAYING
154  except ValueError:
155  _LOGGER.error("Invalid channel: %s", media_id)
156  else:
157  _LOGGER.error(
158  "Invalid media type %s. Supported type: %s",
159  media_type,
160  MediaType.CHANNEL,
161  )
162 
163  def _select_channel(self, channel):
164  """Select a channel (taken from einder library, thx)."""
165  self._send_send(channel=channel)
166 
167  def _send_key(self, key):
168  """Send a key to the Horizon device."""
169  self._send_send(key=key)
170 
171  def _send(self, key=None, channel=None):
172  """Send a key to the Horizon device."""
173 
174  try:
175  if key:
176  self._client_client.send_key(key)
177  elif channel:
178  self._client_client.select_channel(channel)
179  except OSError as msg:
180  _LOGGER.error("%s disconnected: %s. Trying to reconnect", self._name_name, msg)
181 
182  # for reconnect, first gracefully disconnect
183  self._client_client.disconnect()
184 
185  try:
186  self._client_client.connect()
187  self._client_client.authorize()
188  except AuthenticationError as msg2:
189  _LOGGER.error("Authentication to %s failed: %s", self._name_name, msg2)
190  return
191  except OSError as msg2:
192  # occurs if horizon box is offline
193  _LOGGER.error("Reconnect to %s failed: %s", self._name_name, msg2)
194  return
195 
196  self._send_send(key=key, channel=channel)
None play_media(self, MediaType|str media_type, str media_id, **Any kwargs)
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:51