postlund / pyatv

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

AppleTV not waking up #2369

Open billmoseley opened 2 months ago

billmoseley commented 2 months ago

Describe the bug

I'm running tvOS 17.3. atvremote -v 0.14.5

AppleTV is connected via ethernet to my switch. There is no wifi configured in the AppleTV.

I came here from the Home Assistant world where my automations to turn on my Apple TV have quit working. It appears the problem is the AppleTV goes to sleep and pyatv isn't or can't (or isn't designed to) wake up the device.

A caveat here is I don't know how any of the network internals work.

My wild, wild guess is that the AppleTV uses a non-standard wake-on-lan packet.

What I see happening is when I put AppleTV into "standby" mode (turn it off) I can still ping its IP address, and mostly during this time I can power it back on (using media_player.turn_on in Home Assistant).

But, after a few minutes (although the time seems to vary) pings to AppleTV start timing out.

Home Assistant reports the AppleTV as "unavailable" and can no longer use HA to turn on the AppleTV.

If I run atvremote the AppleTV does not show up:

(pyatv_venv) bill@whm4pro ~/dev/python $ atvremote wizard
Looking for devices...
Found the following devices:
    Name               Model           Address
--  -----------------  --------------  -------------
 1  whm4pro            MacBookPro18,3  192.168.0.17
 2  Kitchen            One             192.168.0.158
 3  Ann’s MacBook Air  Mac14,2         192.168.0.33
Enter index of device to set up (q to quit): q

I know the AppleTV remote is Bluetooth, and that will wake up the AppleTV and it does. What I find interesting is even with my iPhone's Bluetooth disabled it will (eventually) connect to the AppleTV.

In both cases as soon as I do that the pings to the AppleTV start returning again.

And when I run atvremote wizard the AppleTV will show up.

(pyatv_venv) bill@whm4pro ~/dev/python $ atvremote wizard
Looking for devices...
Found the following devices:
    Name                  Model           Address
--  --------------------  --------------  -------------
 1  whm4pro               MacBookPro18,3  192.168.0.17
 2  Kitchen               One             192.168.0.158
 3  Apple TV Family Room  Apple TV 4K     192.168.0.25
 4  Ann’s MacBook Air     Mac14,2         192.168.0.33

Considering my iPhone's Bluetooth is turned off, I would assume there's some wake-on-lan that is waking up the AppleTV.

Now, I tried the homebrew (Perl) wakeonlan script targeting the AppleTV's MAC address when the pings were timing out but that didn't cause the AppleTV to start responding to pings.

Again, it's a bit odd, because the number of pings (how long) before it starts timing out really varies. I do not think it's related to my local network (TP Link Omada). And the pings will stop and then start up again. But if I wait long enough the pings start reporting no route to host.

64 bytes from 192.168.0.25: icmp_seq=724 ttl=64 time=4.604 ms
64 bytes from 192.168.0.25: icmp_seq=725 ttl=64 time=148.964 ms
64 bytes from 192.168.0.25: icmp_seq=726 ttl=64 time=219.736 ms
64 bytes from 192.168.0.25: icmp_seq=727 ttl=64 time=7.435 ms
64 bytes from 192.168.0.25: icmp_seq=728 ttl=64 time=5.285 ms
64 bytes from 192.168.0.25: icmp_seq=729 ttl=64 time=3.235 ms
64 bytes from 192.168.0.25: icmp_seq=730 ttl=64 time=6.799 ms
64 bytes from 192.168.0.25: icmp_seq=731 ttl=64 time=3.071 ms
64 bytes from 192.168.0.25: icmp_seq=732 ttl=64 time=3.568 ms
Request timeout for icmp_seq 733
Request timeout for icmp_seq 734
Request timeout for icmp_seq 735
Request timeout for icmp_seq 736
64 bytes from 192.168.0.25: icmp_seq=737 ttl=32 time=162.981 ms
64 bytes from 192.168.0.25: icmp_seq=738 ttl=32 time=4.824 ms
64 bytes from 192.168.0.25: icmp_seq=739 ttl=32 time=4.814 ms
64 bytes from 192.168.0.25: icmp_seq=740 ttl=32 time=6.819 ms
64 bytes from 192.168.0.25: icmp_seq=741 ttl=32 time=25.029 ms
64 bytes from 192.168.0.25: icmp_seq=742 ttl=32 time=7.165 ms
Request timeout for icmp_seq 743
Request timeout for icmp_seq 744
Request timeout for icmp_seq 745
Request timeout for icmp_seq 746
Request timeout for icmp_seq 747
Request timeout for icmp_seq 748
Request timeout for icmp_seq 749
Request timeout for icmp_seq 750
Request timeout for icmp_seq 751
64 bytes from 192.168.0.25: icmp_seq=752 ttl=64 time=8.633 ms
64 bytes from 192.168.0.25: icmp_seq=753 ttl=64 time=34.571 ms
64 bytes from 192.168.0.25: icmp_seq=754 ttl=64 time=4.666 ms
64 bytes from 192.168.0.25: icmp_seq=755 ttl=64 time=5.026 ms
64 bytes from 192.168.0.25: icmp_seq=756 ttl=64 time=5.964 ms
64 bytes from 192.168.0.25: icmp_seq=757 ttl=64 time=13.305 ms
64 bytes from 192.168.0.25: icmp_seq=758 ttl=64 time=60.851 ms

and later (yes, I restarted ping so sequence started over).

Request timeout for icmp_seq 215
Request timeout for icmp_seq 216
Request timeout for icmp_seq 217
Request timeout for icmp_seq 218
Request timeout for icmp_seq 219
Request timeout for icmp_seq 220
Request timeout for icmp_seq 221
ping: sendto: No route to host
Request timeout for icmp_seq 222
ping: sendto: Host is down
Request timeout for icmp_seq 223
ping: sendto: Host is down
Request timeout for icmp_seq 224
ping: sendto: Host is down
Request timeout for icmp_seq 225
ping: sendto: Host is down

Error log

No response

How to reproduce the bug?

Place the AppleTV in suspend mode and wait for it to no longer return pings.

What is expected behavior?

To be able to connect to AppleTV, and power it on after it's been turned off.

Operating System

MacOS

Python

3.6

pyatv

0.14.5

Device

tvOS 17.3

Additional context

I'm not sure when this stopped working. I just noticed a few months ago trying to use Home Assistant to turn on AppleTV and it didn't turn on. I would just use the AppleTV remote and watch my movie.

billmoseley commented 1 month ago

Is anyone else seeing this behavior? Is it new for this version of tvOS?

It seems like Apple TV goes to sleep and the socket is closed and pyatv doesn't or can't reconnect. Again, since Airplay can wake up Apple TV I'm wondering if there's something like a wake-on-lan that needs to be sent?

Here's logs I'm seeing in Home Assistant.

2024-03-24 13:56:46.872 WARNING (MainThread) [homeassistant.components.apple_tv] Connection lost to Apple TV "Apple TV Family Room"
2024-03-24 13:58:00.633 ERROR (MainThread) [pyatv.protocols.airplay] Failed to set up remote control channel
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/airplay/__init__.py", line 348, in _connect_rc
    await session.connect()
  File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/airplay/ap2_session.py", line 69, in connect
    self.connection = await http_connect(self._address, self._control_port)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/pyatv/support/http.py", line 653, in http_connect
    _, connection = await loop.create_connection(HttpConnection, address, port)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1120, in create_connection
    raise exceptions[0]
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1102, in create_connection
    sock = await self._connect_sock(
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1005, in _connect_sock
    await self.sock_connect(sock, address)
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 641, in sock_connect
    return await fut
           ^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 681, in _sock_connect_cb
    raise OSError(err, f'Connect call failed {address}')
OSError: [Errno 113] Connect call failed ('192.168.0.25', 7000)
2024-03-24 13:58:03.706 ERROR (MainThread) [homeassistant.components.apple_tv] Failed to connect
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/apple_tv/__init__.py", line 273, in connect_once
    await self._connect_once(raise_missing_credentials)
  File "/usr/src/homeassistant/homeassistant/components/apple_tv/__init__.py", line 258, in _connect_once
    await self._connect(conf, raise_missing_credentials)
  File "/usr/src/homeassistant/homeassistant/components/apple_tv/__init__.py", line 378, in _connect
    self.atv = await connect(conf, self.hass.loop, session=session)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/pyatv/__init__.py", line 155, in connect
    await atv.connect()
  File "/usr/local/lib/python3.12/site-packages/pyatv/core/facade.py", line 684, in connect
    if await setup_data.connect():
       ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/companion/__init__.py", line 571, in _connect
    await api.connect()
  File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/companion/api.py", line 143, in connect
    await self._protocol.start()
  File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/companion/protocol.py", line 101, in start
    await self.connection.connect()
  File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/companion/connection.py", line 80, in connect
    await self.loop.create_connection(lambda: self, self.host, self.port)
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1120, in create_connection
    raise exceptions[0]
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1102, in create_connection
    sock = await self._connect_sock(
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/base_events.py", line 1005, in _connect_sock
    await self.sock_connect(sock, address)
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 641, in sock_connect
    return await fut
           ^^^^^^^^^
  File "/usr/local/lib/python3.12/asyncio/selector_events.py", line 681, in _sock_connect_cb
    raise OSError(err, f'Connect call failed {address}')
OSError: [Errno 113] Connect call failed ('192.168.0.25', 49153)

Thanks,

frank2604 commented 1 month ago

I think the same issue here with two Apple TVs:

`Logger: homeassistant.components.apple_tv Quelle: components/apple_tv/init.py:206 Integration: Apple TV (Dokumentation, Probleme) Erstmals aufgetreten: 26. März 2024 um 20:11:23 (174 Vorkommnisse) Zuletzt protokolliert: 10:10:53

Connection lost to Apple TV "Essbereich" Connection lost to Apple TV "Wohnzimmer"`

`Logger: homeassistant.components.apple_tv Quelle: components/apple_tv/init.py:273 Integration: Apple TV (Dokumentation, Probleme) Erstmals aufgetreten: 26. März 2024 um 20:13:46 (5 Vorkommnisse) Zuletzt protokolliert: 10:12:18

Failed to connect Traceback (most recent call last): File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/mrp/protocol.py", line 275, in _receive await semaphore.acquire() File "/usr/local/lib/python3.12/asyncio/locks.py", line 386, in acquire await fut asyncio.exceptions.CancelledError

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/components/apple_tv/init.py", line 273, in connect_once await self._connect_once(raise_missing_credentials) File "/usr/src/homeassistant/homeassistant/components/apple_tv/init.py", line 258, in _connect_once await self._connect(conf, raise_missing_credentials) File "/usr/src/homeassistant/homeassistant/components/apple_tv/init.py", line 378, in _connect self.atv = await connect(conf, self.hass.loop, session=session) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/site-packages/pyatv/init.py", line 155, in connect await atv.connect() File "/usr/local/lib/python3.12/site-packages/pyatv/core/facade.py", line 684, in connect if await setup_data.connect(): ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/mrp/init.py", line 1092, in _connect await protocol.start() File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/mrp/protocol.py", line 146, in start self.device_info = await self.send_and_receive( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/mrp/protocol.py", line 262, in send_and_receive return await self._receive(identifier, timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/site-packages/pyatv/protocols/mrp/protocol.py", line 274, in _receive async with async_timeout.timeout(timeout): File "/usr/local/lib/python3.12/site-packages/async_timeout/init.py", line 141, in aexit self._do_exit(exc_type) File "/usr/local/lib/python3.12/site-packages/async_timeout/init.py", line 228, in _do_exit raise asyncio.TimeoutError TimeoutError `