Don't hang forever if manually added cast is down (#21565)

* Don't hang forever if manually added cast is down

* Adapt to pychromecast

* Do not set available until connected

* Update __init__.py

* Update requirements

* Lint, tests

* Fix tests
This commit is contained in:
emontnemery 2019-03-11 03:57:30 +01:00 committed by Paulus Schoutsen
parent fe1840f901
commit fc85b3fc5f
4 changed files with 16 additions and 20 deletions

View file

@ -2,7 +2,7 @@
from homeassistant import config_entries
from homeassistant.helpers import config_entry_flow
REQUIREMENTS = ['pychromecast==2.5.2']
REQUIREMENTS = ['pychromecast==3.0.0']
DOMAIN = 'cast'

View file

@ -257,6 +257,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
_async_setup_platform(hass, cfg, async_add_entities, None)
for cfg in config])
if any([task.exception() for task in done]):
exceptions = [task.exception() for task in done]
for exception in exceptions:
_LOGGER.debug("Failed to setup chromecast", exc_info=exception)
raise PlatformNotReady
@ -289,7 +292,7 @@ async def _async_setup_platform(hass: HomeAssistantType, config: ConfigType,
if cast_device is not None:
async_add_entities([cast_device])
remove_handler = async_dispatcher_connect(
async_dispatcher_connect(
hass, SIGNAL_CAST_DISCOVERED, async_cast_discovered)
# Re-play the callback for all past chromecasts, store the objects in
# a list to avoid concurrent modification resulting in exception.
@ -306,8 +309,6 @@ async def _async_setup_platform(hass: HomeAssistantType, config: ConfigType,
if info.friendly_name is None:
_LOGGER.debug("Cannot retrieve detail information for chromecast"
" %s, the device may not be online", info)
remove_handler()
raise PlatformNotReady
hass.async_add_job(_discover_chromecast, hass, info)
@ -477,16 +478,10 @@ class CastDevice(MediaPlayerDevice):
))
self._chromecast = chromecast
self._status_listener = CastStatusListener(self, chromecast)
# Initialise connection status as connected because we can only
# register the connection listener *after* the initial connection
# attempt. If the initial connection failed, we would never reach
# this code anyway.
self._available = True
self._available = False
self.cast_status = chromecast.status
self.media_status = chromecast.media_controller.status
_LOGGER.debug("[%s %s (%s:%s)] Connection successful!",
self.entity_id, self._cast_info.friendly_name,
self._cast_info.host, self._cast_info.port)
self._chromecast.start()
self.async_schedule_update_ha_state()
async def async_del_cast_info(self, cast_info):
@ -562,6 +557,10 @@ class CastDevice(MediaPlayerDevice):
self.entity_id, self._cast_info.friendly_name,
self._cast_info.host, self._cast_info.port,
connection_status.status)
info = self._cast_info
if info.friendly_name is None and not info.is_audio_group:
# We couldn't find friendly_name when the cast was added, retry
self._cast_info = _fill_out_missing_chromecast_info(info)
self._available = new_available
self.schedule_update_ha_state()

View file

@ -977,7 +977,7 @@ pycfdns==0.0.1
pychannels==1.0.0
# homeassistant.components.cast
pychromecast==2.5.2
pychromecast==3.0.0
# homeassistant.components.media_player.cmus
pycmus==0.1.1

View file

@ -222,13 +222,6 @@ async def test_normal_chromecast_not_starting_discovery(hass):
assert setup_discovery.call_count == 1
async def test_normal_raises_platform_not_ready(hass):
"""Test cast platform raises PlatformNotReady if HTTP dial fails."""
with patch('pychromecast.dial.get_device_status', return_value=None):
with pytest.raises(PlatformNotReady):
await async_setup_cast(hass, {'host': 'host1'})
async def test_replay_past_chromecasts(hass):
"""Test cast platform re-playing past chromecasts when adding new one."""
cast_group1 = get_fake_chromecast_info(host='host1', port=42)
@ -262,6 +255,10 @@ async def test_entity_media_states(hass: HomeAssistantType):
return_value=full_info):
chromecast, entity = await async_setup_media_player_cast(hass, info)
entity._available = True
entity.schedule_update_ha_state()
await hass.async_block_till_done()
state = hass.states.get('media_player.speaker')
assert state is not None
assert state.name == 'Speaker'