From 399571701cca72634bf9cd27b1bf03eb134e584b Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Sun, 27 Sep 2026 16:38:53 +0200 Subject: [PATCH] Remove songpal stop listener when the entity is removed (#183323) Co-authored-by: Claude --- .../components/songpal/media_player.py | 4 +++- tests/components/songpal/test_media_player.py | 24 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/songpal/media_player.py b/homeassistant/components/songpal/media_player.py index 35f50d4cb44f..5430589b4719 100644 --- a/homeassistant/components/songpal/media_player.py +++ b/homeassistant/components/songpal/media_player.py @@ -241,7 +241,9 @@ class SongpalEntity(MediaPlayerEntity): async def handle_stop(event): await self._dev.stop_listen_notifications() - self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, handle_stop) + self.async_on_remove( + self.hass.bus.async_listen(EVENT_HOMEASSISTANT_STOP, handle_stop) + ) entry.async_create_background_task( self.hass, self._dev.listen_notifications(), "songpal-listen-notifications" diff --git a/tests/components/songpal/test_media_player.py b/tests/components/songpal/test_media_player.py index c469109cc375..619cb3fcaf57 100644 --- a/tests/components/songpal/test_media_player.py +++ b/tests/components/songpal/test_media_player.py @@ -19,7 +19,12 @@ from homeassistant.components import media_player, songpal from homeassistant.components.media_player import MediaPlayerEntityFeature from homeassistant.components.songpal.const import ERROR_REQUEST_RETRY from homeassistant.components.songpal.services import SET_SOUND_SETTING -from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE +from homeassistant.const import ( + EVENT_HOMEASSISTANT_STOP, + STATE_OFF, + STATE_ON, + STATE_UNAVAILABLE, +) from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.setup import async_setup_component @@ -410,6 +415,23 @@ async def test_websocket_events(hass: HomeAssistant) -> None: assert hass.states.get(ENTITY_ID).state == STATE_OFF +async def test_stop_listener_removed_on_unload(hass: HomeAssistant) -> None: + """Test the stop listener is removed when the entity is removed.""" + mocked_device = _create_mocked_device() + entry = MockConfigEntry(domain=songpal.DOMAIN, data=CONF_DATA) + entry.add_to_hass(hass) + + with _patch_media_player_device(mocked_device): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + stop_listeners = hass.bus.async_listeners()[EVENT_HOMEASSISTANT_STOP] + + assert await hass.config_entries.async_unload(entry.entry_id) + await hass.async_block_till_done() + + assert hass.bus.async_listeners()[EVENT_HOMEASSISTANT_STOP] == stop_listeners - 1 + + async def test_disconnected( hass: HomeAssistant, caplog: pytest.LogCaptureFixture ) -> None: