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

Specify how re-connection works #31

Closed
shuangMoz opened this issue Aug 21, 2014 · 21 comments
Closed

Specify how re-connection works #31

shuangMoz opened this issue Aug 21, 2014 · 21 comments

Comments

@shuangMoz
Copy link

Currently connect() is missing auto-connect optional parameter. Do we have any concern to do this? Without auto-connect parameter, I think it will be hard to handle reconnection scenario. If a website already paired and connect with a Smart Device, Smart Device moves out-of-range. Is it nature to reconnect smart device if the user already trusted this website to connect with that specific device?

@jyasskin
Copy link
Member

I'd like to broaden this topic a bit: We need to figure out how sites should reconnect to devices they already have permission to access, whether or not they have a BluetoothDevice object lying around. It seems like we'll need some event to fire when an allowed device comes into range. (And an event when a connection is lost.) Per w3c/ServiceWorker#416, we need to avoid guaranteeing that this event announces the same JS object that the page already had. On the other hand, it'd make programmers' lives a bit easier if we fire the event on the Device object itself.

Similar to #2, should we automatically reconnect to a lost-and-recovered device or should we tell the site about it and make it reconnect manually? Providing an auto-reconnect option to connect() will let the developer decide, but we still need to pick the default.

P.S. I'm imagining that the device-chooser dialog has a "remember this permission" checkbox at the bottom. If the user checks that, the origin keeps access to that device until the user revokes the permission in the Page Info settings. If the user unchecks that, the page keeps access to the device while it's open, even if the device moves temporarily out of range while the page is open. That's totally open for discussion, but if so, I'd like to split it into a different bug.

@jyasskin jyasskin changed the title Specify how connect() works Specify how re-connection works Aug 22, 2014
@jyasskin
Copy link
Member

Similarly, when a page is opened, and there's a nearby device it already has permission to access, should this device be listed in navigator.bluetooth.availableDevices or similar? That would address Device advertised URL opened by user.

@armansito
Copy link

It seems like we'll need some event to fire when an allowed device comes into range. (And an event when a connection is lost.)

The Chrome APIs have the onDeviceAdded, onDeviceRemoved, and onDeviceChanged events. The onDeviceChanged event can be used to check the connected property of the passed device object. Perhaps we want to do something similar?

Per w3c/ServiceWorker#416, we need to avoid guaranteeing that this event announces the same JS object that the page already had. On the other hand, it'd make programmers' lives a bit easier if we fire the event on the Device object itself.

Isn't it ok as long as the app sees a device object that has the same identifier as before? Or should it at least be a guarantee that whatever object is representing a specific peripheral will always have the same identifier assigned to it?

Similarly, when a page is opened, and there's a nearby device it already has permission to access, should this device be listed in navigator.bluetooth.availableDevices or similar? That would address Device advertised URL opened by user.

I'm not exactly sure how the URL obtained from AD is related to auto-reconnection? In this use case, as far as I remember, the URL is in the AD, which means that there is no connection and GATT involved.

Actually, are we thinking of providing the raw AD to applications when an advertisement is received? This will eventually be needed for any API that wants to deal with iBeacon or mesh-like devices that operate over advertising only. This could end up being the solution to the "what event to send when a device is nearby" problem, though it probably needs a separate discussion.

@armansito
Copy link

Similar to #2, should we automatically reconnect to a lost-and-recovered device or should we tell the site about it and make it reconnect manually? Providing an auto-reconnect option to connect() will let the developer decide, but we still need to pick the default.

I suggest keeping things simple for now. I say let's just encourage apps to manually reconnect. In most LE implementations, OSs end up automatically reconnecting to peripherals that have been bonded with anyway, so if the peripheral ended up being paired with and the OS supports auto-connection, then they could choose to reconnect. I worry that requiring UAs to keep track of which website requested an auto-connect and which ones didn't might end up making the implementation too complicated, especially at the time being.

Do you guys think that this is a crucial feature that needs to be in the first version? Could we perhaps revisit this in the future? Or maybe you had something simpler in mind?

@shuangMoz
Copy link
Author

If we don't expose auto-connect optional flag to handle reconnection, my major concern is the use case of Proximity Profile tag or something similar. Do we expect app to re-connect manually to proximity profile tag? I think background auto connection is really important feature for LE, and it improves a lot user experience than classic bluetooth.
It might be very tedious to reconnect manually for users if they use FindMe or Proximity tag, especially for the phone users. Just my two cents.

@armansito
Copy link

I agree in that background auto connection is an important LE feature. My concern is whether it's too much to require it from UAs if the OS doesn't support it. BlueZ and iOS don't have APIs for apps to pass an auto-connect flag, though BlueZ actually automatically handles this (the daemon sometimes does this internally and I think as of kernel 3.17 the stack performs passive background scanning and automatically reconnects when it receives connectable directed AD).

How about we test this on a Mac and see if it automatically handles it? Afaik Android doesn't provide an auto-connect flag either (I may be wrong) though it might be automatically handling this as well. Something to try out.

If most native platform APIs don't expose this flag, then supporting an optional flag at the Web API level will put the implementation burden on the browsers, which is my main concern. If most platforms already handle this automatically, then maybe we can get away with a "MAY autoconnect"?

P.S. For the Proximity Profile, the app needs to know the connection RSSI + TxPower GATT service and before connection it needs inquiry RSSI + TxPower received from AD to properly calculate path loss. I agree that proximity use cases will become important (both GATT and AD based) so we should probably have a separate discussion on exposing the RSSI to apps.

@armansito
Copy link

Oops, I accidentally closed it again

@armansito armansito reopened this Aug 22, 2014
@shuangMoz
Copy link
Author

iOS:
Performing Long-Term Actions in the Background
Reconnecting to Peripherals:
If the peripheral device goes out of range,you will receive -CBCentralManagerDelegate centralManager:didDisconnectPeripheral:error: The error code will indicate the reason of the disconnect and should be non-nil for out of range connection aborts. Then call another CBCentralManager connectPeripheral:options: request to reconnect to the peripheral. This connect request does not time out, and will complete when the peripheral device is back in range.
Android:
[BluetoothDevice::connectGatt()](https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#connectGatt%28android.content.Context, boolean, android.bluetooth.BluetoothGattCallback%29)
autoConnect Whether to directly connect to the remote device (false) or to automatically connect as soon as the remote device becomes available (true).
BluetoothGatt::connect()
This method is used to re-connect to a remote device after the connection has been dropped. If the device is not in range, the re-connection will be triggered once the device is back in range.

@ghost
Copy link

ghost commented Aug 22, 2014

I think it's worth remembering how LE works, and how that fits in with the
security/privacy model of the proposed specification, and not getting
distracted by how particular platforms happen to implement things.

In LE, when a Peripheral is able to receive a connection, it sends
Advertisements. A Central picks these up by Scanning, and then uses the
information in the Advertisement to establish a connection. That's what the
Android connect method means, it means that it will connect if an
advertisement was received within the last few seconds, if not it will wait
for the device to come back in range.

The draft specification already covers an Application requesting a device
that implements a particular service, and allowing the OS to deal with that
in an appropriate manner including allowing the user to confirm that the
application should be allowed to access the device, and in the case of
many, which device.

This is completely sufficient for an application to establish an initial
connection to a device, and for the application to reconnect to the device
later. In both cases it can use the proposed requestDevice() method. The
OS/Platform can be smart and put the previously used device at the top - or
implement "always allow connection" itself, these don't need to be in the
specification at first.

That's more than sufficient for a first implementation.

On Fri, Aug 22, 2014 at 12:56 PM, Shawn Huang notifications@github.com
wrote:

iOS:
Performing Long-Term Actions in the Background
https://developer.apple.com/Library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html
Reconnecting to Peripherals:
https://developer.apple.com/Library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/BestPracticesForInteractingWithARemotePeripheralDevice/BestPracticesForInteractingWithARemotePeripheralDevice.html
Android:
BluetoothDevice::connectGatt()
https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#connectGatt(android.content.Context,%20boolean,%20android.bluetooth.BluetoothGattCallback)
BluetoothGatt::connect()
https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#connect()
This method is used to re-connect to a remote device after the connection
has been dropped. If the device is not in range, the re-connection will be
triggered once the device is back in range.


Reply to this email directly or view it on GitHub
#31 (comment)
.

@jracle
Copy link

jracle commented Sep 22, 2014

Thanks @keybukium for the clarification. I still have to get the input of our BLE specialists here at Logitech, so please pardon my questions which might not be related to this discussion or point my partial knowledge of BT protocol stacks!

Concerning your last paragraph, are you talking about Link-Layer's white-list capability? I'm worried about how an app can re-connect to a device without adapter having to re-scan for devices when device is disconnected.

I'm also concerned with multi-app scenario: what if one app has auto-reconnection flag while another has not (maybe it is not an issue though).

@keybuk
Copy link

keybuk commented Sep 25, 2014

@jracle I'm not talking about any specific capability of the Link-Layer or even Application-Layer. I'm trying to avoid creating a first version of the specification that has complex requirements on the Link-Layer or Application-Layer for dealing with something that we don't fully understand the application use cases of yet—reconnection.

I think it's totally fine that if an app wants to connect to a device, it calls requestDevice. If it wants to reconnect to a device, it calls requestDevice again. And we leave it up to the OS to decide exactly what that means in this case.

And later when we understand what application authors are actually doing, we can extend the spec to support the kinds of reconnections they require.

In terms of LE itself, the adapter must re-scan for devices when a device is disconnected; it's just a fact of how LE works. The host can deal with reconnection one of two basic ways: it can call LE Create Connection again on the device, this command will perform a scan until the device advertises again, or the command times out; or the host can use a background scan and white list to have the controller automatically connect if the device advertises again.

I just don't think we should specify those behaviors right now, let's leave that up to the host.

@pzboyz
Copy link

pzboyz commented Sep 26, 2014

@keybukium wrote:
"In LE, when a Peripheral is able to receive a connection, it sends
Advertisements. A Central picks these up by Scanning, and then uses the
information in the Advertisement to establish a connection. That's what the
Android connect method means, it means that it will connect if an
advertisement was received within the last few seconds, if not it will wait
for the device to come back in range."

A device, I dont like to use the term Peripheral as it is misleading, can send one of two types of adverts. It could send the promiscuous ADV_IND packets which does include the AdvData, which means any Scanning device could connect to it, or it may send the ADV_DIRECTED_IND packets, which are targeted at a specific device it wants to be connected to, the ADV_DIRECTED_IND packets do not contain the AdvData.

For a device which has just gone out of range, it is highly likely that for a short time period after disconnection the Peripheral would send ADV_DIRECTED_IND packets for a few minutes at a frequent rate trying to get reconnected to the Central, and then maybe fall back to using the ADV_IND packets to allow any of its paired devices to connect.

The AdvData is not always in an Advertisment Packet, it depends on the type.

@keybuk
Copy link

keybuk commented Sep 26, 2014

@pzboyz "Peripheral" is a term defined by the standard, one of the two(four) possible roles of an LE Device—it shouldn't be misleading.

Talking of terms, note that I didn't refer to Advertising Data in my message, just Advertising in general. I was hopefully broadly covering both the cases of connectable undirected and directed advertising, except:

ADV_DIRECT_IND (correcting the name :p) actually doesn't tend to work out too well in practice. If a Central is actively scanning using a non-Public address, then the controller will generally filter out any advertisements directed at its Public address (it varies a bit by controller, Atheros tend not to, Intel do).

Not to mention that there's no way to direct an advertisement at a device using Resolvable Private Addresses, etc.

Those issues with the standard should be addressed in BT 4.2

@pzboyz
Copy link

pzboyz commented Sep 27, 2014

The TxAdd and RxAdd bits define if the Advertiser is using a Random Address in the AdvA or InitA fields. Agreed that this is making it complicated to say the least for one or both of the devices, but this is reality.

@keybuk
Copy link

keybuk commented Sep 27, 2014

Right, the fields aren't enough.

For example, try grabbing a Microsoft Arc Touch Mouse (Surface Edition) and pairing it with an OS X machine. It'll work exactly once, after which the mouse will use ADV_DIRECT_IND to reconnect to the host—and OS X won't respond to that because it's switched to a different random address.

Same is true for Chrome OS too.

@jracle
Copy link

jracle commented Sep 27, 2014

@keybuk ok got your points. Indeed we don't master all scenarios yet, hence no need to introduce un-necessary complexity. Thanks again guys for clarifying.

@wesleyyee
Copy link

Is there any update on this?

@adhodi
Copy link

adhodi commented Feb 18, 2019

is there a way to get connected device after page load yet?

@reillyeon
Copy link
Contributor

@adhodi I've answered this on #428. This issue and persistent permissions are interrelated problems as once permission can be maintained across multiple page loads it is also much more likely that a device will have gone in and out of range.

@reillyeon
Copy link
Contributor

Discussed at the 2019 TPAC F2F. The combination of the watchAdvertisements() and connect() methods are sufficient to determine that a device is in range and connectable and to connect to it. As mentioned previously Chromium does not currently implement these methods but the mechanism is specified.

device.addEventListener('gattserverdisconnected', async e => {
  await device.watchAdvertisements();
});
device.addEventListener('advertisementreceived', async e => {
  try {
    await device.gatt.connect();
    await device.unwatchAdvertisements();
  } catch (e) {
    // Continue listening for advertisements.
  }
});

@Emill
Copy link

Emill commented Sep 16, 2019

Well it would be much better to use the OS's auto-connect feature if available. That leads to a much faster connection setup.
Also with Android's scan parameters when not full duty is used, it can take very long time to discover the device.

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

10 participants