postlund / pyatv

A client library for Apple TV and AirPlay devices
https://pyatv.dev
MIT License
838 stars 91 forks source link

Re-raise TimeoutError when pairing #2242

Closed postlund closed 8 months ago

postlund commented 8 months ago

What to change?

Currently pyatv tries to be "smart" by catching more or less all exceptions that happens during pairing and connecting and just re-raises them as an AuthenticationError. In like 99% of the cases, that works just fine. Sometimes however a timeout occurs (for whatever reason), which is re-raised as AuthenticationError. IMHO, that exception should just be kept as is as it's not really a problem with the authentication.

Main reason for changing this is this case in Home Assistant:

Authentication failed for Vardagsrum, try reconfiguring device
Traceback (most recent call last):
  File "/usr/local/lib/python3.11/asyncio/tasks.py", line 490, in wait_for
    return fut.result()
           ^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/asyncio/locks.py", line 213, in wait
    await fut
asyncio.exceptions.CancelledError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/pyatv/protocols/companion/protocol.py", line 121, in _setup_encryption
    await pair_verifier.verify_credentials()
  File "/usr/local/lib/python3.11/site-packages/pyatv/protocols/companion/auth.py", line 135, in verify_credentials
    resp = await self.protocol.exchange_auth(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pyatv/protocols/companion/protocol.py", line 145, in exchange_auth
    return await self._exchange_generic_opack(frame_type, data, identifier, timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pyatv/protocols/companion/protocol.py", line 170, in _exchange_generic_opack
    unpacked_object = await self._queues[identifier].wait(timeout)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pyatv/support/collections.py", line 130, in wait
    await asyncio.wait_for(self._event.wait(), timeout)
  File "/usr/local/lib/python3.11/asyncio/tasks.py", line 492, in wait_for
    raise exceptions.TimeoutError() from exc
TimeoutError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/apple_tv/__init__.py", line 227, in connect_once
    await self._connect(conf, raise_missing_credentials)
  File "/usr/src/homeassistant/homeassistant/components/apple_tv/__init__.py", line 329, in _connect
    self.atv = await connect(conf, self.hass.loop, session=session)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pyatv/__init__.py", line 136, in connect
    await atv.connect()
  File "/usr/local/lib/python3.11/site-packages/pyatv/core/facade.py", line 681, in connect
    if await setup_data.connect():
       ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/site-packages/pyatv/protocols/companion/__init__.py", line 573, in _connect
    await api.connect()
  File "/usr/local/lib/python3.11/site-packages/pyatv/protocols/companion/api.py", line 143, in connect
    await self._protocol.start()
  File "/usr/local/lib/python3.11/site-packages/pyatv/protocols/companion/protocol.py", line 108, in start
    await self._setup_encryption()
  File "/usr/local/lib/python3.11/site-packages/pyatv/protocols/companion/protocol.py", line 127, in _setup_encryption
    raise exceptions.AuthenticationError(str(ex)) from ex
pyatv.exceptions.AuthenticationError

When an AuthenticationError is raised, the Apple TV integration will trigger a reconfiguration which is very annoying. Sometimes the connection will fail, but trying again will restore function again. So changing this would help a lot I think.

postlund commented 8 months ago

Fixed in #2246.