From e89d3d954f7cbca71ccd5d8d07b744aa1613eb76 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Sat, 28 Apr 2018 15:55:40 +0200 Subject: [PATCH 1/2] Attempt Cast Fix --- homeassistant/components/media_player/cast.py | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 632ab4214b819..0942a4c40938b 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -306,13 +306,17 @@ def async_cast_discovered(discover: ChromecastInfo): _LOGGER.debug("Discovered chromecast with same UUID: %s", discover) self.hass.async_add_job(self.async_set_cast_info(discover)) + async def stop(event): + await self.async_will_remove_from_hass() + async_dispatcher_connect(self.hass, SIGNAL_CAST_DISCOVERED, async_cast_discovered) + self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop) self.hass.async_add_job(self.async_set_cast_info(self._cast_info)) async def async_will_remove_from_hass(self) -> None: """Disconnect Chromecast object when removed.""" - self._async_disconnect() + await self._async_disconnect() if self._cast_info.uuid is not None: # Remove the entity from the added casts so that it can dynamically # be re-added again. @@ -328,7 +332,7 @@ async def async_set_cast_info(self, cast_info): if old_cast_info.host_port == cast_info.host_port: # Nothing connection-related updated return - self._async_disconnect() + await self._async_disconnect() # Failed connection will unfortunately never raise an exception, it # will instead just try connecting indefinitely. @@ -348,15 +352,17 @@ async def async_set_cast_info(self, cast_info): _LOGGER.debug("Connection successful!") self.async_schedule_update_ha_state() - @callback - def _async_disconnect(self): + async def _async_disconnect(self): """Disconnect Chromecast object if it is set.""" if self._chromecast is None: # Can't disconnect if not connected. return - _LOGGER.debug("Disconnecting from previous chromecast socket.") + _LOGGER.debug("Disconnecting from chromecast socket.") self._available = False - self._chromecast.disconnect(blocking=False) + self.async_schedule_update_ha_state() + + await self.hass.async_add_job(self._chromecast.disconnect) + # Invalidate some attributes self._chromecast = None self.cast_status = None @@ -365,6 +371,8 @@ def _async_disconnect(self): self._status_listener.invalidate() self._status_listener = None + self.async_schedule_update_ha_state() + # ========== Callbacks ========== def new_cast_status(self, cast_status): """Handle updates of the cast status.""" From 4db9f02a882ec34dfade82dad1c82a36b4bd22d0 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Mon, 30 Apr 2018 10:40:37 +0200 Subject: [PATCH 2/2] Cleanup --- homeassistant/components/media_player/cast.py | 12 +++++++----- tests/components/media_player/test_cast.py | 16 ++++++++++++---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/media_player/cast.py b/homeassistant/components/media_player/cast.py index 0942a4c40938b..a9bea9e4c1d13 100644 --- a/homeassistant/components/media_player/cast.py +++ b/homeassistant/components/media_player/cast.py @@ -306,12 +306,13 @@ def async_cast_discovered(discover: ChromecastInfo): _LOGGER.debug("Discovered chromecast with same UUID: %s", discover) self.hass.async_add_job(self.async_set_cast_info(discover)) - async def stop(event): - await self.async_will_remove_from_hass() + async def async_stop(event): + """Disconnect socket on Home Assistant stop.""" + await self._async_disconnect() async_dispatcher_connect(self.hass, SIGNAL_CAST_DISCOVERED, async_cast_discovered) - self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, stop) + self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_stop) self.hass.async_add_job(self.async_set_cast_info(self._cast_info)) async def async_will_remove_from_hass(self) -> None: @@ -368,8 +369,9 @@ async def _async_disconnect(self): self.cast_status = None self.media_status = None self.media_status_received = None - self._status_listener.invalidate() - self._status_listener = None + if self._status_listener is not None: + self._status_listener.invalidate() + self._status_listener = None self.async_schedule_update_ha_state() diff --git a/tests/components/media_player/test_cast.py b/tests/components/media_player/test_cast.py index ee69ec1c85d37..41cf6749b7158 100644 --- a/tests/components/media_player/test_cast.py +++ b/tests/components/media_player/test_cast.py @@ -346,8 +346,16 @@ async def test_switched_host(hass: HomeAssistantType): async_dispatcher_send(hass, cast.SIGNAL_CAST_DISCOVERED, changed) await hass.async_block_till_done() assert get_chromecast.call_count == 1 - chromecast.disconnect.assert_called_once_with(blocking=False) + assert chromecast.disconnect.call_count == 1 - hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP) - await hass.async_block_till_done() - chromecast.disconnect.assert_called_once_with(blocking=False) + +async def test_disconnect_on_stop(hass: HomeAssistantType): + """Test cast device disconnects socket on stop.""" + info = get_fake_chromecast_info() + + with patch('pychromecast.dial.get_device_status', return_value=info): + chromecast, _ = await async_setup_media_player_cast(hass, info) + + hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP) + await hass.async_block_till_done() + assert chromecast.disconnect.call_count == 1