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

added BleakDeviceNotFoundError #1022

Merged
merged 1 commit into from
Sep 29, 2022

Conversation

jochenjagers
Copy link
Contributor

This is a first draft for BleakDeviceNotFoundError as discussed in #527

@jochenjagers jochenjagers changed the title fadded BleakDeviceNotFoundError added BleakDeviceNotFoundError Sep 22, 2022
@jochenjagers
Copy link
Contributor Author

jochenjagers commented Sep 22, 2022

I basically only replace the BleakErrors with device not found messages by BleakDeviceNotFoundError
But this covers not all functions/backends yet.

CoreBluetooth:

  • connect
  • pair ("Pairing is not available in Core Bluetooth.")
  • unpair ("Pairing is not available in Core Bluetooth.")

WinRT:

  • connect
  • pair (Pair is not possible without connect at the moment)
  • unpair

BlueZ:

  • connect
  • pair (Pair is not possible without connect at the moment)
  • unpair ("Unpairing is seemingly unavailable in the BlueZ DBus API at the moment.")

p4android:

  • connect
  • pair
  • unpair ("Unpairing is seemingly unavailable in the Android API at the moment.")

The Android backend does not have a check for the availability of the device yet.

raise BleakError(
"Device with address {0} was not found.".format(self.address)
raise BleakDeviceNotFoundError(
self.address, f"Device with address {self.address} was not found."
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left the messages in there to not break compatibility with programs which check for the text as described in #527 (comment)

bleak/exc.py Outdated
def __init__(self, identifier: str, *args: object) -> None:
"""
Args:
identifier (str): The identifier which was used to search the device (e. g. Bluetooth address or UUID)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only added the identifier here for now. But it can also be the BLEDevice to share some more information about the device if they are available. I'm a bit ambivalent about this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be best to use the BLEDevice object to wrap the platform-specific details.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed it to the BLEDevice.

Copy link
Collaborator

@dlech dlech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the connect methods, in addition to the optional scanner not finding the device, we need to handle the case for when the device is removed from the OS between the external scan and the connection request.

For example, in the BlueZ backend, if the "Connected" D-Bus method reply contains a org.freedesktop.DBus.Error.UnknownObject error, then we should raise the new BleakDeviceNotFoundError .

I'm not sure what it would be in the other backends, so I guess we will have to do some experimentation to find out.

bleak/exc.py Outdated
def __init__(self, identifier: str, *args: object) -> None:
"""
Args:
identifier (str): The identifier which was used to search the device (e. g. Bluetooth address or UUID)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be best to use the BLEDevice object to wrap the platform-specific details.

self._peripheral, disconnect_callback, timeout=timeout
)
except asyncio.TimeoutError as error:
raise BleakDeviceNotFoundError(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I seems like corebluetooth has no real mechanism for detecting "device not found" errors. the connect function just receives a Timeout error. Can we assume that the device was not found in case of this?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should probably just leave this as a timeout.

If we really want a "device not found" here, I suppose we could check if the peripheral is still in the list returned by CBCentalManager.retrievePeripheralsWithIdentifiers_ before attempting to connect.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I think it is fine to just leave it as-is for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we really want a "device not found" here, I suppose we could check if the peripheral is still in the list returned by CBCentalManager.retrievePeripheralsWithIdentifiers_ before attempting to connect.

This is already done a few lines above where the device is searched using the bleak scanner. The catch for the TimeoutError was only for the edge-case in which the device goes out of sight in between.
But I reverted this change as it might be misleading if the connection attempt times out for other reasons.

if (
reply is not None
and reply.message_type == MessageType.ERROR
and reply.error_name == ErrorType.UNKNOWN_OBJECT
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure about the UnknownObject error? The documentation does not mention it:
https://github.com/bluez/bluez/blob/master/doc/device-api.txt

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. It is a standard D-Bus error. (Searching the issues in this repo for "UnknownObject" reveals quite a few hits)

@jochenjagers
Copy link
Contributor Author

For Android the documentation is ambiguous.
On the one hand: https://developer.android.com/guide/topics/connectivity/bluetooth/connect-gatt-server

The service will first call getRemoteDevice() on the BluetoothAdapter to access the device. If the adapter is unable to find a device with that address, getRemoteDevice() throws an IllegalArgumentException.

On the other hand:
https://developer.android.com/reference/android/bluetooth/BluetoothAdapter#getRemoteDevice(java.lang.String)

A BluetoothDevice will always be returned for a valid hardware address, even if this adapter has never seen that device.

@jochenjagers jochenjagers marked this pull request as ready for review September 27, 2022 14:10
@dlech
Copy link
Collaborator

dlech commented Sep 27, 2022

For Android the documentation is ambiguous.

It sounds like we shouldn't worry about it on android then.

@dlech
Copy link
Collaborator

dlech commented Sep 27, 2022

In the connect methods, in addition to the optional scanner not finding the device,

...

I'm not sure what it would be in the other backends, so I guess we will have to do some experimentation to find out.

I suppose it could be the case that the non-BlueZ backends actually allow connecting to a device without having ever "seen" it before, in which case I guess there isn't an extra case to handle.

(As a side note, BlueZ has an Adapter1.ConnectDevice experimental method that in theory could be used to do the same, but we removed it recently because it doesn't seem to work as expected).

@jochenjagers jochenjagers force-pushed the feature/device-not-found-error branch from 42c5066 to 8c237e4 Compare September 28, 2022 10:50
@jochenjagers
Copy link
Contributor Author

From my point of view this is ready to merge now.

requester = BluetoothLEDevice.from_bluetooth_address_async(*args)
if requester is None:
raise BleakDeviceNotFoundError(
BLEDevice(self.address),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I didn't think about this before when I suggested using BLEDevice, but if we don't have any other information besides the address, then it doesn't make sense to create an incomplete BLEDevice object. So probably better to just stick with the "identifier" as you originally had it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem. I changed it back to the identifier version.
Nevertheless storing the whole BLEDevice might be an interesting improvement for the future.

@jochenjagers jochenjagers force-pushed the feature/device-not-found-error branch from 8c237e4 to b6e811a Compare September 29, 2022 13:05
@dlech
Copy link
Collaborator

dlech commented Sep 29, 2022

Thanks for updating!

@dlech dlech merged commit 57f4c87 into hbldh:develop Sep 29, 2022
@jochenjagers
Copy link
Contributor Author

Thanks for updating!

Thanks for your fast and constructive feedback.

@dlech dlech mentioned this pull request Oct 13, 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

Successfully merging this pull request may close these issues.

2 participants