diff --git a/homeassistant/components/cast/media_player.py b/homeassistant/components/cast/media_player.py index d65b61877ab2..8020a714eec6 100644 --- a/homeassistant/components/cast/media_player.py +++ b/homeassistant/components/cast/media_player.py @@ -191,6 +191,7 @@ class CastDevice: self._status_listener: CastStatusListener | None = None self._add_remove_handler: Callable[[], None] | None = None self._del_remove_handler: Callable[[], None] | None = None + self._stop_listener: Callable[[], None] | None = None self._name: str | None = None def _async_setup(self, name: str) -> None: @@ -202,7 +203,9 @@ class CastDevice: self._del_remove_handler = async_dispatcher_connect( self.hass, SIGNAL_CAST_REMOVED, self._async_cast_removed ) - self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self._async_stop) + self._stop_listener = self.hass.bus.async_listen( + EVENT_HOMEASSISTANT_STOP, self._async_stop + ) # async_create_background_task is used to avoid delaying # startup wrapup if the device # is discovered already during startup but then fails to respond @@ -226,6 +229,9 @@ class CastDevice: if self._del_remove_handler: self._del_remove_handler() self._del_remove_handler = None + if self._stop_listener: + self._stop_listener() + self._stop_listener = None async def _async_connect_to_chromecast(self): """Set up the chromecast object.""" diff --git a/tests/components/cast/test_media_player.py b/tests/components/cast/test_media_player.py index 9ed13f498221..bccb7daf162e 100644 --- a/tests/components/cast/test_media_player.py +++ b/tests/components/cast/test_media_player.py @@ -26,6 +26,7 @@ from homeassistant.components.cast.const import ( ) from homeassistant.components.cast.media_player import ChromecastInfo from homeassistant.components.media_player import ( + DOMAIN as MP_DOMAIN, BrowseMedia, MediaClass, MediaPlayerEntityFeature, @@ -2114,6 +2115,22 @@ async def test_disconnect_on_stop(hass: HomeAssistant) -> None: assert chromecast.disconnect.call_count == 1 +async def test_stop_listener_removed_with_entity(hass: HomeAssistant) -> None: + """Test the stop listener is removed when the entity is removed.""" + info = get_fake_chromecast_info() + await async_setup_media_player_cast(hass, info) + stop_listeners = hass.bus.async_listeners()[EVENT_HOMEASSISTANT_STOP] + + entity = hass.data[MP_DOMAIN].get_entity("media_player.speaker") + await entity.async_remove() + await hass.async_block_till_done() + + assert ( + hass.bus.async_listeners().get(EVENT_HOMEASSISTANT_STOP, 0) + == stop_listeners - 1 + ) + + async def test_entry_setup_no_config(hass: HomeAssistant) -> None: """Test deprecated empty yaml config..""" await async_setup_component(hass, DOMAIN, {})