node-pyatv icon indicating copy to clipboard operation
node-pyatv copied to clipboard

Support for pairing with a device

Open KotKarol opened this issue 6 months ago • 6 comments

Hi,

Is there a support for pairing with a device? After 1st connection using control methods like .down() throws an error of "not supported".

Should I pair the devices myself using atvremote?

Thanks for any help!

KotKarol avatar Sep 11 '25 10:09 KotKarol

No, manual pairing is required. Can you provide a full example with your code and output? Please also set debug: true for proper logging.

sebbo2002 avatar Sep 11 '25 17:09 sebbo2002

Hi, sorry for late reply!

This is a code snippet:

import pyatv, {
  NodePyATVDevice,
  NodePyATVDeviceEvent,
} from "@sebbo2002/node-pyatv";

let devices: NodePyATVDevice[] = [];
let ipMacMap: { [key: string]: string } = {};
export async function init() {
  await pyatv.check();

  devices = await pyatv.find({ debug: true });
  if (!devices.length) {
    throw new Error("No devices found! :(");
  }

  devices.forEach(({ host, id }) => {
    if (!host || !id) return;
    ipMacMap[host] = id;
  });

  // Assume there is a device for tests.
  const device = devices[0]!;
  await device.up();
}

This is the log:

[node-pyatv][0] atvscript scan
[node-pyatv][0] stdout: {"result": "success", "datetime": "2025-10-06T13:40:50.833949+02:00", "devices": [{"name": "Pok\u00f3j dzienny", "address": "192.168.0.110", "identifier": "56:9B:79:04:6E:39", "all_identifiers": ["559B7904-6E39-4D02-9AE7-5C0DCA4A8C25", "56:9B:79:04:6E:39", "569B79046E39"], "device_info": {"mac": "56:9B:79:04:6E:39", "model": "AppleTV4KGen3", "model_str": "Apple TV 4K (gen 3)", "operating_system": "TvOS", "version": "26.0.1"}, "services": [{"protocol": "companion", "port": 49154}, {"protocol": "airplay", "port": 7000}, {"protocol": "raop", "port": 7000}]}, {"name": "MacBook Pro (Karol)", "address": "192.168.0.153", "identifier": "4A:4E:FD:FE:19:B6", "all_identifiers": ["4A:4E:FD:FE:19:B6", "4A4EFDFE19B6"], "device_info": {"mac": "4A:4E:FD:FE:19:B6", "model": "Unknown", "model_str": "Mac16,8", "operating_system": "MacOS", "version": null}, "services": [{"protocol": "airplay", "port": 7000}, {"protocol": "raop", "port": 7000}]}]}
[node-pyatv][0] atvscript exited with code: 0
[node-pyatv][59] atvscript -s 192.168.0.110 -i 56:9B:79:04:6E:39 up
[node-pyatv][59] stdout: {"result": "failure", "datetime": "2025-10-06T13:40:51.336846+02:00", "exception": "up is not supported", "stacktrace": "Traceback (most recent call last):\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\scripts\\atvscript.py\", line 395, in appstart\n    args.output(await _handle_command(args, abort_sem, storage, loop)),\n                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\scripts\\atvscript.py\", line 275, in _handle_command\n    return await _run_command(atv, args, abort_sem, loop)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\scripts\\atvscript.py\", line 315, in _run_command\n    await getattr(atv.remote_control, args.command)()\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\core\\facade.py\", line 52, in up\n    return await self.relay(\"up\")(action=action)\n                 ~~~~~~~~~~^^^^^^\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\core\\relayer.py\", line 91, in relay\n    instance = self._find_instance(\n        target, chain(self._takeover_protocol, priority or self._priorities)\n    )\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\core\\relayer.py\", line 115, in _find_instance\n    raise exceptions.NotSupportedError(f\"{target} is not supported\")\npyatv.exceptions.NotSupportedError: up is not supported\n"}
[node-pyatv][59] atvscript exited with code: 0
initRemoteController failed Error: Unable to parse pyatv response: {
  "result": "failure",
  "datetime": "2025-10-06T13:40:51.336846+02:00",
  "exception": "up is not supported",
  "stacktrace": "Traceback (most recent call last):\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\scripts\\atvscript.py\", line 395, in appstart\n    args.output(await _handle_command(args, abort_sem, storage, loop)),\n                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\scripts\\atvscript.py\", line 275, in _handle_command\n    return await _run_command(atv, args, abort_sem, loop)\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\scripts\\atvscript.py\", line 315, in _run_command\n    await getattr(atv.remote_control, args.command)()\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\core\\facade.py\", line 52, in up\n    return await self.relay(\"up\")(action=action)\n                 ~~~~~~~~~~^^^^^^\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\core\\relayer.py\", line 91, in relay\n    instance = self._find_instance(\n        target, chain(self._takeover_protocol, priority or self._priorities)\n    )\n  File \"C:\\Users\\karol\\AppData\\Roaming\\Python\\Python313\\site-packages\\pyatv\\core\\relayer.py\", line 115, in _find_instance\n    raise exceptions.NotSupportedError(f\"{target} is not supported\")\npyatv.exceptions.NotSupportedError: up is not supported\n"
}
    at b._pressKeyWithScript (C:\Users\karol\Documents\repos\appletv-controller\node_modules\@sebbo2002\node-pyatv\src\lib\device.ts:1027:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async b.up (C:\Users\karol\Documents\repos\appletv-controller\node_modules\@sebbo2002\node-pyatv\src\lib\device.ts:975:9)
    at async init (C:\Users\karol\Documents\repos\appletv-controller\src\patv-wrapper.ts:23:3)
    at async mainFunc (C:\Users\karol\Documents\repos\appletv-controller\src\index.ts:15:5)
    at async <anonymous> (C:\Users\karol\Documents\repos\appletv-controller\src\index.ts:29:1)

Do i understand this correctly: I cannot check if device is paired - other than read an error code "key is not supported"? And in that case i should pair with atvremote?

KotKarol avatar Oct 06 '25 11:10 KotKarol

You get the error because your device doesn’t support the up button. That has nothing to do with the pairing status for now. For example, use getState instead of up to fix the problem.

sebbo2002 avatar Oct 06 '25 17:10 sebbo2002

This error goes away when i pair it with atvremote. It's a new and up to date AppleTV device. That's why I'm confused. I'm looking for any indicator that device is not paired, other than the command fails. (as seen in my previous comment)

KotKarol avatar Oct 07 '25 14:10 KotKarol

I'm not aware of any indicator in atvscript. But please let me know if you find out how to check it wirh atvscript, so I can add it here as well.

sebbo2002 avatar Oct 09 '25 09:10 sebbo2002

Only thing i have found is that when you are paired, and use NodePyATVDevice getState() method, the result contains fields repeat and shuffle as strings. When you are not paired with the device - those are nulls. I will look into it some more next week.

KotKarol avatar Oct 10 '25 09:10 KotKarol