# Buggy code
async def async_update(self):
    """Get the latest details on a media player.

    Because media players spend the majority of time idle, an adaptive
    update should be used to avoid flooding Amazon focusing on known
    play states. An initial version included an update_devices call on
    every update. However, this quickly floods the network for every new
    device added. This should only call refresh() to call the AlexaAPI.
    """
    try:
        if not self.enabled:
            return
    except AttributeError:
        pass
    email = self._login.email
    if (
        self.entity_id is None  # Device has not initialized yet
        or email not in self.hass.data[DATA_ALEXAMEDIA]["accounts"]
        or self._login.session.closed
    ):
        return
    device = self.hass.data[DATA_ALEXAMEDIA]["accounts"][email]["devices"][
        "media_player"
    ][self.unique_id]
    seen_commands = (
        self.hass.data[DATA_ALEXAMEDIA]["accounts"][email]["websocket_commands"].keys()
        if "websocket_commands" in (self.hass.data[DATA_ALEXAMEDIA]["accounts"][email])
        else None
    )
    await self.refresh(  # pylint: disable=unexpected-keyword-arg
        device, no_throttle=True
    )
    websocket_enabled = self.hass.data[DATA_ALEXAMEDIA]["accounts"][email].get(
        "websocket"
    )
    if (
        self.state in [STATE_PLAYING]
        and
        #  only enable polling if websocket not connected
        (
            not websocket_enabled
            or not seen_commands
            or not (
                "PUSH_AUDIO_PLAYER_STATE" in seen_commands
                or "PUSH_MEDIA_CHANGE" in seen_commands
                or "PUSH_MEDIA_PROGRESS_CHANGE" in seen_commands
            )
        )
    ):
        self._should_poll = False  # disable polling since manual update
        if (
            self._last_update == 0
            or util.dt.as_timestamp(util.utcnow())
            - util.dt.as_timestamp(self._last_update)
            > PLAY_SCAN_INTERVAL
        ):
            _LOGGER.debug(
                "%s playing; scheduling update in %s seconds",
                self.name,
                PLAY_SCAN_INTERVAL,
            )
            async_call_later(
                self.hass,
                PLAY_SCAN_INTERVAL,
                lambda _: self.async_schedule_update_ha_state(force_refresh=True),
            )
    elif self._should_poll:  # Not playing, one last poll
        self._should_poll = False
        if not websocket_enabled:
            _LOGGER.debug(
                "Disabling polling and scheduling last update in 300 seconds for %s",
                self.name,
            )
            async_call_later(
                self.hass,
                300,
                lambda _: self.async_schedule_update_ha_state(force_refresh=True),
            )
        else:
            _LOGGER.debug("Disabling polling for %s", self.name)
    self._last_update = util.utcnow()
    self.async_schedule_update_ha_state()


# Traceback (RuntimeError)
2020-06-21 12:36:29 ERROR (MainThread) [alexapy.helpers] alexaapi.get_state((<alexapy.alexaapi.AlexaAPI object at 0xa8cddbd0>,), {}): An error occured accessing AlexaAPI: An exception of type RuntimeError occurred. Arguments:
('Session is closed',)
2020-06-21 12:36:29 ERROR (MainThread) [homeassistant.util.logging] Exception in _handle_event when dispatching 'alexa_media_a******e@g*******m': ({'player_state': {'destinationUserId': 'XXX', 'dopplerId': {'deviceType': 'AB72C64C86AW2', 'deviceSerialNumber': 'XXX'}, 'audioPlayerState': 'PLAYING', 'quality': None, 'error': False, 'errorMessage': None, 'mediaReferenceId': '78e56ac3-4ab4-4c85-86b4-3d9bb3f5ae60:6'}},)
Traceback (most recent call last):
File "/config/custom_components/alexa_media/media_player.py", line 369, in _handle_event
await self.async_update()
File "/config/custom_components/alexa_media/helpers.py", line 148, in wrapper
result = await func(*args, **kwargs)
File "/config/custom_components/alexa_media/media_player.py", line 802, in async_update
device, no_throttle=True
File "/config/custom_components/alexa_media/helpers.py", line 148, in wrapper
result = await func(*args, **kwargs)
File "/config/custom_components/alexa_media/media_player.py", line 545, in refresh
session = await self.alexa_api.get_state()
File "/usr/local/lib/python3.7/site-packages/alexapy/helpers.py", line 69, in wrapper
return await func(*args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/alexapy/alexaapi.py", line 761, in get_state
+ "&amp;screenWidth=2560"
File "/usr/local/lib/python3.7/site-packages/alexapy/alexaapi.py", line 122, in _get_request
return await self._request("get", uri, data)
File "/usr/local/lib/python3.7/site-packages/backoff/_async.py", line 133, in retry
ret = await target(*args, **kwargs)
File "/usr/local/lib/python3.7/site-packages/alexapy/alexaapi.py", line 93, in _request
ssl=self._login._ssl,
File "/usr/local/lib/python3.7/site-packages/alexapy/aiohttp/client.py", line 377, in _request
raise RuntimeError("Session is closed")
RuntimeError: Session is closed

# Fixed code
async def async_update(self):
    """Get the latest details on a media player.

    Because media players spend the majority of time idle, an adaptive
    update should be used to avoid flooding Amazon focusing on known
    play states. An initial version included an update_devices call on
    every update. However, this quickly floods the network for every new
    device added. This should only call refresh() to call the AlexaAPI.
    """
    self.check_login_changes()
    try:
        if not self.enabled:
            return
    except AttributeError:
        pass
    email = self._login.email
    if (
        self.entity_id is None  # Device has not initialized yet
        or email not in self.hass.data[DATA_ALEXAMEDIA]["accounts"]
        or self._login.session.closed
    ):
        return
    device = self.hass.data[DATA_ALEXAMEDIA]["accounts"][email]["devices"][
        "media_player"
    ][self.unique_id]
    seen_commands = (
        self.hass.data[DATA_ALEXAMEDIA]["accounts"][email]["websocket_commands"].keys()
        if "websocket_commands" in (self.hass.data[DATA_ALEXAMEDIA]["accounts"][email])
        else None
    )
    await self.refresh(  # pylint: disable=unexpected-keyword-arg
        device, no_throttle=True
    )
    websocket_enabled = self.hass.data[DATA_ALEXAMEDIA]["accounts"][email].get(
        "websocket"
    )
    if (
        self.state in [STATE_PLAYING]
        and
        #  only enable polling if websocket not connected
        (
            not websocket_enabled
            or not seen_commands
            or not (
                "PUSH_AUDIO_PLAYER_STATE" in seen_commands
                or "PUSH_MEDIA_CHANGE" in seen_commands
                or "PUSH_MEDIA_PROGRESS_CHANGE" in seen_commands
            )
        )
    ):
        self._should_poll = False  # disable polling since manual update
        if (
            self._last_update == 0
            or util.dt.as_timestamp(util.utcnow())
            - util.dt.as_timestamp(self._last_update)
            > PLAY_SCAN_INTERVAL
        ):
            _LOGGER.debug(
                "%s playing; scheduling update in %s seconds",
                self.name,
                PLAY_SCAN_INTERVAL,
            )
            async_call_later(
                self.hass,
                PLAY_SCAN_INTERVAL,
                lambda _: self.async_schedule_update_ha_state(force_refresh=True),
            )
    elif self._should_poll:  # Not playing, one last poll
        self._should_poll = False
        if not websocket_enabled:
            _LOGGER.debug(
                "Disabling polling and scheduling last update in 300 seconds for %s",
                self.name,
            )
            async_call_later(
                self.hass,
                300,
                lambda _: self.async_schedule_update_ha_state(force_refresh=True),
            )
        else:
            _LOGGER.debug("Disabling polling for %s", self.name)
    self._last_update = util.utcnow()
    self.async_schedule_update_ha_state()