Home Assistant Unofficial Reference 2024.12.1
diagnostics.py
Go to the documentation of this file.
1 """Provides diagnostics for Sonos."""
2 
3 from __future__ import annotations
4 
5 import time
6 from typing import Any
7 
8 from homeassistant.config_entries import ConfigEntry
9 from homeassistant.core import HomeAssistant
10 from homeassistant.helpers.device_registry import DeviceEntry
11 
12 from .const import DATA_SONOS, DOMAIN
13 from .speaker import SonosSpeaker
14 
15 MEDIA_DIAGNOSTIC_ATTRIBUTES = (
16  "album_name",
17  "artist",
18  "channel",
19  "duration",
20  "image_url",
21  "queue_position",
22  "playlist_name",
23  "source_name",
24  "title",
25  "uri",
26 )
27 SPEAKER_DIAGNOSTIC_ATTRIBUTES = (
28  "available",
29  "battery_info",
30  "hardware_version",
31  "household_id",
32  "is_coordinator",
33  "model_name",
34  "model_number",
35  "software_version",
36  "sonos_group_entities",
37  "subscription_address",
38  "subscriptions_failed",
39  "version",
40  "zone_name",
41  "_group_members_missing",
42  "_last_activity",
43  "_last_event_cache",
44 )
45 
46 
48  hass: HomeAssistant, config_entry: ConfigEntry
49 ) -> dict[str, Any]:
50  """Return diagnostics for a config entry."""
51  payload: dict[str, Any] = {"current_timestamp": time.monotonic()}
52 
53  for section in ("discovered", "discovery_known"):
54  payload[section] = {}
55  data: set[Any] | dict[str, Any] = getattr(hass.data[DATA_SONOS], section)
56  if isinstance(data, set):
57  payload[section] = data
58  continue
59  for key, value in data.items():
60  if isinstance(value, SonosSpeaker):
61  payload[section][key] = await async_generate_speaker_info(hass, value)
62  else:
63  payload[section][key] = value
64  return payload
65 
66 
68  hass: HomeAssistant, config_entry: ConfigEntry, device: DeviceEntry
69 ) -> dict[str, Any]:
70  """Return diagnostics for a device."""
71  uid = next(
72  (identifier[1] for identifier in device.identifiers if identifier[0] == DOMAIN),
73  None,
74  )
75  if uid is None:
76  return {}
77 
78  if (speaker := hass.data[DATA_SONOS].discovered.get(uid)) is None:
79  return {}
80 
81  return await async_generate_speaker_info(hass, speaker)
82 
83 
85  hass: HomeAssistant, speaker: SonosSpeaker
86 ) -> dict[str, Any]:
87  """Generate a diagnostic payload for current media metadata."""
88  payload: dict[str, Any] = {}
89 
90  for attrib in MEDIA_DIAGNOSTIC_ATTRIBUTES:
91  payload[attrib] = getattr(speaker.media, attrib)
92 
93  def poll_current_track_info() -> dict[str, Any] | str:
94  try:
95  return speaker.soco.avTransport.GetPositionInfo(
96  [("InstanceID", 0), ("Channel", "Master")],
97  timeout=3,
98  )
99  except OSError as ex:
100  return f"Error retrieving: {ex}"
101 
102  payload["current_track_poll"] = await hass.async_add_executor_job(
103  poll_current_track_info
104  )
105 
106  return payload
107 
108 
110  hass: HomeAssistant, speaker: SonosSpeaker
111 ) -> dict[str, Any]:
112  """Generate the diagnostic payload for a specific speaker."""
113  payload: dict[str, Any] = {}
114 
115  def get_contents(
116  item: float | str | dict[str, Any],
117  ) -> int | float | str | dict[str, Any]:
118  if isinstance(item, (int, float, str)):
119  return item
120  if isinstance(item, dict):
121  payload = {}
122  for key, value in item.items():
123  payload[key] = get_contents(value)
124  return payload
125  if hasattr(item, "__dict__"):
126  return vars(item)
127  return item
128 
129  for attrib in SPEAKER_DIAGNOSTIC_ATTRIBUTES:
130  value = getattr(speaker, attrib)
131  payload[attrib] = get_contents(value)
132 
133  payload["enabled_entities"] = {
134  entity_id
135  for entity_id, s in hass.data[DATA_SONOS].entity_id_mappings.items()
136  if s is speaker
137  }
138  payload["media"] = await async_generate_media_info(hass, speaker)
139  payload["activity_stats"] = speaker.activity_stats.report()
140  payload["event_stats"] = speaker.event_stats.report()
141  payload["zone_group_state_stats"] = {
142  "processed": speaker.soco.zone_group_state.processed_count,
143  "total_requests": speaker.soco.zone_group_state.total_requests,
144  }
145  return payload
dict[str, Any] async_generate_speaker_info(HomeAssistant hass, SonosSpeaker speaker)
Definition: diagnostics.py:111
dict[str, Any] async_get_config_entry_diagnostics(HomeAssistant hass, ConfigEntry config_entry)
Definition: diagnostics.py:49
dict[str, Any] async_get_device_diagnostics(HomeAssistant hass, ConfigEntry config_entry, DeviceEntry device)
Definition: diagnostics.py:69
dict[str, Any] async_generate_media_info(HomeAssistant hass, SonosSpeaker speaker)
Definition: diagnostics.py:86