Home Assistant Unofficial Reference 2024.12.1
websocket.py
Go to the documentation of this file.
1 """Update coordinator and WebSocket listener(s) for the Bang & Olufsen integration."""
2 
3 from __future__ import annotations
4 
5 import logging
6 
7 from mozart_api.models import (
8  ListeningModeProps,
9  PlaybackContentMetadata,
10  PlaybackError,
11  PlaybackProgress,
12  RenderingState,
13  SoftwareUpdateState,
14  Source,
15  VolumeState,
16  WebsocketNotificationTag,
17 )
18 from mozart_api.mozart_client import BaseWebSocketResponse, MozartClient
19 
20 from homeassistant.config_entries import ConfigEntry
21 from homeassistant.core import HomeAssistant
22 from homeassistant.helpers import device_registry as dr
23 from homeassistant.helpers.dispatcher import async_dispatcher_send
24 from homeassistant.util.enum import try_parse_enum
25 
26 from .const import (
27  BANG_OLUFSEN_WEBSOCKET_EVENT,
28  CONNECTION_STATUS,
29  WebsocketNotification,
30 )
31 from .entity import BangOlufsenBase
32 from .util import get_device
33 
34 _LOGGER = logging.getLogger(__name__)
35 
36 
38  """The WebSocket listeners."""
39 
40  def __init__(
41  self, hass: HomeAssistant, entry: ConfigEntry, client: MozartClient
42  ) -> None:
43  """Initialize the WebSocket listeners."""
44 
45  BangOlufsenBase.__init__(self, entry, client)
46 
47  self.hasshass = hass
48  self._device_device = get_device(hass, self._unique_id)
49 
50  # WebSocket callbacks
51  self._client_client.get_notification_notifications(self.on_notification_notificationon_notification_notification)
52  self._client_client.get_on_connection_lost(self.on_connection_loston_connection_lost)
53  self._client_client.get_on_connection(self.on_connectionon_connection)
54  self._client_client.get_active_listening_mode_notifications(
55  self.on_active_listening_modeon_active_listening_mode
56  )
57  self._client_client.get_playback_error_notifications(
58  self.on_playback_error_notificationon_playback_error_notification
59  )
60  self._client_client.get_playback_metadata_notifications(
61  self.on_playback_metadata_notificationon_playback_metadata_notification
62  )
63  self._client_client.get_playback_progress_notifications(
64  self.on_playback_progress_notificationon_playback_progress_notification
65  )
66  self._client_client.get_playback_source_notifications(
67  self.on_playback_source_notificationon_playback_source_notification
68  )
69  self._client_client.get_playback_state_notifications(
70  self.on_playback_state_notificationon_playback_state_notification
71  )
72  self._client_client.get_software_update_state_notifications(
73  self.on_software_update_stateon_software_update_state
74  )
75  self._client_client.get_source_change_notifications(self.on_source_change_notificationon_source_change_notification)
76  self._client_client.get_volume_notifications(self.on_volume_notificationon_volume_notification)
77 
78  # Used for firing events and debugging
79  self._client_client.get_all_notifications_raw(self.on_all_notifications_rawon_all_notifications_raw)
80 
81  def _update_connection_status(self) -> None:
82  """Update all entities of the connection status."""
84  self.hasshass,
85  f"{self._unique_id}_{CONNECTION_STATUS}",
86  self._client_client.websocket_connected,
87  )
88 
89  def on_connection(self) -> None:
90  """Handle WebSocket connection made."""
91  _LOGGER.debug("Connected to the %s notification channel", self.entry.title)
92  self._update_connection_status_update_connection_status()
93 
94  def on_connection_lost(self) -> None:
95  """Handle WebSocket connection lost."""
96  _LOGGER.error("Lost connection to the %s", self.entry.title)
97  self._update_connection_status_update_connection_status()
98 
99  def on_active_listening_mode(self, notification: ListeningModeProps) -> None:
100  """Send active_listening_mode dispatch."""
102  self.hasshass,
103  f"{self._unique_id}_{WebsocketNotification.ACTIVE_LISTENING_MODE}",
104  notification,
105  )
106 
108  self, notification: WebsocketNotificationTag
109  ) -> None:
110  """Send notification dispatch."""
111  # Try to match the notification type with available WebsocketNotification members
112  notification_type = try_parse_enum(WebsocketNotification, notification.value)
113 
114  if notification_type in (
115  WebsocketNotification.BEOLINK_PEERS,
116  WebsocketNotification.BEOLINK_LISTENERS,
117  WebsocketNotification.BEOLINK_AVAILABLE_LISTENERS,
118  ):
120  self.hasshass,
121  f"{self._unique_id}_{WebsocketNotification.BEOLINK}",
122  )
123  elif notification_type is WebsocketNotification.CONFIGURATION:
125  self.hasshass,
126  f"{self._unique_id}_{WebsocketNotification.CONFIGURATION}",
127  )
128  elif notification_type is WebsocketNotification.REMOTE_MENU_CHANGED:
130  self.hasshass,
131  f"{self._unique_id}_{WebsocketNotification.REMOTE_MENU_CHANGED}",
132  )
133 
134  def on_playback_error_notification(self, notification: PlaybackError) -> None:
135  """Send playback_error dispatch."""
137  self.hasshass,
138  f"{self._unique_id}_{WebsocketNotification.PLAYBACK_ERROR}",
139  notification,
140  )
141 
143  self, notification: PlaybackContentMetadata
144  ) -> None:
145  """Send playback_metadata dispatch."""
147  self.hasshass,
148  f"{self._unique_id}_{WebsocketNotification.PLAYBACK_METADATA}",
149  notification,
150  )
151 
152  def on_playback_progress_notification(self, notification: PlaybackProgress) -> None:
153  """Send playback_progress dispatch."""
155  self.hasshass,
156  f"{self._unique_id}_{WebsocketNotification.PLAYBACK_PROGRESS}",
157  notification,
158  )
159 
160  def on_playback_state_notification(self, notification: RenderingState) -> None:
161  """Send playback_state dispatch."""
163  self.hasshass,
164  f"{self._unique_id}_{WebsocketNotification.PLAYBACK_STATE}",
165  notification,
166  )
167 
168  def on_playback_source_notification(self, notification: Source) -> None:
169  """Send playback_source dispatch."""
171  self.hasshass,
172  f"{self._unique_id}_{WebsocketNotification.PLAYBACK_SOURCE}",
173  notification,
174  )
175 
176  def on_source_change_notification(self, notification: Source) -> None:
177  """Send source_change dispatch."""
179  self.hasshass,
180  f"{self._unique_id}_{WebsocketNotification.SOURCE_CHANGE}",
181  notification,
182  )
183 
184  def on_volume_notification(self, notification: VolumeState) -> None:
185  """Send volume dispatch."""
187  self.hasshass,
188  f"{self._unique_id}_{WebsocketNotification.VOLUME}",
189  notification,
190  )
191 
192  async def on_software_update_state(self, notification: SoftwareUpdateState) -> None:
193  """Check device sw version."""
194  software_status = await self._client_client.get_softwareupdate_status()
195 
196  # Update the HA device if the sw version does not match
197  if software_status.software_version != self._device_device.sw_version:
198  device_registry = dr.async_get(self.hasshass)
199 
200  device_registry.async_update_device(
201  device_id=self._device_device.id,
202  sw_version=software_status.software_version,
203  )
204 
205  def on_all_notifications_raw(self, notification: BaseWebSocketResponse) -> None:
206  """Receive all notifications."""
207  debug_notification = {
208  "device_id": self._device_device.id,
209  "serial_number": int(self._unique_id),
210  **notification,
211  }
212 
213  _LOGGER.debug("%s", debug_notification)
214  self.hasshass.bus.async_fire(BANG_OLUFSEN_WEBSOCKET_EVENT, debug_notification)
None on_playback_error_notification(self, PlaybackError notification)
Definition: websocket.py:134
None on_active_listening_mode(self, ListeningModeProps notification)
Definition: websocket.py:99
None on_notification_notification(self, WebsocketNotificationTag notification)
Definition: websocket.py:109
None on_all_notifications_raw(self, BaseWebSocketResponse notification)
Definition: websocket.py:205
None on_software_update_state(self, SoftwareUpdateState notification)
Definition: websocket.py:192
None on_playback_metadata_notification(self, PlaybackContentMetadata notification)
Definition: websocket.py:144
None on_playback_state_notification(self, RenderingState notification)
Definition: websocket.py:160
None on_playback_progress_notification(self, PlaybackProgress notification)
Definition: websocket.py:152
None __init__(self, HomeAssistant hass, ConfigEntry entry, MozartClient client)
Definition: websocket.py:42
DeviceEntry get_device(HomeAssistant hass, str unique_id)
Definition: util.py:12
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
Definition: dispatcher.py:193