WebBluetoothCG / web-bluetooth

Bluetooth support for the Web.
http://www.w3.org/community/web-bluetooth/
Other
1.39k stars 188 forks source link

Allow requestDevice for all devices #234

Closed scheib closed 8 years ago

scheib commented 8 years ago

Initially the Web Bluetooth specification has required requestDevice options to filter the set of devices that will be displayed for the user to select from. One argument against allowing developers to request all devices be shown is that out of laziness they may often do so to the detriment of the user's experience.

When devices do not advertise their services and do not have a reliable name that can be used as a filter then there is no way to select devices.

One concrete example is this Bluetooth Rename Tool I made recently (link will break eventually, maybe it will appear on demos page eventually). This tool uses generic_access's gap.device_name, however generic_access is prohibited from being advertized. It is unknown what device names may be already that the user wishes to edit.

I believe other developers will eventually encounter this for devices that don't advertise services and have a multitude of names. Though this should be a small fraction of use.

This demo currently works in Chrome due to a bug allowing a filter of name: "" to return all devices. That isn't the right way to solve this. I'm not clear on how it should be solved, but would like to communicate to developers that they should only ask for all devices when they really need to. Only half jokingly:

navigator.bluetooth.requestDevice({
  filters: [{
    'listAllDevicesEvenThoughItIsAPoorUserExperience': true
  }],
  optionalServices: ['generic_access']
})
nemik commented 8 years ago

I can definitely see a need for limiting a scan-everything mode, but in that case perhaps the filters should be expanded a little bit. Sorry, I'm new to the community here so maybe I haven't seen all the documentation and specs, but according to: https://webbluetoothcg.github.io/web-bluetooth/#dom-requestdeviceoptions-filters the only filters are for service-UUID's and names. Having one for manufacturer UUID would be nice.

One implementation I like very much, on Android, is: http://altbeacon.github.io/android-beacon-library/javadoc/org/altbeacon/beacon/BeaconParser.html I understand that can be too much to pack into a web-spec, but some way to specify flexible filtering would be nice.

For my purpose, I have to pack my sensor data and other info into an advertisement. It would be nice to not need to use additional, precious, advertising bytes on things like service UUID's or names solely for being able to scan for them, when there are more compact options available.

youcangetme commented 8 years ago

OK, so the Web Bluetooth spec is all about connecting devices around me to a website so that I can interact with that website in more interactive and complex fashion, right? What about apps for artists or musicians?

Artists/musicians are notorious for using things as they were never intended by their creators to make or inspire new works. If you limit the API or service spec in such a draconian manner you will eventually limit the usefulness of the spec you are developing.

Yes, by all means give me a method to search for advertised services BUT do not stop me from saying, "Hey! Use any BT-LE sensor as a tone controller for my way cool music app!" OR "Paint with your biorhythms and by banging your head on this impact sensor!"

That was a poor attempt at humor but hopefully you see the point I'm making.

Also, right now there is not a single manufacturer of a Automation IO device I have found that advertises correctly. I have to filter based on known names which is just irritating to no end!

Anyways, thanks for considering my worthless two pennies on the topic of scanning. I personally believe this along with storing connections for reconstitution when returning is VERY important for acceptance and adoption by the public.

jyasskin commented 8 years ago

@nemik Your question is #153: yes, I think it makes sense to filter by manufacturer data and service data.

@youcangetme If you have a concrete use case that we're not supporting, could you file another issue? Everything your comment mentions can be done with the existing filters. e.g. filtering by known names.

@scheib I'm torn: on the one hand, I think most uses of this API will be for applications that need to talk to particular devices that can be identified by their advertisements. It's only the generic utilities that need to look at arbitrary devices, and those are likely served better by native apps anyway, so they're not constrained by the web's permission restrictions. However, to popularize the API, maybe we do want to implement some generic utilities like the rename tool and @beaufortfrancois' GAP reader.

We could allow folks to list 'generic_access' and 'generic_attribute' in their services filter and infer that all devices match that even though they don't explicitly advertise it. I'm inclined to put some restriction on those requests, for example that they can't have other filters or list any optional services, but I'm not sure that's the best idea. Maybe just a scary key is the way to go.

scheib commented 8 years ago

Re: "only the generic utilities that need to look at arbitrary devices, and those are likely served better by native apps anyway, so they're not constrained by the web's permission restrictions":

Generic utilities may be great or better on web tech vs native. E.g. I needed that rename tool and was able to author it quickly using the web stack. The web permission model didn't get in the way. I wouldn't have bothered starting with writing a native application. I could easily see folks writing quick custom apps to help e.g. provision a large number of devices using certain rules or constraints.

Vudentz commented 8 years ago

A tool to discover GATT attribute would be great, but Im afraid there could be some security problems with some services such as GAP as it is used to expose lower layer details of GAP over GATT there is always a risk that we don't blacklist something important, or the blacklist is outdated, and something gets leaked. Another observation I have is that GAP roles and GATT roles may not be related, you may have a GAP peripheral that acts as GATT client or a GAP central that is a GATT server, there also the possibility that the profile is not GATT based. e.g. uses a different L2CAP channel or only really uses advertising to broadcast something, in those cases there may be no service(s) to match and that should be ok.

beaufortfrancois commented 8 years ago

@jyasskin What do you think about GAP Service issue raised by @Vudentz? For info, we have a crbug for this at https://bugs.chromium.org/p/chromium/issues/detail?id=611678

jyasskin commented 8 years ago
scheib commented 8 years ago

So, perhaps developers will solve this with something such as:

navigator.bluetooth.requestDevice({
  filters: [
    { name: '' },
    { namePrefix: '0' },
    { namePrefix: '1' },
    { namePrefix: '2' },
    { namePrefix: '3' },
    { namePrefix: '4' },
    { namePrefix: '5' },
    { namePrefix: '6' },
    { namePrefix: '7' },
    { namePrefix: '8' },
    { namePrefix: '9' },
    { namePrefix: 'a' },
    { namePrefix: 'b' },
    { namePrefix: 'c' },
    { namePrefix: 'd' },
    { namePrefix: 'e' },
    { namePrefix: 'f' },
    { namePrefix: 'g' },
    { namePrefix: 'h' },
    { namePrefix: 'i' },
    { namePrefix: 'j' },
    { namePrefix: 'k' },
    { namePrefix: 'l' },
    { namePrefix: 'm' },
    { namePrefix: 'n' },
    { namePrefix: 'o' },
    { namePrefix: 'p' },
    { namePrefix: 'q' },
    { namePrefix: 'r' },
    { namePrefix: 's' },
    { namePrefix: 't' },
    { namePrefix: 'u' },
    { namePrefix: 'v' },
    { namePrefix: 'w' },
    { namePrefix: 'x' },
    { namePrefix: 'y' },
    { namePrefix: 'z' },
    { namePrefix: 'A' },
    { namePrefix: 'B' },
    { namePrefix: 'C' },
    { namePrefix: 'D' },
    { namePrefix: 'E' },
    { namePrefix: 'F' },
    { namePrefix: 'G' },
    { namePrefix: 'H' },
    { namePrefix: 'I' },
    { namePrefix: 'J' },
    { namePrefix: 'K' },
    { namePrefix: 'L' },
    { namePrefix: 'M' },
    { namePrefix: 'N' },
    { namePrefix: 'O' },
    { namePrefix: 'P' },
    { namePrefix: 'Q' },
    { namePrefix: 'R' },
    { namePrefix: 'S' },
    { namePrefix: 'T' },
    { namePrefix: 'U' },
    { namePrefix: 'V' },
    { namePrefix: 'W' },
    { namePrefix: 'X' },
    { namePrefix: 'Y' },
    { namePrefix: 'Z' }
  ],
  optionalServices: ['generic_access']
})

And, perhaps that's better / nearly equivalent to the obvious intent and ugliness of filters: [{ 'listAllDevicesEvenThoughItIsAPoorUserExperience': true }],

I'm happy having just thought of that, knowing that a device rename tool should be possible no matter how we decide the syntax here.

scheib commented 8 years ago

I take this back, this work around is not sufficient to match devices that do not advertise a name or service UUIDs. ;) Those devices may be 'doing it wrong', or they may have some other motivation, e.g. using all of the ad packet for service data etc. No matter why, I'd still like Web Bluetooth apps to be able to connect to them if a native app can do so.

jyasskin commented 8 years ago

If a device doesn't advertise a name, there's nothing user-understandable to put in the picker, so we probably wouldn't show the device at all. As I mentioned before, we should add filters for service and manufacturer data.

scheib commented 8 years ago

Bluetooth UI choosers have displayed unnamed devices for many years. E.G Chrome uses the appearance and the address to generate a name for UI. Other platforms use conventions such as "unknown device", which while not ideal are still functional. Not having a name isn't a reason to not connect to a device.

beaufortfrancois commented 8 years ago

I wonder what is the intent behind requestDevice... If the next step is to connect to the GATT Server afterwards, we should only show devices that advertised themselves as connectable. If not, we may want to add a connectable filter then so that we show all devices, even those who are not connectable. I'd say it should be true by default though.

navigator.bluetooth.requestDevice({
  filters: [{
    'listAllDevicesEvenThoughItIsAPoorUserExperience': true,
    'connectable': false
  }],
  optionalServices: ['generic_access']
})
jyasskin commented 8 years ago

Check out https://github.com/WebBluetoothCG/web-bluetooth/pull/278 for my attempt to allow this.