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

Missing API for GATT Write w/o Response #238

Closed
martijnthe opened this issue May 4, 2016 · 59 comments
Closed

Missing API for GATT Write w/o Response #238

martijnthe opened this issue May 4, 2016 · 59 comments

Comments

@martijnthe
Copy link

There does not seem to be a way to specify that the GATT Write w/o Response operation should be used when calling writeValue().

I don't think this should be "abstracted away" / left up to the UA implementation because this is the only GATT operation by which GATT clients can have more than one GATT packets in flight towards the GATT server. The other write operations have to be ack'd before the next write can be sent out, making it very slow.

Most applications that I've seen that need to optimize for throughput (Pebble smartwatch, Parrot's drones, ...), usually use GATT Write w/o Response in combination with GATT Value Notifications for data in the other direction.

Also related: #26

@jyasskin
Copy link
Member

jyasskin commented May 4, 2016

Do you have devices that allow both Write with Response and Write w/o Response on the same characteristic?

What behavior do you want when the requested write type isn't among the characteristic's properties?

I suspect the API shape will be writeValue(value, {type: 'without-response'})

@jyasskin jyasskin added this to the Complete GATT Communication milestone May 4, 2016
@martijnthe
Copy link
Author

martijnthe commented May 4, 2016

Do you have devices that allow both Write with Response and Write w/o Response on the same characteristic?

Is possible and allowed by the BT spec.
I'm sure someone will come up with a good use case for having both enabled for the same characteristic.

What behavior do you want when the requested write type isn't among the characteristic's properties?

I'd say if with-response was explicitly specified, error out the way you would do normally when an operation is attempted that isn't allowed. If it's not explicitly specified, fallback to write with response?

I suspect the API shape will be writeValue(value, {type: 'without-response'})

Sounds good to me!

@360fun
Copy link

360fun commented Aug 3, 2016

Hi, I think I may got stuck in this issue: basically I'm trying to cache the GATT server connection, but when I write some data it executes the command and it disconnects right after! So the second time that I try to write a command using the cached service variable, I get the error "Uncaught (in promise) DOMException: GATT Service no longer exists.".
The trick seems to re-connect every time the GATT server, but this adds latency and this is a problem in applications like drive drones, cars, robots...since they need a real time feedback! :(

I started to guess why this happens and then I read that the kind of command in this case, for my device, is "without response", so, guessing, when the API doesn't get anything after the promise, it disconnects the GATT server. If this is right...is there a workaround or we need to wait an update in the API? :\

@g-ortuno
Copy link
Contributor

g-ortuno commented Aug 3, 2016

It would be great if you could open a Chromium issue with your problem. Here are the instructions:

https://www.chromium.org/developers/how-tos/file-web-bluetooth-bugs

@beaufortfrancois
Copy link
Member

For info, @360fun also reported this issue at poshaughnessy/web-bluetooth-parrot-drone#1 (comment)

@360fun
Copy link

360fun commented Aug 3, 2016

Yes I did :) I'm kind of lost...but now I've a new way to investigate the issue, thanks! :D I never worked with Bluetooth before, so is good to learn! ;)

@beaufortfrancois
Copy link
Member

We'll continue conversation at poshaughnessy/web-bluetooth-parrot-drone#1 (comment) to not pollute this thread and come back if it's a Web Bluetooth API issue.

@Emill
Copy link

Emill commented Sep 16, 2016

I'm also in favor for adding this option.

From the Bluetooth spec:

This sub-procedure is used to write a Characteristic Value to a server when the client knows the Characteristic Value Handle and the client does not need an acknowledgement that the write was successfully performed.

It basically informs that Write Without Response should be chosen when the client does not need an acknowledgement. In this case I guess the "client" should refer to the application (and not the stack or browser) since the application is the only one who knows if an acknowledgement is really needed or not. The Bluetooth spec does not state that Write Without Response can only be used if no other write sub-procedures are allowed according to the characteristic's permissions.

If the client wants to write many values and it ignores Write Responses, and the browser by itself chooses Write With Response, it results in wasteful significant delays.

@360fun
Copy link

360fun commented Sep 16, 2016

In the end I found that the problem was in my device: a watchdog is killing the connection after 500ms, so I just have to use a loop to keep alive the connection! :) But was nice to discover this thing anyway and know a bit more about Bluetooth. :D

@Vudentz
Copy link

Vudentz commented Sep 19, 2016

If the client wants to write many values and it ignores Write Responses, and the browser by itself chooses Write With Response, it results in wasteful significant delays.

It goes both ways, if the remote device does not support this mode for some reason then the values would be ignored so at least it shouldn't be the default behavior.

@beaufortfrancois
Copy link
Member

beaufortfrancois commented Sep 20, 2016

Just to be clear, this option would only be useful if one single bluetooth characteristic supports Write w Response AND Write w/o Response at the same time. In this case, UA may choose the bad one by default I agree.
If not, UA will always choose the right option, the one that is specified by the writable bluetooth characteristic's properties.

@ghost
Copy link

ghost commented Jan 31, 2018

@beaufortfrancois I have a device with a characteristic which supports both write and write without response. The device is the BBC micro:bit. It has an event bus which is exposed over Bluetooth via input and output event characteristics. For the input event, you can use either write or write without response. The point is that events are a generalised mechanism for communicating with the micro:bit and the decision as to whether acknowledged or unacknowledged writes are required has to be taken on an application by application basis. We definitely need this.

Some of the standard SIG defined Bluetooth services allow characteristics which support both variants too btw. For example:

Automation IO:
https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.automation_io.xml

Human Interface Device (HID):

https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.human_interface_device.xml

@timmyhadwen
Copy link

Hi All,

Also need this for Silicon Labs Bluetooth over the air updates which have both Write and Write without response. Any updates on whether this can be added in the near future?

Cheers
Tim

@reillyeon
Copy link
Contributor

@timmyhadwen, can you clarify whether you need support for both methods because of your application logic or because the UA is choosing the wrong one (perhaps the device advertises support for both and one is broken)?

@poshaughnessy
Copy link

poshaughnessy commented Jun 28, 2018

On this topic (I hope), please may I check... It looks from the spec that writeValue does not return a response; it says that in the successful case, the Promise will be resolved with undefined?

(We're developing a Bluetooth peripheral and it should be returning a success response from the 'write' command, but I'm not receiving it back...)

I wondered if this is by design and if so, how this would fit in with this split between write with response, and write without response. Should write with response return a value from the Promise?

@g-ortuno
Copy link
Contributor

@poshaughnessy: in both cases the promise returned by writeValue should resolve. This sounds like a bug with the implementation or the peripheral. Would you mind opening a bug at http://crbug.com/new with a repro case? If you can include logs that would be great. Instructions at: https://www.chromium.org/developers/how-tos/file-web-bluetooth-bugs

@ghost
Copy link

ghost commented Dec 24, 2018

I'm wondering if this is this ever going to be addressed?

It's clearly a mistake in the Web Bluetooth specification. Characteristics may support both WRITE (requests) and WRITE WITHOUT RESPONSE and a browser cannot be expected to second guess which is the most appropriate to use for a given application. Only the application developer can decide whether reliability or responsiveness are their priorities. There need to be two distinct APIs available or a flag which allows developers to indicate which variant should be used. You can continue to default to the current auto (not very) magic approach for backward compatibility.

There are plenty of examples of characteristics with both write operations supported, clearly documented at bluetooth.com.

@beaufortfrancois
Copy link
Member

beaufortfrancois commented Jan 2, 2019

@reillyeon @dougt Shall we add writeValueWithResponse(data) and writeValueWithoutResponse(data) methods to the Web Bluetooth Spec on top of the existing writeValue(data) method?

@Emill
Copy link

Emill commented Mar 18, 2019

BlueZ now finally supports to select which write type to perform (Write With Response or Write Without Response) since https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=fa9473bcc48417d69cc9ef81d41a72b18e34a55a. This means it is now implementable on all platforms, so there shouldn't be any reason to hide the option for the user anymore.

As we have seen, there are multiple devices out in the market allowing both write types and it would be good to fully support them.

@jyasskin
Copy link
Member

I'm not implementing this and don't know when @reillyeon's team will have time, but I'd probably design the API as, writeValue(data, {response: "with"|"without"|"guess"}), although I haven't thought through the exact strings in that options struct.

@Emill
Copy link

Emill commented Mar 18, 2019

I think I would rather use auto instead of guess, since it doesn't guess anything. It picks whatever is possible according to the characteristic properties.

@MikeTheDane
Copy link

I suggest the following:
writeValue(data) for backward compatibility. Does whatever currently is used.
writeValue(data, true) for GATT Write
writeValue(data, false) for GATT Write Without Response

@ghost
Copy link

ghost commented Apr 11, 2019

@MikeTheDane 's suggestion looks good to me.

@beaufortfrancois
Copy link
Member

@reillyeon Do you think you'd have time to implement this? If not, I'm happy to have a look and start prototyping something.

@beaufortfrancois
Copy link
Member

beaufortfrancois commented Apr 12, 2019

@MikeTheDane, @bluetooth-mdw, @Emill, @poshaughnessy, @timmyhadwen, @martijnthe What do you think of this proposal?
If that looks good to you, I'll send a PR to update the spec for @reillyeon, @jyasskin and @g-ortuno to have a look.

// Write value to a BLE characteristic. Client trusts UA to know which type to send.
try {
  await myCharacteristic.writeValue(someData, { response: 'auto' });
  // OR await `myCharacteristic.writeValue(someData);`
} catch(error) {
  // Error is thrown if BLE characteristic does NOT support any write operation.
}

// Write value with response to a BLE characteristic.
try {
  await myCharacteristic.writeValue(someData, { response: 'with' });
} catch(error) {
  // [NEW] Error is thrown if BLE characteristic does NOT support writeWithResponse.
}

// Write value without response to a BLE characteristic.
try {
  await myCharacteristic.writeValue(someData, { response: 'without' });
} catch(error) {
  // [NEW] Error is thrown if BLE characteristic does NOT support writeWithoutResponse.
}

@Emill
Copy link

Emill commented Apr 12, 2019

Yes that looks ok to me!

@reillyeon
Copy link
Contributor

reillyeon commented Apr 12, 2019

I think the advantage of "auto", "with" and "without" is that they somewhat map to the language in the spec but in isolation I feel like writeValue(someData, { response: 'with' }) will be hard for a reader to interpret. Does it mean that the response is "with"? As an alternative can I suggest "optional" (the current behavior), "required" (write with response), and "never" (write without response)?

@MikeTheDane
Copy link

MikeTheDane commented Apr 29, 2020 via email

@ghost
Copy link

ghost commented Apr 29, 2020

I agree with @MikeTheDane . The remote device will enforce its own rules anyway.

@odejesush
Copy link
Contributor

Please correct me if I'm wrong, but it sounds like there's still agreement to have two explicit methods for write with/without response while keeping the original writeValue. This change was already added to the spec with #433. It also looks like there's agreement that the specified write should be done regardless of the characteristic properties. I also agree with these ideas.

If that's the case, what's left is to agree on a default algorithm for writeValue(), which @scheib and @g-ortuno prefer writeWithResponse(). Would this algorithm also be the "best effort write" @MikeTheDane and @bluetooth-mdw ?

@MikeTheDane
Copy link

MikeTheDane commented Apr 29, 2020 via email

@g-ortuno
Copy link
Contributor

The issue with best effort is that it's not specified, so what we do depends on the underlying platform. I think it would be good to specify what we mean by best effort.

@MikeTheDane
Copy link

MikeTheDane commented Apr 30, 2020 via email

@odejesush
Copy link
Contributor

For not using writeValue() correct? It would still be good to explicitly state what writeValue() will do so that its behavior is consistent cross-platform, even if it is discouraged from being used.

@dlech
Copy link
Contributor

dlech commented Apr 30, 2020

FWIW, the current implementation of writeValue() in chromium is already inconsistent across platforms, so "fixing" it could break existing users. For example, Android currently prefers write without response while other platforms prefer write with response if both corresponding write properties are set on a characteristic. Another example, BlueZ will give a NOT_SUPPORTED error when attempting to write if no write property flags are set while other platforms will raise a NOT_PERMITTED error.

@odejesush
Copy link
Contributor

That's one reason that the specification should declare what algorithm writeValue() should use. That would clear up any confusion on how this API is implemented for both users and implementors.

As for the error, the algorithm for write value currently specifies that in that scenario, NotSupportedError should be thrown. So it looks like that's a bug for Chromium's implementation using BlueZ.

@MikeTheDane
Copy link

MikeTheDane commented May 1, 2020 via email

@odejesush
Copy link
Contributor

Ah, I misunderstood where the error was coming from. From a Web Bluetooth point of view, I was suggesting that the error returned should be consistent if the platform does not support writing to a characteristic without the write property set. I do acknowledge that this might not be easy to do given that different errors are produced by different platforms.

I see what you mean now, and I agree now that writeValue() should be kept as is and eventually become deprecated in favor of the more specific write operations.

@reillyeon
Copy link
Contributor

I agree that writeValue() should be deprecated in favor of the new methods. I also agree with removing enforcement that the device supports the requested algorithm in order to provide broader compatibility. We could add a (one time) console warning when using an unsupported method but let the request proceed.

dlech added a commit to pybricks/web-bluetooth that referenced this issue May 11, 2020
This deprecates BluetoothRemoteGATTCharacteristic.writeValue() in
favor of writeValueWithResponse() and writeValueWithoutResponse().

Issue: WebBluetoothCG#238
dlech added a commit to pybricks/web-bluetooth that referenced this issue May 11, 2020
This deprecates BluetoothRemoteGATTCharacteristic.writeValue() in
favor of writeValueWithResponse() and writeValueWithoutResponse().

Issue: WebBluetoothCG#238
dlech added a commit to pybricks/web-bluetooth that referenced this issue May 11, 2020
This deprecates BluetoothRemoteGATTCharacteristic.writeValue() in
favor of writeValueWithResponse() and writeValueWithoutResponse().

Issue: WebBluetoothCG#238
odejesush pushed a commit that referenced this issue May 13, 2020
This deprecates BluetoothRemoteGATTCharacteristic.writeValue() in
favor of writeValueWithResponse() and writeValueWithoutResponse().

Issue: #238
blueboxd pushed a commit to blueboxd/chromium-legacy that referenced this issue May 19, 2020
This deprecates the current implementation of WriteRemoteCharacteristic.

This implementation has been found to have issues when dealing with
writing with response vs. writing without response. For example, most
platforms look at characteristic properties to determine which to use
and prefer writing with response if both are available while Android
uses the OS default without looking the properties.

Furthermore, there is currently no way to explicitly select writing
with or without response.

WriteRemoteCharacteristic will be replaced by a new implementation in
crrev.com/c/2191232. However, to maintain backward compatibility we need
to keep the current implementation as-is. So, we rename it to
DeprecatedWriteRemoteCharacteristic. Unit tests that test this method
are also renamed accordingly.

Ref: WebBluetoothCG/web-bluetooth#238

Also fix spelling of "already" in a comment while we are touching this
code.

Bug: 672648
Change-Id: I4469a51de960e2b6215b8f402318ee901ba5c335
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2191231
Commit-Queue: Reilly Grant <[email protected]>
Reviewed-by: Ryan Hansberry <[email protected]>
Reviewed-by: Sonny Sasaka <[email protected]>
Reviewed-by: Hidehiko Abe <[email protected]>
Reviewed-by: Reilly Grant <[email protected]>
Reviewed-by: Ovidio de Jesús Ruiz-Henríquez <[email protected]>
Reviewed-by: Vincent Scheib <[email protected]>
Cr-Commit-Position: refs/heads/master@{#769901}
@scheib
Copy link
Contributor

scheib commented May 29, 2020

Interested web-devs:

@dlech 's chromium patch adding writeValueWithoutResponse etc landed via https://crrev.com/c/2159770.

Give it a try in Chrome Canary with chrome://flags/#enable-experimental-web-platform-features set.

@reillyeon
Copy link
Contributor

The new writeWithResponse() and writeWithoutResponse() methods are available in Chrome 85.

pwespi added a commit to capacitor-community/bluetooth-le that referenced this issue Jul 3, 2021
pwespi added a commit to capacitor-community/bluetooth-le that referenced this issue Jul 3, 2021
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