Reduce overhead to write dlna_dmr state (#113776)

* Reduce overhead to write dlna_dmr state

- Only update supported_features once per state write cycle
- Use a dict lookup for state

* useless dispatch

* fix tests

* remove unreachable code
pull/113854/head
J. Nick Koston 2024-03-19 15:13:34 -10:00 committed by GitHub
parent 02c1088596
commit 417b491b78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 20 deletions

View File

@ -57,6 +57,17 @@ _R = TypeVar("_R")
_P = ParamSpec("_P") _P = ParamSpec("_P")
_TRANSPORT_STATE_TO_MEDIA_PLAYER_STATE = {
TransportState.PLAYING: MediaPlayerState.PLAYING,
TransportState.TRANSITIONING: MediaPlayerState.PLAYING,
TransportState.PAUSED_PLAYBACK: MediaPlayerState.PAUSED,
TransportState.PAUSED_RECORDING: MediaPlayerState.PAUSED,
# Unable to map this state to anything reasonable, so it's "Unknown"
TransportState.VENDOR_DEFINED: None,
None: MediaPlayerState.ON,
}
def catch_request_errors( def catch_request_errors(
func: Callable[Concatenate[_DlnaDmrEntityT, _P], Awaitable[_R]], func: Callable[Concatenate[_DlnaDmrEntityT, _P], Awaitable[_R]],
) -> Callable[Concatenate[_DlnaDmrEntityT, _P], Coroutine[Any, Any, _R | None]]: ) -> Callable[Concatenate[_DlnaDmrEntityT, _P], Coroutine[Any, Any, _R | None]]:
@ -186,6 +197,7 @@ class DlnaDmrEntity(MediaPlayerEntity):
self._updated_registry: bool = False self._updated_registry: bool = False
self._config_entry = config_entry self._config_entry = config_entry
self._attr_device_info = dr.DeviceInfo(connections={(dr.CONNECTION_UPNP, udn)}) self._attr_device_info = dr.DeviceInfo(connections={(dr.CONNECTION_UPNP, udn)})
self._attr_supported_features = self._supported_features()
async def async_added_to_hass(self) -> None: async def async_added_to_hass(self) -> None:
"""Handle addition.""" """Handle addition."""
@ -345,6 +357,11 @@ class DlnaDmrEntity(MediaPlayerEntity):
# Device was de/re-connected, state might have changed # Device was de/re-connected, state might have changed
self.async_write_ha_state() self.async_write_ha_state()
def async_write_ha_state(self) -> None:
"""Write the state."""
self._attr_supported_features = self._supported_features()
super().async_write_ha_state()
async def _device_connect(self, location: str) -> None: async def _device_connect(self, location: str) -> None:
"""Connect to the device now that it's available.""" """Connect to the device now that it's available."""
_LOGGER.debug("Connecting to device at %s", location) _LOGGER.debug("Connecting to device at %s", location)
@ -491,6 +508,9 @@ class DlnaDmrEntity(MediaPlayerEntity):
finally: finally:
self.check_available = False self.check_available = False
# Supported features may have changed
self._attr_supported_features = self._supported_features()
def _on_event( def _on_event(
self, service: UpnpService, state_variables: Sequence[UpnpStateVariable] self, service: UpnpService, state_variables: Sequence[UpnpStateVariable]
) -> None: ) -> None:
@ -531,28 +551,13 @@ class DlnaDmrEntity(MediaPlayerEntity):
@property @property
def state(self) -> MediaPlayerState | None: def state(self) -> MediaPlayerState | None:
"""State of the player.""" """State of the player."""
if not self._device or not self.available: if not self._device:
return MediaPlayerState.OFF return MediaPlayerState.OFF
if self._device.transport_state is None: return _TRANSPORT_STATE_TO_MEDIA_PLAYER_STATE.get(
return MediaPlayerState.ON self._device.transport_state, MediaPlayerState.IDLE
if self._device.transport_state in ( )
TransportState.PLAYING,
TransportState.TRANSITIONING,
):
return MediaPlayerState.PLAYING
if self._device.transport_state in (
TransportState.PAUSED_PLAYBACK,
TransportState.PAUSED_RECORDING,
):
return MediaPlayerState.PAUSED
if self._device.transport_state == TransportState.VENDOR_DEFINED:
# Unable to map this state to anything reasonable, so it's "Unknown"
return None
return MediaPlayerState.IDLE def _supported_features(self) -> MediaPlayerEntityFeature:
@property
def supported_features(self) -> MediaPlayerEntityFeature:
"""Flag media player features that are supported at this moment. """Flag media player features that are supported at this moment.
Supported features may change as the device enters different states. Supported features may change as the device enters different states.

View File

@ -1009,6 +1009,7 @@ async def test_shuffle_repeat_modes(
dmr_device_mock.async_set_play_mode.reset_mock() dmr_device_mock.async_set_play_mode.reset_mock()
dmr_device_mock.play_mode = PlayMode.RANDOM dmr_device_mock.play_mode = PlayMode.RANDOM
dmr_device_mock.valid_play_modes = {PlayMode.SHUFFLE, PlayMode.RANDOM} dmr_device_mock.valid_play_modes = {PlayMode.SHUFFLE, PlayMode.RANDOM}
await get_attrs(hass, mock_entity_id)
await hass.services.async_call( await hass.services.async_call(
MP_DOMAIN, MP_DOMAIN,
ha_const.SERVICE_SHUFFLE_SET, ha_const.SERVICE_SHUFFLE_SET,
@ -1022,6 +1023,7 @@ async def test_shuffle_repeat_modes(
dmr_device_mock.async_set_play_mode.reset_mock() dmr_device_mock.async_set_play_mode.reset_mock()
dmr_device_mock.play_mode = PlayMode.RANDOM dmr_device_mock.play_mode = PlayMode.RANDOM
dmr_device_mock.valid_play_modes = {PlayMode.REPEAT_ONE, PlayMode.REPEAT_ALL} dmr_device_mock.valid_play_modes = {PlayMode.REPEAT_ONE, PlayMode.REPEAT_ALL}
await get_attrs(hass, mock_entity_id)
await hass.services.async_call( await hass.services.async_call(
MP_DOMAIN, MP_DOMAIN,
ha_const.SERVICE_REPEAT_SET, ha_const.SERVICE_REPEAT_SET,