Home Assistant Unofficial Reference 2024.12.1
media_player.py
Go to the documentation of this file.
1 """Support for interfacing with WS66i 6 zone home audio controller."""
2 
3 from pyws66i import WS66i, ZoneStatus
4 
6  MediaPlayerEntity,
7  MediaPlayerEntityFeature,
8  MediaPlayerState,
9 )
10 from homeassistant.config_entries import ConfigEntry
11 from homeassistant.core import HomeAssistant, callback
12 from homeassistant.helpers.device_registry import DeviceInfo
13 from homeassistant.helpers.entity_platform import AddEntitiesCallback
14 from homeassistant.helpers.update_coordinator import CoordinatorEntity
15 
16 from .const import DOMAIN, MAX_VOL
17 from .coordinator import Ws66iDataUpdateCoordinator
18 from .models import Ws66iData
19 
20 PARALLEL_UPDATES = 1
21 
22 
24  hass: HomeAssistant,
25  config_entry: ConfigEntry,
26  async_add_entities: AddEntitiesCallback,
27 ) -> None:
28  """Set up the WS66i 6-zone amplifier platform from a config entry."""
29  ws66i_data: Ws66iData = hass.data[DOMAIN][config_entry.entry_id]
30 
31  # Build and add the entities from the data class
33  Ws66iZone(
34  device=ws66i_data.device,
35  ws66i_data=ws66i_data,
36  entry_id=config_entry.entry_id,
37  zone_id=zone_id,
38  data_idx=idx,
39  coordinator=ws66i_data.coordinator,
40  )
41  for idx, zone_id in enumerate(ws66i_data.zones)
42  )
43 
44 
45 class Ws66iZone(CoordinatorEntity[Ws66iDataUpdateCoordinator], MediaPlayerEntity):
46  """Representation of a WS66i amplifier zone."""
47 
48  _attr_has_entity_name = True
49  _attr_name = None
50  _attr_supported_features = (
51  MediaPlayerEntityFeature.VOLUME_MUTE
52  | MediaPlayerEntityFeature.VOLUME_SET
53  | MediaPlayerEntityFeature.VOLUME_STEP
54  | MediaPlayerEntityFeature.TURN_ON
55  | MediaPlayerEntityFeature.TURN_OFF
56  | MediaPlayerEntityFeature.SELECT_SOURCE
57  )
58 
59  def __init__(
60  self,
61  device: WS66i,
62  ws66i_data: Ws66iData,
63  entry_id: str,
64  zone_id: int,
65  data_idx: int,
66  coordinator: Ws66iDataUpdateCoordinator,
67  ) -> None:
68  """Initialize a zone entity."""
69  super().__init__(coordinator)
70  self._ws66i_ws66i: WS66i = device
71  self._ws66i_data: Ws66iData = ws66i_data
72  self._zone_id: int = zone_id
73  self._zone_id_idx: int = data_idx
74  self._status_status: ZoneStatus = coordinator.data[data_idx]
75  self._attr_source_list_attr_source_list = ws66i_data.sources.name_list
76  self._attr_unique_id_attr_unique_id = f"{entry_id}_{zone_id}"
77  self._attr_device_info_attr_device_info = DeviceInfo(
78  identifiers={(DOMAIN, str(self.unique_idunique_id))},
79  name=f"Zone {zone_id}",
80  manufacturer="Soundavo",
81  model="WS66i 6-Zone Amplifier",
82  )
83  self._set_attrs_from_status_set_attrs_from_status()
84 
85  @callback
86  def _handle_coordinator_update(self) -> None:
87  """Handle updated data from the coordinator."""
88  # This will be called for each of the entities after the coordinator
89  # finishes executing _async_update_data()
90 
91  # Save a reference to the zone status that this entity represents
92  self._status_status = self.coordinator.data[self._zone_id_idx]
93  self._set_attrs_from_status_set_attrs_from_status()
94 
95  # Parent will notify HA of the update
97 
98  @callback
99  def _set_attrs_from_status(self) -> None:
100  status = self._status_status
101  sources = self._ws66i_data.sources.id_name
102  self._attr_state_attr_state = MediaPlayerState.ON if status.power else MediaPlayerState.OFF
103  self._attr_volume_level_attr_volume_level = status.volume / float(MAX_VOL)
104  self._attr_is_volume_muted_attr_is_volume_muted = status.mute
105  self._attr_source_attr_source = self._attr_media_title_attr_media_title = sources[status.source]
106 
107  @callback
109  self._set_attrs_from_status_set_attrs_from_status()
110  self.async_write_ha_stateasync_write_ha_state()
111 
112  async def async_select_source(self, source: str) -> None:
113  """Set input source."""
114  idx = self._ws66i_data.sources.name_id[source]
115  await self.hasshasshass.async_add_executor_job(
116  self._ws66i_ws66i.set_source, self._zone_id, idx
117  )
118  self._status_status.source = idx
119  self._async_update_attrs_write_ha_state_async_update_attrs_write_ha_state()
120 
121  async def async_turn_on(self) -> None:
122  """Turn the media player on."""
123  await self.hasshasshass.async_add_executor_job(
124  self._ws66i_ws66i.set_power, self._zone_id, True
125  )
126  self._status_status.power = True
127  self._async_update_attrs_write_ha_state_async_update_attrs_write_ha_state()
128 
129  async def async_turn_off(self) -> None:
130  """Turn the media player off."""
131  await self.hasshasshass.async_add_executor_job(
132  self._ws66i_ws66i.set_power, self._zone_id, False
133  )
134  self._status_status.power = False
135  self._async_update_attrs_write_ha_state_async_update_attrs_write_ha_state()
136 
137  async def async_mute_volume(self, mute: bool) -> None:
138  """Mute (true) or unmute (false) media player."""
139  await self.hasshasshass.async_add_executor_job(
140  self._ws66i_ws66i.set_mute, self._zone_id, mute
141  )
142  self._status_status.mute = bool(mute)
143  self._async_update_attrs_write_ha_state_async_update_attrs_write_ha_state()
144 
145  async def async_set_volume_level(self, volume: float) -> None:
146  """Set volume level, range 0..1."""
147  await self.hasshasshass.async_add_executor_job(self._set_volume_set_volume, int(volume * MAX_VOL))
148  self._async_update_attrs_write_ha_state_async_update_attrs_write_ha_state()
149 
150  async def async_volume_up(self) -> None:
151  """Volume up the media player."""
152  await self.hasshasshass.async_add_executor_job(
153  self._set_volume_set_volume, min(self._status_status.volume + 1, MAX_VOL)
154  )
155  self._async_update_attrs_write_ha_state_async_update_attrs_write_ha_state()
156 
157  async def async_volume_down(self) -> None:
158  """Volume down media player."""
159  await self.hasshasshass.async_add_executor_job(
160  self._set_volume_set_volume, max(self._status_status.volume - 1, 0)
161  )
162  self._async_update_attrs_write_ha_state_async_update_attrs_write_ha_state()
163 
164  def _set_volume(self, volume: int) -> None:
165  """Set the volume of the media player."""
166  # Can't set a new volume level when this zone is muted.
167  # Follow behavior of keypads, where zone is unmuted when volume changes.
168  if self._status_status.mute:
169  self._ws66i_ws66i.set_mute(self._zone_id, False)
170  self._status_status.mute = False
171 
172  self._ws66i_ws66i.set_volume(self._zone_id, volume)
173  self._status_status.volume = volume
None __init__(self, WS66i device, Ws66iData ws66i_data, str entry_id, int zone_id, int data_idx, Ws66iDataUpdateCoordinator coordinator)
Definition: media_player.py:67
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: media_player.py:27