Home Assistant Unofficial Reference 2024.12.1
media_player.py
Go to the documentation of this file.
1 """Support for interfacing with Monoprice Blackbird 4k 8x8 HDBaseT Matrix."""
2 
3 from __future__ import annotations
4 
5 import logging
6 
7 from pyblackbird import get_blackbird
8 from serial import SerialException
9 import voluptuous as vol
10 
12  PLATFORM_SCHEMA as MEDIA_PLAYER_PLATFORM_SCHEMA,
13  MediaPlayerEntity,
14  MediaPlayerEntityFeature,
15  MediaPlayerState,
16 )
17 from homeassistant.const import (
18  ATTR_ENTITY_ID,
19  CONF_HOST,
20  CONF_NAME,
21  CONF_PORT,
22  CONF_TYPE,
23 )
24 from homeassistant.core import HomeAssistant, ServiceCall
26 from homeassistant.helpers.entity_platform import AddEntitiesCallback
27 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
28 
29 from .const import DOMAIN, SERVICE_SETALLZONES
30 
31 _LOGGER = logging.getLogger(__name__)
32 
33 MEDIA_PLAYER_SCHEMA = vol.Schema({ATTR_ENTITY_ID: cv.comp_entity_ids})
34 
35 ZONE_SCHEMA = vol.Schema({vol.Required(CONF_NAME): cv.string})
36 
37 SOURCE_SCHEMA = vol.Schema({vol.Required(CONF_NAME): cv.string})
38 
39 CONF_ZONES = "zones"
40 CONF_SOURCES = "sources"
41 
42 DATA_BLACKBIRD = "blackbird"
43 
44 ATTR_SOURCE = "source"
45 
46 BLACKBIRD_SETALLZONES_SCHEMA = MEDIA_PLAYER_SCHEMA.extend(
47  {vol.Required(ATTR_SOURCE): cv.string}
48 )
49 
50 
51 # Valid zone ids: 1-8
52 ZONE_IDS = vol.All(vol.Coerce(int), vol.Range(min=1, max=8))
53 
54 # Valid source ids: 1-8
55 SOURCE_IDS = vol.All(vol.Coerce(int), vol.Range(min=1, max=8))
56 
57 PLATFORM_SCHEMA = vol.All(
58  cv.has_at_least_one_key(CONF_PORT, CONF_HOST),
59  MEDIA_PLAYER_PLATFORM_SCHEMA.extend(
60  {
61  vol.Exclusive(CONF_PORT, CONF_TYPE): cv.string,
62  vol.Exclusive(CONF_HOST, CONF_TYPE): cv.string,
63  vol.Required(CONF_ZONES): vol.Schema({ZONE_IDS: ZONE_SCHEMA}),
64  vol.Required(CONF_SOURCES): vol.Schema({SOURCE_IDS: SOURCE_SCHEMA}),
65  }
66  ),
67 )
68 
69 
71  hass: HomeAssistant,
72  config: ConfigType,
73  add_entities: AddEntitiesCallback,
74  discovery_info: DiscoveryInfoType | None = None,
75 ) -> None:
76  """Set up the Monoprice Blackbird 4k 8x8 HDBaseT Matrix platform."""
77  if DATA_BLACKBIRD not in hass.data:
78  hass.data[DATA_BLACKBIRD] = {}
79 
80  port = config.get(CONF_PORT)
81  host = config.get(CONF_HOST)
82 
83  connection = None
84  if port is not None:
85  try:
86  blackbird = get_blackbird(port)
87  connection = port
88  except SerialException:
89  _LOGGER.error("Error connecting to the Blackbird controller")
90  return
91 
92  if host is not None:
93  try:
94  blackbird = get_blackbird(host, False)
95  connection = host
96  except TimeoutError:
97  _LOGGER.error("Error connecting to the Blackbird controller")
98  return
99 
100  sources = {
101  source_id: extra[CONF_NAME] for source_id, extra in config[CONF_SOURCES].items()
102  }
103 
104  devices = []
105  for zone_id, extra in config[CONF_ZONES].items():
106  _LOGGER.debug("Adding zone %d - %s", zone_id, extra[CONF_NAME])
107  unique_id = f"{connection}-{zone_id}"
108  device = BlackbirdZone(blackbird, sources, zone_id, extra[CONF_NAME])
109  hass.data[DATA_BLACKBIRD][unique_id] = device
110  devices.append(device)
111 
112  add_entities(devices, True)
113 
114  def service_handle(service: ServiceCall) -> None:
115  """Handle for services."""
116  entity_ids = service.data.get(ATTR_ENTITY_ID)
117  source = service.data.get(ATTR_SOURCE)
118  if entity_ids:
119  devices = [
120  device
121  for device in hass.data[DATA_BLACKBIRD].values()
122  if device.entity_id in entity_ids
123  ]
124 
125  else:
126  devices = hass.data[DATA_BLACKBIRD].values()
127 
128  for device in devices:
129  if service.service == SERVICE_SETALLZONES:
130  device.set_all_zones(source)
131 
132  hass.services.register(
133  DOMAIN, SERVICE_SETALLZONES, service_handle, schema=BLACKBIRD_SETALLZONES_SCHEMA
134  )
135 
136 
138  """Representation of a Blackbird matrix zone."""
139 
140  _attr_supported_features = (
141  MediaPlayerEntityFeature.TURN_ON
142  | MediaPlayerEntityFeature.TURN_OFF
143  | MediaPlayerEntityFeature.SELECT_SOURCE
144  )
145 
146  def __init__(self, blackbird, sources, zone_id, zone_name):
147  """Initialize new zone."""
148  self._blackbird_blackbird = blackbird
149  # dict source_id -> source name
150  self._source_id_name_source_id_name = sources
151  # dict source name -> source_id
152  self._source_name_id_source_name_id = {v: k for k, v in sources.items()}
153  # ordered list of all source names
154  self._attr_source_list_attr_source_list = sorted(
155  self._source_name_id_source_name_id.keys(), key=lambda v: self._source_name_id_source_name_id[v]
156  )
157  self._zone_id_zone_id = zone_id
158  self._attr_name_attr_name = zone_name
159 
160  def update(self) -> None:
161  """Retrieve latest state."""
162  state = self._blackbird_blackbird.zone_status(self._zone_id_zone_id)
163  if not state:
164  return
165  self._attr_state_attr_state = MediaPlayerState.ON if state.power else MediaPlayerState.OFF
166  idx = state.av
167  self._attr_source_attr_source = self._source_id_name_source_id_name.get(idx)
168 
169  @property
170  def media_title(self):
171  """Return the current source as media title."""
172  return self.sourcesource
173 
174  def set_all_zones(self, source):
175  """Set all zones to one source."""
176  if source not in self._source_name_id_source_name_id:
177  return
178  idx = self._source_name_id_source_name_id[source]
179  _LOGGER.debug("Setting all zones source to %s", idx)
180  self._blackbird_blackbird.set_all_zone_source(idx)
181 
182  def select_source(self, source: str) -> None:
183  """Set input source."""
184  if source not in self._source_name_id_source_name_id:
185  return
186  idx = self._source_name_id_source_name_id[source]
187  _LOGGER.debug("Setting zone %d source to %s", self._zone_id_zone_id, idx)
188  self._blackbird_blackbird.set_zone_source(self._zone_id_zone_id, idx)
189 
190  def turn_on(self) -> None:
191  """Turn the media player on."""
192  _LOGGER.debug("Turning zone %d on", self._zone_id_zone_id)
193  self._blackbird_blackbird.set_zone_power(self._zone_id_zone_id, True)
194 
195  def turn_off(self) -> None:
196  """Turn the media player off."""
197  _LOGGER.debug("Turning zone %d off", self._zone_id_zone_id)
198  self._blackbird_blackbird.set_zone_power(self._zone_id_zone_id, False)
def __init__(self, blackbird, sources, zone_id, zone_name)
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:75
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
def service_handle(HomeAssistant hass)
Definition: __init__.py:219