|
43 | 43 | DevicePairingKinds, |
44 | 44 | DevicePairingResultStatus, |
45 | 45 | DeviceUnpairingResultStatus, |
| 46 | + DevicePairingRequestedEventArgs, |
| 47 | + DeviceInformationCustomPairing, |
46 | 48 | ) |
47 | 49 | from bleak_winrt.windows.foundation import EventRegistrationToken |
48 | 50 | from bleak_winrt.windows.storage.streams import Buffer |
49 | 51 |
|
50 | 52 | from ... import BleakScanner |
51 | 53 | from ...agent import BaseBleakAgentCallbacks |
52 | | -from ...exc import PROTOCOL_ERROR_CODES, BleakDeviceNotFoundError, BleakError |
| 54 | +from ...exc import ( |
| 55 | + PROTOCOL_ERROR_CODES, |
| 56 | + BleakDeviceNotFoundError, |
| 57 | + BleakError, |
| 58 | + BleakPairingCancelledError, |
| 59 | + BleakPairingFailedError, |
| 60 | +) |
53 | 61 | from ..characteristic import BleakGATTCharacteristic |
54 | 62 | from ..client import BaseBleakClient, NotifyCallback |
55 | 63 | from ..device import BLEDevice |
@@ -251,7 +259,7 @@ async def connect(self, **kwargs) -> bool: |
251 | 259 |
|
252 | 260 | def handle_services_changed(): |
253 | 261 | if not self._services_changed_events: |
254 | | - logger.warn("%s: unhandled services changed event", self.address) |
| 262 | + logger.warning("%s: unhandled services changed event", self.address) |
255 | 263 | else: |
256 | 264 | for event in self._services_changed_events: |
257 | 265 | event.set() |
@@ -446,52 +454,91 @@ async def pair( |
446 | 454 | """ |
447 | 455 | Attempts to pair with the device. |
448 | 456 | """ |
449 | | - if callbacks: |
450 | | - raise NotImplementedError |
451 | | - |
452 | 457 | # New local device information object created since the object from the requester isn't updated |
453 | | - device_information = await DeviceInformation.create_from_id_async( |
454 | | - self._requester.device_information.id |
| 458 | + device_information: DeviceInformation = ( |
| 459 | + await DeviceInformation.create_from_id_async( |
| 460 | + self._requester.device_information.id |
| 461 | + ) |
455 | 462 | ) |
456 | | - if ( |
457 | | - device_information.pairing.can_pair |
458 | | - and not device_information.pairing.is_paired |
459 | | - ): |
460 | 463 |
|
461 | | - # Currently only supporting Just Works solutions... |
462 | | - ceremony = DevicePairingKinds.CONFIRM_ONLY |
463 | | - custom_pairing = device_information.pairing.custom |
| 464 | + if device_information.pairing.is_paired: |
| 465 | + logger.debug("already paired") |
| 466 | + return True |
464 | 467 |
|
465 | | - def handler(sender, args): |
466 | | - args.accept() |
| 468 | + if not device_information.pairing.can_pair: |
| 469 | + raise BleakError("device does not support pairing") |
467 | 470 |
|
468 | | - pairing_requested_token = custom_pairing.add_pairing_requested(handler) |
469 | | - try: |
470 | | - if protection_level: |
471 | | - pairing_result = await custom_pairing.pair_async( |
472 | | - ceremony, protection_level |
473 | | - ) |
474 | | - else: |
475 | | - pairing_result = await custom_pairing.pair_async(ceremony) |
| 471 | + if callbacks: |
476 | 472 |
|
477 | | - except Exception as e: |
478 | | - raise BleakError("Failure trying to pair with device!") from e |
479 | | - finally: |
480 | | - custom_pairing.remove_pairing_requested(pairing_requested_token) |
| 473 | + loop = asyncio.get_running_loop() |
481 | 474 |
|
482 | | - if pairing_result.status not in ( |
483 | | - DevicePairingResultStatus.PAIRED, |
484 | | - DevicePairingResultStatus.ALREADY_PAIRED, |
| 475 | + def handle_pairing_requested( |
| 476 | + sender: DeviceInformationCustomPairing, |
| 477 | + args: DevicePairingRequestedEventArgs, |
485 | 478 | ): |
486 | | - raise BleakError(f"Could not pair with device: {pairing_result.status}") |
487 | | - else: |
488 | | - logger.info( |
489 | | - "Paired to device with protection level %d.", |
490 | | - pairing_result.protection_level_used, |
| 479 | + print(args.pairing_kind, args.pin) |
| 480 | + logger.debug("kind: %r, pin: %s", args.pairing_kind, args.pin) |
| 481 | + |
| 482 | + deferral = args.get_deferral() |
| 483 | + |
| 484 | + async def handle_callback(): |
| 485 | + print("prompt") |
| 486 | + try: |
| 487 | + ble_device = BLEDevice( |
| 488 | + args.device_information.id, |
| 489 | + args.device_information.name, |
| 490 | + args.device_information, |
| 491 | + ) |
| 492 | + |
| 493 | + if args.pairing_kind & DevicePairingKinds.CONFIRM_PIN_MATCH: |
| 494 | + if await callbacks.confirm_pin(ble_device): |
| 495 | + args.accept() |
| 496 | + elif args.pairing_kind & DevicePairingKinds.PROVIDE_PIN: |
| 497 | + pin = await callbacks.request_pin(ble_device) |
| 498 | + |
| 499 | + if pin: |
| 500 | + args.accept(pin) |
| 501 | + elif args.pairing_kind & DevicePairingKinds.DISPLAY_PIN: |
| 502 | + await callbacks.display_pin(ble_device, args.pin) |
| 503 | + args.accept() |
| 504 | + elif args.pairing_kind & DevicePairingKinds.CONFIRM_ONLY: |
| 505 | + if await callbacks.confirm(ble_device): |
| 506 | + args.accept() |
| 507 | + finally: |
| 508 | + print("complete") |
| 509 | + deferral.complete() |
| 510 | + |
| 511 | + loop.call_soon_threadsafe(loop.create_task, handle_callback()) |
| 512 | + |
| 513 | + token = device_information.pairing.custom.add_pairing_requested( |
| 514 | + handle_pairing_requested |
| 515 | + ) |
| 516 | + try: |
| 517 | + result = await device_information.pairing.custom.pair_async( |
| 518 | + DevicePairingKinds.CONFIRM_ONLY |
| 519 | + | DevicePairingKinds.DISPLAY_PIN |
| 520 | + | DevicePairingKinds.PROVIDE_PIN |
| 521 | + | DevicePairingKinds.CONFIRM_PIN_MATCH |
491 | 522 | ) |
492 | | - return True |
| 523 | + finally: |
| 524 | + device_information.pairing.custom.remove_pairing_requested(token) |
| 525 | + |
493 | 526 | else: |
494 | | - return device_information.pairing.is_paired |
| 527 | + result = await device_information.pairing.pair_async() |
| 528 | + |
| 529 | + if result.status == DevicePairingResultStatus.PAIRING_CANCELED: |
| 530 | + raise BleakPairingCancelledError |
| 531 | + |
| 532 | + if result.status == DevicePairingResultStatus.FAILED: |
| 533 | + raise BleakPairingFailedError |
| 534 | + |
| 535 | + if result.status not in [ |
| 536 | + DevicePairingResultStatus.PAIRED, |
| 537 | + DevicePairingResultStatus.ALREADY_PAIRED, |
| 538 | + ]: |
| 539 | + raise BleakError("pairing failed", result.status) |
| 540 | + |
| 541 | + return True |
495 | 542 |
|
496 | 543 | async def unpair(self) -> bool: |
497 | 544 | """Attempts to unpair from the device. |
|
0 commit comments