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

Open
martijnthe opened this issue May 4, 2016 · 41 comments

Comments

Projects
None yet
@martijnthe
Copy link

commented May 4, 2016

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link
Author

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link
Member

commented Aug 3, 2016

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

@360fun

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Member

commented Aug 4, 2016

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Member

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.

@bluetooth-mdw

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

commented May 24, 2018

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

This comment has been minimized.

Copy link
Contributor

commented May 25, 2018

@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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Contributor

commented Jun 29, 2018

@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

@bluetooth-mdw

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Member

commented Mar 18, 2019

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

commented Apr 11, 2019

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

@bluetooth-mdw

This comment has been minimized.

Copy link

commented Apr 11, 2019

@MikeTheDane 's suggestion looks good to me.

@beaufortfrancois

This comment has been minimized.

Copy link
Member

commented Apr 11, 2019

@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

This comment has been minimized.

Copy link
Member

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

This comment has been minimized.

Copy link

commented Apr 12, 2019

Yes that looks ok to me!

@reillyeon

This comment has been minimized.

Copy link
Contributor

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)?

@g-ortuno

This comment has been minimized.

Copy link
Contributor

commented Apr 12, 2019

What about making a separate function for WriteWithoutResponse? It feels weird to return a promise for an operation without a response.

@thegecko

This comment has been minimized.

Copy link
Contributor

commented Apr 12, 2019

It feels weird to return a promise for an operation without a response

I guess an over-arching decision is whether to merge similar functions which differ using an options object vs specifying different functions altogether. I see the confusion in this case, but would expect the user to simply ignore the promise returned.

@Emill

This comment has been minimized.

Copy link

commented Apr 12, 2019

I think if a user would specify the write type rather than leave it out, he/she would have good knowledge of the Bluetooth spec and the different options already. I though have to admit that "response: with" sounds a bit weird so I am open to other naming.

About receiving a promise even for write without response, that might be good for flow controlling. For example, on Android you need to wait for the callback even if you use write without response because it will wait before delivering the callback in case the buffers are full.

@MikeTheDane

This comment has been minimized.

Copy link

commented Apr 12, 2019

I like the terms suggested by @reillyeon. They seem pretty intuitive. But a separate function would be optimal (I agree with @Emill that a promise is definitely applicable to GATT Write w/o response)

@beaufortfrancois

This comment has been minimized.

Copy link
Member

commented Apr 15, 2019

We could also decide to add two new methods writeValueWithResponse and writeValueWithoutResponse.

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

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

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

This comment has been minimized.

Copy link
Contributor

commented Apr 15, 2019

New methods seem most readable to me.

@MikeTheDane

This comment has been minimized.

Copy link

commented Apr 16, 2019

I absolutely agree that two new methods would be the ideal solution.

@beaufortfrancois

This comment has been minimized.

Copy link
Member

commented Apr 17, 2019

@reillyeon and @MikeTheDane seem to agree.
@thegecko, @bluetooth-mdw, @Emill, @poshaughnessy, @timmyhadwen, @martijnthe What do you think of this proposal?

@Emill

This comment has been minimized.

Copy link

commented Apr 17, 2019

Yes I think it's more clear now.

@martijnthe

This comment has been minimized.

Copy link
Author

commented Apr 17, 2019

+1 for new methods

@bluetooth-mdw

This comment has been minimized.

Copy link

commented Apr 17, 2019

Looks good to me :-)

@thegecko

This comment has been minimized.

Copy link
Contributor

commented Apr 17, 2019

No concerns

@poshaughnessy

This comment has been minimized.

Copy link

commented Apr 17, 2019

I like the separate methods too. Looks intuitive and clear, thanks @beaufortfrancois

@beaufortfrancois

This comment has been minimized.

Copy link
Member

commented Apr 18, 2019

FYI I've just sent a PR to the spec: #433

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.