Skip to content
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

Unable to unpair with device #699

Closed
harshdeepsehgal opened this issue Dec 22, 2021 · 12 comments
Closed

Unable to unpair with device #699

harshdeepsehgal opened this issue Dec 22, 2021 · 12 comments
Labels
Backend: WinRT Issues or PRs relating to the WinRT backend bug Something isn't working

Comments

@harshdeepsehgal
Copy link
Contributor

harshdeepsehgal commented Dec 22, 2021

  • bleak version: 0.13.0
  • Python version: 3.8.5
  • Operating System: Win10

Description

I am trying to pair and unpair with an Arduino Nano 33 BLE. I want to pair since there is an HID service I want to use which won't work using the standard connect method since it throws an Access Denied.

What I Did

Pairing works fine and I can use it as an HID. I am planning to use unpair for disconnecting. Calling unpair does nothing.
The issue seems to be that unpair uses the following boolean variable -
self._requester.device_information.pairing.is_paired

        client=BleakClientWinRT(device_address)
        is_connected=await client.connect()
        is_paired=await client.pair(2)
        print(is_paired)
        await asyncio.sleep(10)
        await client.unpair()

Even though the pair function returns true, the above boolean variable remains false. Possibly something on the firmware end and I can't figure out how to fix that.

Is it possible to have another boolean instance variable to store the pairing status at the software end and raise an exception if unpair fails?
Is it also possible that the above boolean variable isn't being refreshed after pairing in Bleak?

This is a bit urgent so I'd appreciate some quick help!
TIA

@dlech
Copy link
Collaborator

dlech commented Dec 22, 2021

Pairing isn't implemented in Windows yet. See #640.

@dlech dlech added the Backend: WinRT Issues or PRs relating to the WinRT backend label Dec 22, 2021
@dlech dlech linked a pull request Dec 22, 2021 that will close this issue
@hbldh
Copy link
Owner

hbldh commented Dec 22, 2021

I did implement pairing in my first winrt reimplementation of the previous backend. There are some elements of it there, right? A just works-pairing?

Try removing the offending check in your local installation of Bleak and see if something breaks. However, I do not think that the Bleak unpair method will lead to a disconnection. You should disconnect with the disconnect method instead.

@harshdeepsehgal
Copy link
Contributor Author

harshdeepsehgal commented Dec 23, 2021

Yes, the elements of your old implementation do work.
From what I have understood, the current implementation of pair/unpair uses UWP Bluetooth. Unpairing using that leads to automatic disconnection and I'm hoping would also trigger the disconnect callback (have not checked this yet).
I tried removing the check on my local installation and it works fine. I could just put in a try/except just in case.

In case there are no immediate plans to re-implement this, maybe I could open a pull request with the temporary changes to make this work for more devices, by removing the check and adding a try/except instead.

@harshdeepsehgal
Copy link
Contributor Author

An update:
I tried refreshing the _requester object before the check, and it seems that fixes it as well. So I guess the issue isn't device-specific after all. The object needs to be refreshed after pairing/unpairing.

I added this code segment at the beginning of unpair :

args = [
            self._device_info,
        ]
        if self._address_type is not None:
            args.append(
                BluetoothAddressType.PUBLIC
                if self._address_type == "public"
                else BluetoothAddressType.RANDOM
            )
        self._requester = await BluetoothLEDevice.from_bluetooth_address_async(*args)
        print(self._requester.device_information.pairing.is_paired)

I get a true for the flag now and it proceeds to unpair and subsequently disconnects (is_connected returns false).

@dlech
Copy link
Collaborator

dlech commented Dec 23, 2021

Nice find. I guess the device_information is just the info at the time the device was discovered.

Instead of creating a new BluetoothLEDevice (which probably breaks event handlers), we should be able to just create a new DeviceInformation object using the ID of the old device information object.

We should also check for other uses of self._requester.device_information in the code and fix those too, if any.

Happy to take a pull request for this.

@dlech dlech added the bug Something isn't working label Dec 23, 2021
@harshdeepsehgal
Copy link
Contributor Author

I didn't quite get what you meant by

we should be able to just create a new DeviceInformation object using the ID of the old device information object.

I'm not sure how exactly to do that. Anything I can refer to?

@hbldh
Copy link
Owner

hbldh commented Dec 25, 2021

There is the update method to call on the device_information object. Not sure what to send in, but I think calling that after pairing can make sure the properties we need are up to date. It should be run before unpairing as well..

https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.deviceinformation.update?view=winrt-22000#Windows_Devices_Enumeration_DeviceInformation_Update_Windows_Devices_Enumeration_DeviceInformationUpdate_

@dlech
Copy link
Collaborator

dlech commented Dec 26, 2021

The update method only applies to updates received from a DeviceInformationWatcher. If we are only using device_information in 1 or 2 places, it is probably easier to just use DeviceInformation.create_from_id_async() instead of setting up and tearing down a device watcher.

@harshdeepsehgal
Copy link
Contributor Author

harshdeepsehgal commented Dec 27, 2021

Yes, that was exactly what I was looking at.
However, I guess the attributes of _requester are not writable.
When I added the following-
self._requester.device_information=await DeviceInformation.create_from_id_async(self._requester.device_information.id)

I get this attribute error-
AttributeError: attribute 'device_information' of '_bleak_winrt_Windows_Devices_Bluetooth.BluetoothLEDevice' objects is not writable

The device_information object is being used only in the pair and unpair functions. If you intend to keep the _requester read-only, what we can do is create a local device_information object for these functions and use them for checks.

device_information=await DeviceInformation.create_from_id_async(self._requester.device_information.id)
if device_information.pairing.is_paired:
    unpairing_result = (
        await device_information.pairing.unpair_async()
     )

I tried this and it worked. Doesn't seem to break anything for now.

@dlech
Copy link
Collaborator

dlech commented Dec 27, 2021

If you intend to keep the _requester read-only, what we can do is create a local device_information object for these functions and use them for checks.

Yes, this is what I was suggesting.

@harshdeepsehgal
Copy link
Contributor Author

I'll test some more with my devices and open a PR with these changes.

@harshdeepsehgal
Copy link
Contributor Author

Hi guys,
I have been MIA for a while, but I was able to test this enough and the solution does work and would be a good stand-in while the new pairing functionality is completed. I have linked the PR to the issue :) (#757 )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backend: WinRT Issues or PRs relating to the WinRT backend bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants