sebbo2002 / node-pyatv

A lightweight node.js wrapper around pyatv…
MIT License
26 stars 2 forks source link

bug when scanning using unicast #324

Closed maxileith closed 1 month ago

maxileith commented 1 month ago

Hi, it's me again.

So on my homebridge-appletv-enhanced plugin I always had coming in a few issues regarding a specific error:

[5/18/2024, 4:20:20 PM] [Apple TV Enhanced] [E] Platform: Error: Unable to parse result U json: SyntaxError: Unexpected non-whitespace character after JSON at position 1504

Now, I got my hand on verbose logs from a user who has these problems: https://github.com/maxileith/homebridge-appletv-enhanced/issues/407 (you can read the original logs in the attatchment of this issue). In verbose log, my plugin prints debug messages from your library and therefore it is easy to dig into it.

So the user has configured the plugin in a way that it does unicast discovery: Your library then executes the following atvscript command:

[5/18/2024, 4:20:12 PM] [Apple TV Enhanced] [V] CustomPyATVInstance: [node-pyatv][U] /var/lib/homebridge/appletv-enhanced/.venv/bin/atvscript -s 10.0.0.30,10.0.0.229,10.0.0.79,10.0.0.20,10.0.0.156,10.0.0.232 scan

So far so good. However, the atvscript then returns instead of a single JSON line three lines with the individual JSONs which your library simply does not expext:

{"result": "failure", "datetime": "2024-05-18T16:20:18.103087-06:00", "error": "Task exception was never retrieved", "exception": "[Errno 113] Connect call failed ('10.0.0.232', 32498)", "stacktrace": "Traceback (most recent call last):\n  File \"/var/lib/homebridge/appletv-enhanced/.venv/lib/python3.11/site-packages/pyatv/support/knock.py\", line 28, in _async_knock\n    _, writer = await asyncio.wait_for(\n                ^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/lib/python3.11/asyncio/tasks.py\", line 479, in wait_for\n    return fut.result()\n           ^^^^^^^^^^^^\n  File \"/usr/lib/python3.11/asyncio/streams.py\", line 48, in open_connection\n    transport, _ = await loop.create_connection(\n                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/lib/python3.11/asyncio/base_events.py\", line 1085, in create_connection\n    raise exceptions[0]\n  File \"/usr/lib/python3.11/asyncio/base_events.py\", line 1069, in create_connection\n    sock = await self._connect_sock(\n           ^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/lib/python3.11/asyncio/base_events.py\", line 973, in _connect_sock\n    await self.sock_connect(sock, address)\n  File \"/usr/lib/python3.11/asyncio/selector_events.py\", line 634, in sock_connect\n    return await fut\n           ^^^^^^^^^\n  File \"/usr/lib/python3.11/asyncio/selector_events.py\", line 674, in _sock_connect_cb\n    raise OSError(err, f'Connect call failed {address}')\nOSError: [Errno 113] Connect call failed ('10.0.0.232', 32498)\n"}
{"result": "failure", "datetime": "2024-05-18T16:20:18.114744-06:00", "error": "Task exception was never retrieved", "exception": "[Errno 113] Connect call failed ('10.0.0.229', 32498)", "stacktrace": "Traceback (most recent call last):\n  File \"/var/lib/homebridge/appletv-enhanced/.venv/lib/python3.11/site-packages/pyatv/support/knock.py\", line 28, in _async_knock\n    _, writer = await asyncio.wait_for(\n                ^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/lib/python3.11/asyncio/tasks.py\", line 479, in wait_for\n    return fut.result()\n           ^^^^^^^^^^^^\n  File \"/usr/lib/python3.11/asyncio/streams.py\", line 48, in open_connection\n    transport, _ = await loop.create_connection(\n                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/lib/python3.11/asyncio/base_events.py\", line 1085, in create_connection\n    raise exceptions[0]\n  File \"/usr/lib/python3.11/asyncio/base_events.py\", line 1069, in create_connection\n    sock = await self._connect_sock(\n           ^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"/usr/lib/python3.11/asyncio/base_events.py\", line 973, in _connect_sock\n    await self.sock_connect(sock, address)\n  File \"/usr/lib/python3.11/asyncio/selector_events.py\", line 634, in sock_connect\n    return await fut\n           ^^^^^^^^^\n  File \"/usr/lib/python3.11/asyncio/selector_events.py\", line 674, in _sock_connect_cb\n    raise OSError(err, f'Connect call failed {address}')\nOSError: [Errno 113] Connect call failed ('10.0.0.229', 32498)\n"}
{"result": "success", "datetime": "2024-05-18T16:20:20.042648-06:00", "devices": [{"name": "Living Room", "address": "10.0.0.30", "identifier": "37323C0E-99E6-4CC3-A006-1ED5368FFF8C", "all_identifiers": ["86B730B2-5189-4B6A-BCAA-CDDB18F05FA8", "C8:D0:83:E9:D0:49", "37323C0E-99E6-4CC3-A006-1ED5368FFF8C", "C8D083E9D049"], "device_info": {"mac": "C8:D0:83:E9:D0:49", "model": "Gen4K", "model_str": "Apple TV 4K", "operating_system": "TvOS", "version": "17.5"}, "services": [{"protocol": "companion", "port": 49153}, {"protocol": "airplay", "port": 7000}, {"protocol": "mrp", "port": 49154}, {"protocol": "raop", "port": 7000}]}, {"name": "Kitchen", "address": "10.0.0.79", "identifier": "45B6A67A-9FAD-497D-95EF-7FC5ECB3371C", "all_identifiers": ["B163C908-000F-4983-BDC7-BEFD76887EF5", "C8:69:CD:63:2A:11", "45B6A67A-9FAD-497D-95EF-7FC5ECB3371C", "C869CD632A11"], "device_info": {"mac": "C8:69:CD:63:2A:11", "model": "Gen4", "model_str": "Apple TV 4", "operating_system": "TvOS", "version": "17.4"}, "services": [{"protocol": "companion", "port": 49153}, {"protocol": "airplay", "port": 7000}, {"protocol": "mrp", "port": 49157}, {"protocol": "raop", "port": 7000}]}, {"name": "Bedroom", "address": "10.0.0.20", "identifier": "CA55DA36-ADEF-4DBC-A0B3-BA68B0C53E40", "all_identifiers": ["08:66:98:BC:37:1F", "108F35A0-FF21-4884-96C2-145AAAB1B4C4", "CA55DA36-ADEF-4DBC-A0B3-BA68B0C53E40", "086698BC371F"], "device_info": {"mac": "08:66:98:BC:37:1F", "model": "Gen4", "model_str": "Apple TV 4", "operating_system": "TvOS", "version": "17.4"}, "services": [{"protocol": "airplay", "port": 7000}, {"protocol": "companion", "port": 49153}, {"protocol": "mrp", "port": 49154}, {"protocol": "raop", "port": 7000}]}, {"name": "Basement", "address": "10.0.0.156", "identifier": "C02B27DB-2AF3-43E7-8EF7-885E1E9AB3B4", "all_identifiers": ["8BDB6773-479F-4C01-A185-29FF5516F2C2", "D0:03:4B:4C:2A:2E", "C02B27DB-2AF3-43E7-8EF7-885E1E9AB3B4", "D0034B4C2A2E"], "device_info": {"mac": "D0:03:4B:4C:2A:2E", "model": "Gen4", "model_str": "Apple TV 4", "operating_system": "TvOS", "version": "17.4"}, "services": [{"protocol": "companion", "port": 49153}, {"protocol": "airplay", "port": 7000}, {"protocol": "mrp", "port": 49154}, {"protocol": "raop", "port": 7000}]}]}

So 2 of the 6 unicast scans were unsuccesful. The atvscript return a seperate json for each error and one single json for all successful scans. As the lib does not expect that it throws the following error:

[5/18/2024, 4:20:20 PM] [Apple TV Enhanced] [V] CustomPyATVInstance: [node-pyatv][U] /var/lib/homebridge/appletv-enhanced/.venv/bin/atvscript exited with code: 0
[5/18/2024, 4:20:20 PM] [Apple TV Enhanced] [V] CustomPyATVInstance: [node-pyatv][U] Unable to parse result U json: SyntaxError: Unexpected non-whitespace character after JSON at position 1504

Position 1504 is the line break after the first JSON in line 1 of 3.

So what I basically need, is that the library does not throw an error and parses the successful scans correctly. On top I need a list of errors so that I can output that in my plugin. Would that be feasible?

A workaround I could imagine would be to do call the find method for each Host individually ...

Thanks in advance and thank you for the lib :)

sebbo2002 commented 1 month ago

:tada: This issue has been resolved in version 7.4.0-develop.1 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

sebbo2002 commented 1 month ago

Fix is on it's way. You get the errors as well if you set the second parameter in find to true:

const result = await pyatv.find({}, true);
console.log(result.devices);
console.log(result.errors);

Give it a try and let me know if that solves the problem. And thank you for the ticket, it was excellent. It contains everything I required. 👍🏼

maxileith commented 1 month ago

Thanks for the fast response. Would it be possible to export the NodePyATVFindResponseObject interfcae, so I can reference that interface?

sebbo2002 commented 1 month ago

I knew I had forgotten something. Fix is on its way...

maxileith commented 1 month ago

I knew I had forgotten something. Fix is on its way...

When will this be available in a prerelease version?

sebbo2002 commented 1 month ago

:tada: This issue has been resolved in version 7.4.0-develop.2 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

sebbo2002 commented 1 month ago

Sorry, now it's there…