-
Notifications
You must be signed in to change notification settings - Fork 304
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
allow unpair without being connected on WinRT backend #1012
allow unpair without being connected on WinRT backend #1012
Conversation
bleak/backends/winrt/client.py
Outdated
if not self._requester: | ||
# close the device object if this was created locally | ||
device.close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be in a finally clause so that it still get called if an exception is raised while awaiting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is unlikely but still theoretically possible that self._requester
could be assigned while awaiting, so perhaps we should just have a local should_close
flag instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a try/finally block to ensure close() is called in case of an error. I also added the should_close flag.
Is it even necessary to use self._requester here at all? Can we just create a new BluetoothLEDevice for every call to unpair an simplify this function?
Something like this:
device = await BluetoothLEDevice.from_bluetooth_address_async(
_address_to_int(self.address)
)
try:
unpairing_result = await device.device_information.pairing.unpair_async()
finally:
device.close()
if unpairing_result.status not in (
DeviceUnpairingResultStatus.UNPAIRED,
DeviceUnpairingResultStatus.ALREADY_UNPAIRED,
):
raise BleakError(f"Could not unpair with device: {unpairing_result.status}")
logger.info("Unpaired with device.")
return True
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not all devices have a static address. Bonded devices with privacy enabled will have a random address that changes from time to time. So from_bluetooth_address_async()
should only be called as a last resort if no other information is available.
In fact, we may already have self._device_info
even if self_requester
is None. So we could do something like this:
if self._device_info is None:
# BleakClient was initialized with address instead of BleDevice and has not connected yet
device = await BluetoothLEDevice.from_bluetooth_address_async(
_address_to_int(self.address)
)
device_information = device.device_information
device.close()
else:
device_information = self._device_info
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self._device_info
does only contain the Bluetooth address from advertising. It is no DeviceInformation
object which can be used for unpairing.
self._device_info = device.details.adv.bluetooth_address
I updated the PR and added a _create_requester function which takes the address type into account and can be used by connect
and unpair
to create the BluetoothLEDevice
object.
For unpair
the address from self._device_info is used if it is available (as it was already done in connect
before). Otherwise self.address is used.
I also recognized that from_bluetooth_address_async
can return None if the device is not paired and not found in the system cache. So I added a check for this case.
bleak/utils.py
Outdated
) | ||
|
||
|
||
def validate_address(address: str) -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function was not used anywhere in code, so I think we can just remove it completely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved it back to where it was. It would be great to might add a check to BaseBleakClient to check the address for validity to get early feedback if you pass something wrong to the client. But this is not the topic of this pull request.
bleak/utils.py
Outdated
return _address_regex.match(address) is not None | ||
|
||
|
||
def address_to_int(address: str) -> int: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this function is useful outside of the WinRT backend. If it is only needed in one file, we can just add it in that file or if it is used in more than one file, we can add a utils.py
in the bleak/backends/winrt/
folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved address_to_int to WinRT's client.py.
be7cd01
to
e5e68b0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think this is potentially problematic for resolvable private addresses since they change periodically, but I don't have a device to test that and it probably deserves consideration beyond the scope of this PR anyway.
bleak/backends/winrt/client.py
Outdated
finally: | ||
device.close() | ||
else: | ||
logger.debug("No device found to unpair.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we raise an error instead of silently ignoring unknown devices?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm really not sure about this. If you only want to remove a device from the system if it is available this is not really an error. But if you expect the device to be available for unpairing this is an error of course.
But raising a BleakError
makes it hard to differentiate between an error caused by the call to WinRT backend and the device not being found. This is a problem if the "device not found" error is no problem for your use case but a "backend error" is.
If we want to raise here we should introduce a DeviceNotFound
exception to be able to handle both cases in different ways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a discussion in #527 about error types. I would say, let's just raise a BleakError for now and consider adding a DeviceNotFound error later in a wider scope.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like a plan.
e5e68b0
to
1789ba4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
This is a alternative approach to #1002
Calling unpair when not connected should remove all device information from the OS.
This also relates to issue #309