diff --git a/homeassistant/components/sonos/diagnostics.py b/homeassistant/components/sonos/diagnostics.py index e2949b8689c..6d5a7fff7a1 100644 --- a/homeassistant/components/sonos/diagnostics.py +++ b/homeassistant/components/sonos/diagnostics.py @@ -21,20 +21,24 @@ MEDIA_DIAGNOSTIC_ATTRIBUTES = ( "source_name", "title", "uri", - "_last_event_variables", ) SPEAKER_DIAGNOSTIC_ATTRIBUTES = ( "available", "battery_info", + "hardware_version", "household_id", "is_coordinator", "model_name", + "model_number", + "software_version", "sonos_group_entities", "subscription_address", "subscriptions_failed", + "version", "zone_name", "_group_members_missing", "_last_activity", + "_last_event_cache", ) @@ -52,8 +56,7 @@ async def async_get_config_entry_diagnostics( continue for key, value in data.items(): if isinstance(value, SonosSpeaker): - speaker_info = await async_generate_speaker_info(hass, value) - payload[section][key] = speaker_info + payload[section][key] = await async_generate_speaker_info(hass, value) else: payload[section][key] = value @@ -66,21 +69,8 @@ async def async_generate_media_info( """Generate a diagnostic payload for current media metadata.""" payload = {} - def get_contents(item): - if isinstance(item, (int, float, str)): - return item - if isinstance(item, dict): - payload = {} - for key, value in item.items(): - payload[key] = get_contents(value) - return payload - if hasattr(item, "__dict__"): - return vars(item) - return item - for attrib in MEDIA_DIAGNOSTIC_ATTRIBUTES: - value = getattr(speaker.media, attrib) - payload[attrib] = get_contents(value) + payload[attrib] = getattr(speaker.media, attrib) def poll_current_track_info(): return speaker.soco.avTransport.GetPositionInfo( @@ -99,7 +89,22 @@ async def async_generate_speaker_info( ) -> dict[str, Any]: """Generate the diagnostic payload for a specific speaker.""" payload = {} + + def get_contents(item): + if isinstance(item, (int, float, str)): + return item + if isinstance(item, dict): + payload = {} + for key, value in item.items(): + payload[key] = get_contents(value) + return payload + if hasattr(item, "__dict__"): + return vars(item) + return item + for attrib in SPEAKER_DIAGNOSTIC_ATTRIBUTES: - payload[attrib] = getattr(speaker, attrib) + value = getattr(speaker, attrib) + payload[attrib] = get_contents(value) + payload["media"] = await async_generate_media_info(hass, speaker) return payload diff --git a/homeassistant/components/sonos/speaker.py b/homeassistant/components/sonos/speaker.py index cf829a890e0..ac5a07f2204 100644 --- a/homeassistant/components/sonos/speaker.py +++ b/homeassistant/components/sonos/speaker.py @@ -123,7 +123,6 @@ class SonosMedia: self.position: float | None = None self.position_updated_at: datetime.datetime | None = None - self._last_event_variables: dict[str, Any] | None = None def clear(self) -> None: """Clear basic media info.""" @@ -164,6 +163,7 @@ class SonosSpeaker: self._resubscription_lock: asyncio.Lock | None = None self._event_dispatchers: dict[str, Callable] = {} self._last_activity: float = NEVER_TIME + self._last_event_cache: dict[str, Any] = {} # Scheduled callback handles self._poll_timer: Callable | None = None @@ -172,8 +172,11 @@ class SonosSpeaker: self.dispatchers: list[Callable] = [] # Device information + self.hardware_version = speaker_info["hardware_version"] + self.software_version = speaker_info["software_version"] self.mac_address = speaker_info["mac_address"] self.model_name = speaker_info["model_name"] + self.model_number = speaker_info["model_number"] self.uid = speaker_info["uid"] self.version = speaker_info["display_version"] self.zone_name = speaker_info["zone_name"] @@ -427,6 +430,9 @@ class SonosSpeaker: dispatcher = self._event_dispatchers[event.service.service_type] dispatcher(event) + # Save most recent event variables for diagnostics + self._last_event_cache[event.service.service_type] = event.variables + @callback def async_dispatch_alarms(self, event: SonosEvent) -> None: """Add the soco instance associated with the event to the callback.""" @@ -1003,12 +1009,6 @@ class SonosSpeaker: if new_status == SONOS_STATE_TRANSITIONING: return - if variables: - # Store for diagnostics - self.media._last_event_variables = ( # pylint: disable=protected-access - variables - ) - self.media.clear() update_position = new_status != self.media.playback_status self.media.playback_status = new_status diff --git a/tests/components/sonos/conftest.py b/tests/components/sonos/conftest.py index a35eee1c1b3..2da2d79ba99 100644 --- a/tests/components/sonos/conftest.py +++ b/tests/components/sonos/conftest.py @@ -206,6 +206,8 @@ def speaker_info_fixture(): "zone_name": "Zone A", "uid": "RINCON_test", "model_name": "Model Name", + "model_number": "S12", + "hardware_version": "1.20.1.6-1.1", "software_version": "49.2-64250", "mac_address": "00-11-22-33-44-55", "display_version": "13.1",