Async help wanted! (Fire TV)

Background

I have a pull request (#17767) for HA that adds improved Fire TV support. It works by establishing an ADB connecting to the Fire TV using the python-adb library and polling the device.

The problem

The python-adb library has a limitation that if you issue too many ADB commands in short succession, it will “overload” the ADB connection and break it.

Current solution

In the HA component, for each device I have an attribute called _adb_lock, and I created a wrapper function for all ADB methods that I called adb_wrapper. The basic idea is to wait up to 5 seconds until _adb_lock is False and then issue the ADB command. Here is the code:

def adb_wrapper(func):
    """Wait if previous ADB commands haven't finished."""
    @functools.wraps(func)
    def _adb_wrapper(self, *args, **kwargs):
        attempts = 0
        while self._adb_lock and attempts < 5:
            attempts += 1
            time.sleep(1)

        if attempts == 5 and self._adb_lock:
            try:
                self._firetv.connect()
            except self._exceptions:
                _LOGGER.error('Failed to re-establish the ADB connection; '
                              'will re-attempt in the next update.')
                self._firetv._adb = None
                self._adb_lock = False
                return

        self._adb_lock = True
        try:
            returns = func(self, *args, **kwargs)
        except self._exceptions:
            returns = None
            _LOGGER.error('Failed to execute an ADB command; will attempt to '
                          're-establish the ADB connection in the next update')
            self._firetv._adb = None
        finally:
            self._adb_lock = False

        return returns

    return _adb_wrapper

Help wanted!!!

In order to get my pull request merged, I can’t use time.sleep. One option is to use asyncio for sleeping. However, given that the sleep function was a workaround in the first place, there might be a better way of using async to avoid running an ADB command before the previous one has finished. I haven’t used async before, so I don’t know it’s capabilities or how to use it. Help would be very much appreciated! Especially in the form of pull requests (either of the following repos will work)! :smiley:

My Home Assistant pull request branch: https://github.com/JeffLIrion/home-assistant/tree/dev-firetv-adb

My native Fire TV support repo: https://github.com/JeffLIrion/homeassistant_native_firetv

1 Like

When you say break it, I am wondering if it is related to the issue being discussed in the other thread?

Yeah, I think it’s the same. @caffeinatedmike has updated the latest version of that component to use this wrapper, so hopefully that will fix those issues. Now we just need to fix the wrapper!