Skip to content

Windows.Devices:DeviceInformationCustomPairing.PairAsync() invalid method args #940

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
andrewleech opened this issue Aug 14, 2019 · 8 comments

Comments

@andrewleech
Copy link

Environment

  • Pythonnet version: 2.4.0
  • Python version: 3.6.4 (amd64)
  • Operating System: Win 10.0.18875 Build 18875

Details

  • Trying to use the DeviceInformationCustomPairing.PairAsync Method to pair to a BLE device

https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.deviceinformationcustompairing.pairasync

I'm trying to add pairing support the the bleak module (https://github.com/hbldh/bleak)

This code runs:

        from Windows.Devices.Enumeration import (
            DevicePairingResult,
            DevicePairingResultStatus,
            DevicePairingProtectionLevel,
            DeviceInformationCustomPairing,
            DevicePairingRequestedEventArgs,
            DevicePairingKinds,
        )
        ...
        device = self._requester  # type: Windows.Devices.Bluetooth.BluetoothLEDevice

        pairing_result = await wrap_IAsyncOperation(
            IAsyncOperation[DevicePairingResult](
                device.DeviceInformation.Pairing.PairAsync(DevicePairingProtectionLevel.Encryption)
                 ),
            return_type=DevicePairingResult,
            loop=self.loop,
        )

However the basic pairing function used fails to work with most devices.
https://stackoverflow.com/a/41423796
This is a common issue in the library, where the suggested fix is the custom pairing below which is the target of this issue request.

        def CustomPairing_PairingRequested(sender: DeviceInformationCustomPairing,
                                           args: DevicePairingRequestedEventArgs):
            args.Accept("123456")

        customPairing = device.DeviceInformation.Pairing.Custom
        customPairing.PairingRequested += CustomPairing_PairingRequested

        pairing_result = await wrap_IAsyncOperation(
            IAsyncOperation[DevicePairingResult](
                customPairing.PairAsync(DevicePairingKinds.ConfirmOnly, DevicePairingProtectionLevel.Encryption)
            ),
            return_type=DevicePairingResult,
            loop=self.loop,
        )

        customPairing.PairingRequested -= CustomPairing_PairingRequested
  • If there was a crash, please include the traceback here.
  File "F:/pi/Kinder/ble_tester/ble_test.py", line 54, in run
    await client.pair()
  File "F:\pi\Kinder\ble_tester\bleak\backends\dotnet\client.py", line 245, in pair
    customPairing.PairAsync(DevicePairingKinds.ConfirmOnly, DevicePairingProtectionLevel.Encryption)
TypeError: No method matches given arguments for PairAsync

I've tried running customPairing.PairAsync() with none, 1, 2 args, passed as the enums shown above and as raw integers (1) which is what they both resolve to.

Is there any way to introspect what the function is expecting to be passed?

There is a third overload of that function listed on the function docs above, with the third arg an interface class IDevicePairingSettings. I don't know how to provide an implementation of this, I've tried a third arg of None with no change.

@filmor
Copy link
Member

filmor commented Sep 11, 2019

Could you try something like DevicePairingKinds(DevicePairingKinds.ConfirmOnly)?

@den-run-ai
Copy link
Contributor

Is there any way to introspect what the function is expecting to be passed?

2 ways: either look at .Overloads or use Reflection.

@andrewleech
Copy link
Author

Thanks, I tried DevicePairingKinds(DevicePairingKinds.ConfirmOnly) and DevicePairingKinds(1) but it gives a {TypeError}cannot instantiate enumeration

I checked the .Overloads of the PairAsync function and I get

Windows.Foundation.IAsyncOperation`1[Windows.Devices.Enumeration.DevicePairingResult] PairAsync(Windows.Devices.Enumeration.DevicePairingKinds)

Windows.Foundation.IAsyncOperation`1[Windows.Devices.Enumeration.DevicePairingResult] PairAsync(Windows.Devices.Enumeration.DevicePairingKinds, Windows.Devices.Enumeration.DevicePairingProtectionLevel)

Windows.Foundation.IAsyncOperation`1[Windows.Devices.Enumeration.DevicePairingResult] PairAsync(Windows.Devices.Enumeration.DevicePairingKinds, Windows.Devices.Enumeration.DevicePairingProtectionLevel, Windows.Devices.Enumeration.IDevicePairingSettings)

To me it looks like it's expecting an Enum type object passed in but once I've got the instance of the enum it's a python int object and the override choosing mechanism isn't accepting that as a viable option?

Is there a different way to pass an enum as an object rather than the int representation of it?

Or is there a different way to explicitly choose which override of the bound method to call?

@andrewleech
Copy link
Author

I just found #935 which appears to be the same problem I'm hitting.

My understanding of the suggested fix there still isn't working though

customPairing.PairAsync[DevicePairingKinds](DevicePairingKinds.ConfirmOnly)

gives {TypeError}No match found for given type params

@nicosoto0
Copy link

Hi! I am having the exact same problems, with the exact same results. Where you able to solve it in some way?

@andrewleech
Copy link
Author

I haven't spent any more time on this myself, though by memory I believe the problem is likely due to it not picking the right override function.

A colleague of mine working with an un-related .net library ran into problems with overloads too, they finally got their problem fixed with code to explicitly choose the desired overload function and call it like this

>>> Messages.MessageFactory.CreateCommand.Overloads
Communication.Messages.CommandMessage CreateCommand(Communication.Messages.ServiceCode, UInt16)
Communication.Messages.CommandMessage CreateCommand(Communication.Messages.ServiceCode, System.String)
>>> Messages.MessageFactory.CreateCommand.Overloads[Messages.ServiceCode, System.UInt16](Messages.ServiceCode.ManufacturingService, 0X8002)
<Communication.Messages.GetLogStatusCommand object at 0x015BBDF0>

In my previous post I wasn't accessing the function via the .Overloads[] property, so this might be the sort of usage needed here too.

@nicosoto0
Copy link

I worked! Thanks for the help!

I leave the final version of my code in case it is useful for someone else:

##  ble_device:  [Windows.Devices.Bluetooth import BluetoothLEDevice] object
device_custom_pair = ble_device.DeviceInformation.Pairing.Custom

def custom_pairing_handler(sender: DeviceInformationCustomPairing, 
                            args: DevicePairingRequestedEventArgs) -> None:
    """
    Handle custom pairing. (Design for ConfirmOnly)

    Args:
        sender [DeviceInformationCustomPairing]
        args [DevicePairingRequestedEventArgs]

    Return: None
    """
    args.Accept()

device_custom_pair.PairingRequested += custom_pairing_handler

custom_pair_result = await wrap_iasync_event(
    IAsyncOperation[DevicePairingResult](
        device_custom_pair.PairAsync.Overloads[DevicePairingKinds](
            DevicePairingKinds.ConfirmOnly
        )
    ),
    return_type=DevicePairingResult,
    loop=loop,
)

pair_result = custom_pair_result.Status

print(f"pairing_result  status -> {pairing_result}")
##  OUTPUT: pairing_result  status -> 0
## Remember: DevicePairingResultStatus 0 signifies Paired 

Remember: DevicePairingResultStatus
Paired | 0 | The device object is now paired.
Source: https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicepairingresultstatus?view=winrt-18362

@andrewleech
Copy link
Author

That's wonderful, thanks for sharing!

@lostmsu lostmsu closed this as completed Sep 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants