-
-
Notifications
You must be signed in to change notification settings - Fork 37.4k
Avoid unnecessary cast state updates #13770
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| """The tests for the Cast Media player platform.""" | ||
| # pylint: disable=protected-access | ||
| import asyncio | ||
| import datetime as dt | ||
| from typing import Optional | ||
| from unittest.mock import patch, MagicMock, Mock | ||
| from uuid import UUID | ||
|
|
@@ -14,7 +15,8 @@ | |
| from homeassistant.const import EVENT_HOMEASSISTANT_STOP | ||
| from homeassistant.helpers.dispatcher import async_dispatcher_connect, \ | ||
| async_dispatcher_send | ||
| from homeassistant.components.media_player import cast | ||
| from homeassistant.components.media_player import cast, \ | ||
| ATTR_MEDIA_POSITION, ATTR_MEDIA_POSITION_UPDATED_AT | ||
| from homeassistant.setup import async_setup_component | ||
|
|
||
|
|
||
|
|
@@ -286,6 +288,8 @@ async def test_entity_media_states(hass: HomeAssistantType): | |
| assert entity.unique_id == full_info.uuid | ||
|
|
||
| media_status = MagicMock(images=None) | ||
| media_status.current_time = 0 | ||
| media_status.playback_rate = 1 | ||
| media_status.player_is_playing = True | ||
| entity.new_media_status(media_status) | ||
| await hass.async_block_till_done() | ||
|
|
@@ -320,6 +324,85 @@ async def test_entity_media_states(hass: HomeAssistantType): | |
| assert state.state == 'unknown' | ||
|
|
||
|
|
||
| async def test_entity_media_position(hass: HomeAssistantType): | ||
| """Test various entity media states.""" | ||
| info = get_fake_chromecast_info() | ||
| full_info = attr.evolve(info, model_name='google home', | ||
| friendly_name='Speaker', uuid=FakeUUID) | ||
|
|
||
| with patch('pychromecast.dial.get_device_status', | ||
| return_value=full_info): | ||
| chromecast, entity = await async_setup_media_player_cast(hass, info) | ||
|
|
||
| media_status = MagicMock(images=None) | ||
| media_status.current_time = 10 | ||
| media_status.playback_rate = 1 | ||
| media_status.player_is_playing = True | ||
| media_status.player_is_paused = False | ||
| media_status.player_is_idle = False | ||
| now = dt.datetime.now(dt.timezone.utc) | ||
| with patch('homeassistant.util.dt.utcnow', return_value=now): | ||
| entity.new_media_status(media_status) | ||
| await hass.async_block_till_done() | ||
| state = hass.states.get('media_player.speaker') | ||
| assert state.attributes[ATTR_MEDIA_POSITION] == 10 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION' |
||
| assert state.attributes[ATTR_MEDIA_POSITION_UPDATED_AT] == now | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION_UPDATED_AT' |
||
|
|
||
| media_status.current_time = 15 | ||
| now_plus_5 = now + dt.timedelta(seconds=5) | ||
| with patch('homeassistant.util.dt.utcnow', return_value=now_plus_5): | ||
| entity.new_media_status(media_status) | ||
| await hass.async_block_till_done() | ||
| state = hass.states.get('media_player.speaker') | ||
| assert state.attributes[ATTR_MEDIA_POSITION] == 10 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION' |
||
| assert state.attributes[ATTR_MEDIA_POSITION_UPDATED_AT] == now | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION_UPDATED_AT' |
||
|
|
||
| media_status.current_time = 20 | ||
| with patch('homeassistant.util.dt.utcnow', return_value=now_plus_5): | ||
| entity.new_media_status(media_status) | ||
| await hass.async_block_till_done() | ||
| state = hass.states.get('media_player.speaker') | ||
| assert state.attributes[ATTR_MEDIA_POSITION] == 20 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION' |
||
| assert state.attributes[ATTR_MEDIA_POSITION_UPDATED_AT] == now_plus_5 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION_UPDATED_AT' |
||
|
|
||
| media_status.current_time = 25 | ||
| now_plus_10 = now + dt.timedelta(seconds=10) | ||
| media_status.player_is_playing = False | ||
| media_status.player_is_paused = True | ||
| with patch('homeassistant.util.dt.utcnow', return_value=now_plus_10): | ||
| entity.new_media_status(media_status) | ||
| await hass.async_block_till_done() | ||
| state = hass.states.get('media_player.speaker') | ||
| assert state.attributes[ATTR_MEDIA_POSITION] == 25 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION' |
||
| assert state.attributes[ATTR_MEDIA_POSITION_UPDATED_AT] == now_plus_10 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION_UPDATED_AT' |
||
|
|
||
| now_plus_15 = now + dt.timedelta(seconds=15) | ||
| with patch('homeassistant.util.dt.utcnow', return_value=now_plus_15): | ||
| entity.new_media_status(media_status) | ||
| await hass.async_block_till_done() | ||
| state = hass.states.get('media_player.speaker') | ||
| assert state.attributes[ATTR_MEDIA_POSITION] == 25 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION' |
||
| assert state.attributes[ATTR_MEDIA_POSITION_UPDATED_AT] == now_plus_10 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION_UPDATED_AT' |
||
|
|
||
| media_status.current_time = 30 | ||
| now_plus_20 = now + dt.timedelta(seconds=20) | ||
| with patch('homeassistant.util.dt.utcnow', return_value=now_plus_20): | ||
| entity.new_media_status(media_status) | ||
| await hass.async_block_till_done() | ||
| state = hass.states.get('media_player.speaker') | ||
| assert state.attributes[ATTR_MEDIA_POSITION] == 30 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION' |
||
| assert state.attributes[ATTR_MEDIA_POSITION_UPDATED_AT] == now_plus_20 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'ATTR_MEDIA_POSITION_UPDATED_AT' |
||
|
|
||
| media_status.player_is_paused = False | ||
| media_status.player_is_idle = True | ||
| with patch('homeassistant.util.dt.utcnow', return_value=now_plus_20): | ||
| entity.new_media_status(media_status) | ||
| await hass.async_block_till_done() | ||
| state = hass.states.get('media_player.speaker') | ||
| assert ATTR_MEDIA_POSITION not in state.attributes | ||
| assert ATTR_MEDIA_POSITION_UPDATED_AT not in state.attributes | ||
|
|
||
|
|
||
| async def test_switched_host(hass: HomeAssistantType): | ||
| """Test cast device listens for changed hosts and disconnects old cast.""" | ||
| info = get_fake_chromecast_info() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dersger That shouldn't be an issue since the
MEDIA_STATUSpackage always contains thecurrentTimeattribute. At least that's the case with all apps I just tested: Spotify, YouTube and Netflix.However, there's a really weird thing going on: With the packets we receive when we manually poll the media status with
GET_STATUS. We don't get the actualcurrentTimein the track, but the current time from the last callback! So for example, if I pause and play a track at 30 seconds, we will first receiveMEDIA_STATUSpackages withcurrentTime = 30from the callback. But even 30 and 60 seconds later when manually poll the device,currentTimein the packet will still be 30 - even though it should be 60/90 by now.As there's no information from the cast packages about relative to which timestamp
currentTimeis measured, I think we can't really solve this problem :( So I'd say maybe remove the half-polling feature again?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ugggh. Can we distinguish between polling and non-polling updates?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the current pychromecast library, AFAIK not. We might be able to create two MediaControllers on two different cast socket "channels" (not actually new sockets, just IDs that identify a stream of packets), and use one of them for Push-Updates and the other one for polling updates. But that would probably just end up being a lot of spaghetti code :(