1. Introduction
This section is non-normative.
Bluetooth is a standard for short-range wireless communication between devices. Bluetooth "Classic" ( BR / EDR ) defines a set of binary protocols and supports speeds up to about 24Mbps. Bluetooth 4.0 introduced a new "Low Energy" mode known as "Bluetooth Smart", BLE , or just LE which is limited to about 1Mbps but allows devices to leave their transmitters off most of the time. BLE provides most of its functionality through key/value pairs provided by the Generic Attribute Profile ( GATT ) .
BLE defines multiple roles that devices can play. The Broadcaster and Observer roles are for transmitter- and receiver-only applications, respectively. Devices acting in the Peripheral role can receive connections, and devices acting in the Central role can connect to Peripheral devices.
A device acting in either the Peripheral or Central role can host a GATT Server , which exposes a hierarchy of Service s, Characteristic s, and Descriptor s. See § 6.1 GATT Information Model for more details about this hierarchy. Despite being designed to support BLE transport, the GATT protocol can also run over BR/EDR transport.
The first version of this specification allows web pages, running on a UA in the Central role, to connect to GATT Server s over either a BR/EDR or LE connection. While this specification cites the [BLUETOOTH42] specification, it intends to also support communication among devices that only implement Bluetooth 4.0 or 4.1.
1.1. Examples
let chosenHeartRateService= null ; navigator. bluetooth. requestDevice({ filters: [{ services: [ 'heart_rate' ], }] }). then( device=> device. gatt. connect() ) . then( server=> server. getPrimaryService( 'heart_rate' )) . then( service=> { chosenHeartRateService= service; return Promise. all([ service. getCharacteristic( 'body_sensor_location' ) . then( handleBodySensorLocationCharacteristic), service. getCharacteristic( 'heart_rate_measurement' ) . then( handleHeartRateMeasurementCharacteristic), ]); }); function handleBodySensorLocationCharacteristic( characteristic) { if ( characteristic=== null ) { console. log( "Unknown sensor location." ); return Promise. resolve(); } return characteristic. readValue() . then( sensorLocationData=> { const sensorLocation= sensorLocationData. getUint8( 0 ); switch ( sensorLocation) { case 0 : return 'Other' ; case 1 : return 'Chest' ; case 2 : return 'Wrist' ; case 3 : return 'Finger' ; case 4 : return 'Hand' ; case 5 : return 'Ear Lobe' ; case 6 : return 'Foot' ; default : return 'Unknown' ; } }). then( location=> console. log( location)); } function handleHeartRateMeasurementCharacteristic( characteristic) { return characteristic. startNotifications() . then( char => { characteristic. addEventListener( ' characteristicvaluechanged ' , onHeartRateChanged); }); } function onHeartRateChanged( event) { const characteristic= event. target; console. log( parseHeartRate( characteristic. value)); }
parseHeartRate()
would
be
defined
using
the
heart_rate_measurement
documentation
to
read
the
DataView
stored
in
a
BluetoothRemoteGATTCharacteristic
’s
value
field.
function parseHeartRate( data) { const flags= data. getUint8( 0 ); const rate16Bits= flags& 0x1 ; const result= {}; let index= 1 ; if ( rate16Bits) { result. heartRate= data. getUint16( index, /*littleEndian=*/ true ); index+= 2 ; } else { result. heartRate= data. getUint8( index); index+= 1 ; } const contactDetected= flags& 0x2 ; const contactSensorPresent= flags& 0x4 ; if ( contactSensorPresent) { result. contactDetected= !! contactDetected; } const energyPresent= flags& 0x8 ; if ( energyPresent) { result. energyExpended= data. getUint16( index, /*littleEndian=*/ true ); index+= 2 ; } const rrIntervalPresent= flags& 0x10 ; if ( rrIntervalPresent) { const rrIntervals= []; for (; index+ 1 < data. byteLength; index+= 2 ) { rrIntervals. push( data. getUint16( index, /*littleEndian=*/ true )); } result. rrIntervals= rrIntervals; } return result; }
onHeartRateChanged()
might
log
an
object
like
{ heartRate: 70 , contactDetected: true , energyExpended: 750 , // Meaning 750kJ. rrIntervals: [ 890 , 870 ] // Meaning .87s and .85s. }
If
the
heart
rate
sensor
reports
the
energyExpended
field,
the
web
application
can
reset
its
value
to
0
by
writing
to
the
heart_rate_control_point
characteristic:
function resetEnergyExpended() { if ( ! chosenHeartRateService) { return Promise. reject( new Error ( 'No heart rate sensor selected yet.' )); } return chosenHeartRateService. getCharacteristic( 'heart_rate_control_point' ) . then( controlPoint=> { const resetEnergyExpended= new Uint8Array([ 1 ]); return controlPoint. writeValue( resetEnergyExpended); }); }
2. Security considerations
See § 3 Privacy considerations section. [Issue #575]
3. Privacy considerations
3.1. Device access is powerful
When
a
website
requests
access
to
devices
using
requestDevice()
,
it
gets
the
ability
to
access
all
GATT
services
mentioned
in
the
call.
The
UA
MUST
inform
the
user
what
capabilities
these
services
give
the
website
before
asking
which
devices
to
entrust
to
it.
If
any
services
in
the
list
aren’t
known
to
the
UA,
the
UA
MUST
assume
they
give
the
site
complete
control
over
the
device
and
inform
the
user
of
this
risk.
The
UA
MUST
also
allow
the
user
to
inspect
what
sites
have
access
to
what
devices
and
revoke
these
pairings.
The UA MUST NOT allow the user to pair entire classes of devices with a website. It is possible to construct a class of devices for which each individual device sends the same Bluetooth-level identifying information. UAs are not required to attempt to detect this sort of forgery and MAY let a user pair this pseudo-device with a website.
To help ensure that only the entity the user approved for access actually has access, this specification requires that only secure contexts can access Bluetooth devices.
3.2. Trusted servers can serve malicious code
This section is non-normative.
Even if the user trusts an origin, that origin’s servers or developers could be compromised, or the origin’s site could be vulnerable to XSS attacks. Either could lead to users granting malicious code access to valuable devices. Origins should define a Content Security Policy ( [CSP3] ) to reduce the risk of XSS attacks, but this doesn’t help with compromised servers or developers.
The ability to retrieve granted devices after a page reload, provided by § 4.1 Permission API Integration , makes this risk worse. Instead of having to get the user to grant access while the site is compromised, the attacker can take advantage of previously-granted devices if the user simply visits while the site is compromised. On the other hand, when sites can keep access to devices across page reloads, they don’t have to show as many permission prompts overall, making it more likely that users will pay attention to the prompts they do see.
3.3. Attacks on devices
This section is non-normative.
Communication from websites can break the security model of some devices, which assume they only receive messages from the trusted operating system of a remote device. Human Interface Devices are a prominent example, where allowing a website to communicate would allow that site to log keystrokes. This specification includes a GATT blocklist of such vulnerable services, characteristics, and descriptors to prevent websites from taking advantage of them.
We expect that many devices are vulnerable to unexpected data delivered to their radio. In the past, these devices had to be exploited one-by-one, but this API makes it plausible to conduct large-scale attacks. This specification takes several approaches to make such attacks more difficult:
-
Pairing individual devices instead of device classes requires at least a user action before a device can be exploited.
-
Constraining access to GATT , as opposed to generic byte-stream access, denies malicious websites access to most parsers on the device.
On the other hand, GATT’s Characteristic and Descriptor values are still byte arrays, which may be set to lengths and formats the device doesn’t expect. UAs are encouraged to validate these values when they can.
-
This API never exposes Bluetooth addressing, data signing or encryption keys ( Definition of Keys and Values ) to websites. This makes it more difficult for a website to predict the bits that will be sent over the radio, which blocks packet-in-packet injection attacks . Unfortunately, this only works over encrypted links, which not all BLE devices are required to support.
-
The integration with § 11.1 Permissions Policy provides protection against unwanted access to Bluetooth capabilities, which requires the top-level document to explicitly allow a cross-origin iframe to use the API’s methods.
UAs can also take further steps to protect their users:
-
A web service may collect lists of malicious websites and vulnerable devices. UAs can deny malicious websites access to any device and any website access to vulnerable devices.
3.4. Bluetooth device identifiers
This section is non-normative.
Each Bluetooth BR/EDR device has a unique 48-bit MAC address known as the BD_ADDR . Each Bluetooth LE device has at least one of a Public Device Address and a Static Device Address . The Public Device Address is a MAC address. The Static Device Address may be regenerated on each restart. A BR/EDR/LE device will use the same value for the BD_ADDR and the Public Device Address (specified in the Read BD_ADDR Command ).
An LE device may also have a unique, 128-bit Identity Resolving Key , which is sent to trusted devices during the bonding process. To avoid leaking a persistent identifier, an LE device may scan and advertise using a random Resolvable or Non-Resolvable Private Address instead of its Static or Public Address. These are regenerated periodically (approximately every 15 minutes), but a bonded device can check whether one of its stored IRK s matches any given Resolvable Private Address using the Resolvable Private Address Resolution Procedure .
Each Bluetooth device also has a human-readable Bluetooth Device Name . These aren’t guaranteed to be unique, but may well be, depending on the device type.
3.4.1. Identifiers for remote Bluetooth devices
This section is non-normative.
If a website can retrieve any of the persistent device IDs, these can be used, in combination with a large effort to catalog ambient devices, to discover a user’s location. A device ID can also be used to identify that a user who pairs two different websites with the same Bluetooth device is a single user. On the other hand, many GATT services are available that could be used to fingerprint a device, and a device can easily expose a custom GATT service to make this easier.
This specification suggests that the UA use different device IDs for a single device when its user doesn’t intend scripts to learn that it’s a single device, which makes it difficult for websites to abuse the device address like this. Device makers can still design their devices to help track users, but it takes work.
3.4.2. The UA’s Bluetooth address
This section is non-normative.
In BR/EDR mode, or in LE mode during active scanning without the Privacy Feature , the UA broadcasts its persistent ID to any nearby Bluetooth radio. This makes it easy to scatter hostile devices in an area and track the UA. As of 2014-08, few or no platforms document that they implement the Privacy Feature , so despite this spec recommending it, few UAs are likely to use it. This spec does require a user gesture for a website to trigger a scan, which reduces the frequency of scans some, but it would still be better for more platforms to expose the Privacy Feature .
3.5. Exposing Bluetooth availability
This section is non-normative.
navigator.bluetooth.
exposes
whether
a
Bluetooth
radio
is
available
on
the
user’s
system,
regardless
of
whether
it
is
powered
on
or
not.
The
availability
is
also
affected
if
the
user
has
configured
the
UA
to
block
Web
Bluetooth.
Some
users
might
consider
this
private,
although
it’s
hard
to
imagine
the
damage
that
would
result
from
revealing
it.
This
information
also
increases
the
UA’s
fingerprinting
surface
by
a
bit.
This
function
returns
a
getAvailability()
Promise
,
so
UAs
have
the
option
of
asking
the
user
what
value
they
want
to
return,
but
we
expect
the
increased
risk
to
be
small
enough
that
UAs
will
choose
not
to
prompt.
4. Device Discovery
dictionary {BluetoothDataFilterInit BufferSource ;dataPrefix BufferSource ; };mask dictionary :BluetoothManufacturerDataFilterInit BluetoothDataFilterInit {required [EnforceRange ]unsigned short ; };companyIdentifier dictionary :BluetoothServiceDataFilterInit BluetoothDataFilterInit {required BluetoothServiceUUID ; };service dictionary {BluetoothLEScanFilterInit sequence <BluetoothServiceUUID >services ;DOMString name ;DOMString namePrefix ;sequence <BluetoothManufacturerDataFilterInit >manufacturerData ;sequence <BluetoothServiceDataFilterInit >serviceData ; };dictionary {RequestDeviceOptions sequence <BluetoothLEScanFilterInit >filters ;sequence <BluetoothLEScanFilterInit >exclusionFilters ;sequence <BluetoothServiceUUID >optionalServices = [];sequence <unsigned short >optionalManufacturerData = [];boolean acceptAllDevices =false ; }; [Exposed =Window ,SecureContext ]interface :Bluetooth EventTarget {Promise <boolean >getAvailability ();attribute EventHandler ; [onavailabilitychanged SameObject ]readonly attribute BluetoothDevice ?referringDevice ;Promise <sequence <BluetoothDevice >>getDevices ();Promise <BluetoothDevice >requestDevice (optional RequestDeviceOptions = {}); };options Bluetooth includes BluetoothDeviceEventHandlers ;Bluetooth includes CharacteristicEventHandlers ;Bluetooth includes ServiceEventHandlers ;
Methods defined in this specification typically complete asynchronously, queuing work on a Bluetooth task source .
Bluetooth
members
getAvailability()
informs
the
page
whether
Bluetooth
is
available
at
all.
An
adapter
that’s
disabled
through
software
should
count
as
available.
Changes
in
availability,
for
example
when
the
user
physically
attaches
or
detaches
an
adapter,
are
reported
through
the
availabilitychanged
event.
referringDevice
gives
access
to
the
device
from
which
the
user
opened
this
page,
if
any.
For
example,
an
Eddystone
beacon
might
advertise
a
URL,
which
the
UA
allows
the
user
to
open.
A
BluetoothDevice
representing
the
beacon
would
be
available
through
navigator.bluetooth.
.
referringDevice
getDevices()
enables
the
page
to
retrieve
Bluetooth
devices
that
the
user
has
granted
access
to.
requestDevice(options)
asks
the
user
to
grant
this
origin
access
to
a
device
that
matches
any
filter
in
options.
but
does
not
match
any
filter
in
filters
options.
.
To
match
a
filter
,
the
device
has
to:
exclusionFilters
-
support all the GATT service UUIDs in the
serviceslist if that member is present, -
have a name equal to
nameif that member is present, -
have a name starting with
namePrefixif that member is present, -
advertise manufacturer specific data matching all of the values in
manufacturerDataif that member is present, and -
advertise service data matching all of the values in
serviceDataif that member is present.
Both
Manufacturer
Specific
Data
and
Service
Data
map
a
key
to
an
array
of
bytes.
BluetoothDataFilterInit
filters
these
arrays.
An
array
matches
if
it
has
a
prefix
such
that
prefix
&
is
equal
to
mask
.
dataPrefix
&
mask
Note that if a device changes its behavior significantly when it connects, for example by not advertising its identifying manufacturer data anymore and instead having the client discover some identifying GATT services, the website may need to include filters for both behaviors.
In
rare
cases,
a
device
may
not
advertise
enough
distinguishing
information
to
let
a
site
filter
out
uninteresting
devices.
In
those
cases,
a
site
can
set
acceptAllDevices
to
true
and
omit
all
filters
and
exclusionFilters
.
This
puts
the
burden
of
selecting
the
right
device
entirely
on
the
site’s
users.
If
a
site
uses
acceptAllDevices
,
it
will
only
be
able
to
use
services
listed
in
optionalServices
.
After
the
user
selects
a
device
to
pair
with
this
origin,
the
origin
is
allowed
to
access
any
service
whose
UUID
was
listed
in
the
services
list
in
any
element
of
options.filters
or
in
options.
.
The
origin
is
also
allowed
to
access
any
manufacturer
data
from
manufacturer
codes
defined
in
optionalServices
options.
from
the
device’s
advertisement
data.
optionalManufacturerData
This
implies
that
if
developers
filter
just
by
name,
they
must
use
optionalServices
to
get
access
to
any
services.
| Device | Advertised Services |
|---|---|
| D1 | A, B, C, D |
| D2 | A, B, E |
| D3 | C, D |
| D4 | E |
| D5 | <none> |
If the website calls
navigator. bluetooth. requestDevice({ filters: [ { services: [ A, B]} ] });
the user will be shown a dialog containing devices D1 and D2. If the user selects D1, the website will not be able to access services C or D. If the user selects D2, the website will not be able to access service E.
On the other hand, if the website calls
navigator. bluetooth. requestDevice({ filters: [ { services: [ A, B]}, { services: [ C, D]} ] });
the dialog will contain devices D1, D2, and D3, and if the user selects D1, the website will be able to access services A, B, C, and D.
If the website then calls
navigator. bluetooth. getDevices();
the
resulting
Promise
will
resolve
into
an
array
containing
device
D1,
and
the
website
will
be
able
to
access
services
A,
B,
C,
and
D.
The
optionalServices
list
doesn’t
add
any
devices
to
the
dialog
the
user
sees,
but
it
does
affect
which
services
the
website
can
use
from
the
device
the
user
picks.
navigator. bluetooth. requestDevice({ filters: [ { services: [ A, B]} ], optionalServices: [ E] });
Shows a dialog containing D1 and D2, but not D4, since D4 doesn’t contain the required services. If the user selects D2, unlike in the first example, the website will be able to access services A, B, and E.
If the website calls
navigator. bluetooth. getDevices();
again,
then
the
resulting
Promise
will
resolve
into
an
array
containing
the
devices
D1
and
D2.
The
A,
B,
C,
and
D
services
will
be
accessible
on
device
D1,
while
A,
B,
and
E
services
will
be
accessible
on
device
D2.
The
allowed
services
also
apply
if
the
device
changes
after
the
user
grants
access.
For
example,
if
the
user
selects
D1
in
the
previous
requestDevice()
call,
and
D1
later
adds
a
new
E
service,
that
will
fire
the
serviceadded
event,
and
the
web
page
will
be
able
to
access
service
E.
| Device | Advertised Device Name |
|---|---|
| D1 | First De… |
| D2 | <none> |
| D3 | Device Third |
| D4 | Device Fourth |
| D5 | Unique Name |
The
following
table
shows
which
devices
the
user
can
select
between
for
several
values
of
filters
passed
to
navigator.bluetooth.requestDevice({filters:
filters
})
.
| filters | Devices | Notes |
|---|---|---|
| D5 | |
| D3, D4 | |
| <none> | D1 only advertises a prefix of its name, so trying to match its whole name fails. |
| D1, D5 | |
| D3, D5 |
The
following
table
shows
which
devices
the
user
can
select
between
for
several
values
of
filters
and
exclusionFilters
passed
to
navigator.bluetooth.requestDevice({filters:
filters
,
exclusionFilters:
exclusionFilters
})
.
| filters | exclusionFilters | Devices |
|---|---|---|
|
| D4 |
|
| D3 |
|
| D3 |
| Device | Manufacturer Data | Service Data |
|---|---|---|
| D1 | 17: 01 02 03 | |
| D2 | A: 01 02 03 |
The
following
table
shows
which
devices
the
user
can
select
between
for
several
values
of
filters
passed
to
navigator.bluetooth.requestDevice({filters:
filters
})
.
| filters | Devices |
|---|---|
| D1 |
| D2 |
| D1, D2 |
| <none> |
| D1 |
| <none> |
| D1 |
| D1 |
| <none> |
TypeError
s.
To
accept
all
devices,
use
acceptAllDevices
instead.
| Call | Notes |
|---|---|
requestDevice | Invalid: An absent list of filters doesn’t accept any devices. |
requestDevice | Invalid: An empty list of filters doesn’t accept any devices. |
requestDevice | Invalid: An empty filter accepts all devices, and so isn’t allowed either. |
requestDevice |
Valid:
Explicitly
accept
all
devices
with
acceptAllDevices
.
|
requestDevice |
Invalid:
acceptAllDevices
would
override
any
filters
.
|
requestDevice |
Invalid:
acceptAllDevices
would
override
any
exclusionFilters
.
|
requestDevice |
Invalid:
exclusionFilters
require
filters
.
|
requestDevice |
Invalid:
exclusionFilters
must
be
non-empty
to
exclude
devices.
|
requestDevice |
Invalid:
namePrefix
,
if
present,
must
be
non-empty
to
filter
devices.
|
requestDevice |
Invalid:
manufacturerData
,
if
present,
must
be
non-empty
to
filter
devices.
|
requestDevice |
Invalid:
serviceData
,
if
present,
must
be
non-empty
to
filter
devices.
|
Instances
of
Bluetooth
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[deviceInstanceMap]]
|
An
empty
map
from
Bluetooth
device
s
to
instances.
|
Ensures
only
one
BluetoothDevice
instance
represents
each
Bluetooth
device
inside
a
single
global
object.
|
[[attributeInstanceMap]]
|
An
empty
map
from
Bluetooth
cache
entries
to
Promise
s.
|
The
Promise
s
resolve
to
either
BluetoothRemoteGATTService
,
BluetoothRemoteGATTCharacteristic
,
or
BluetoothRemoteGATTDescriptor
instances.
|
[[referringDevice]]
|
null
|
Set
to
a
BluetoothDevice
while
initializing
the
Document
object
if
the
Document
was
opened
from
the
device.
|
navigator.bluetooth.
referringDevice
must
return
[[referringDevice]]
.
If
this
happens,
then
as
part
of
initializing
the
Document
object
,
the
UA
MUST
run
the
following
steps:
-
Let referringDevice be the device that caused the navigation.
-
Get the
BluetoothDevicerepresenting referringDevice insidenavigator.bluetooth, and let referringDeviceObj be the result. -
If the previous step threw an exception, abort these steps.
Note: This means the UA didn’t infer that the user intended to grant the current realm access to referringDevice . For example, the user might have denied GATT access globally. -
Set
navigator.bluetooth.to referringDeviceObj .[[referringDevice]]
match
:
-
If
filter .is present then, if device ’s Bluetooth Device Name isn’t complete and equal tonamefilter .name, returnmismatch. -
If
filter .is present then if device ’s Bluetooth Device Name isn’t present or doesn’t start withnamePrefixfilter .namePrefix, returnmismatch. -
For each uuid in
filter ., if the UA has not received advertising data, an extended inquiry response , or a service discovery response indicating that the device supports a primary (vs included) service with UUID uuid , returnservicesmismatch. -
For each manufacturerData in
filter [", if device hasn’t advertised manufacturer specific data with a company identifier code equal tomanufacturerData"]manufacturerData ["and with data that matchescompanyIdentifier"]manufacturerDatareturnmismatch. -
For each serviceData in
filter [", if device hasn’t advertised service data with a UUID whose 128-bit form isserviceData"]serviceData ["and with data that matchesservice"]serviceDatareturnmismatch. -
Return
match.
BluetoothDataFilterInit
filter
if
the
following
steps
return
match
.
-
Let expectedPrefix be a copy of the bytes held by
filter ..dataPrefix -
Let mask be a copy of the bytes held by
filter ..mask -
If data has fewer bytes than expectedPrefix , return
mismatch. -
For each
1bit in mask , if the corresponding bit in data is not equal to the corresponding bit in expectedPrefix , returnmismatch. -
Return
match.
BluetoothDataFilterInit
filter1
is
a
strict
subset
of
a
BluetoothDataFilterInit
filter2
if
the
following
steps
return
true
:
-
If the length of filter1 is less than the length of filter2 , return
false. -
Let byteIndex be
0. -
While byteIndex is less than the length of filter2 , do the following sub-steps:
-
If
filter1 .is not equal to filter2 .mask[ byteIndex ] & filter2 .mask[ byteIndex ]mask[ byteIndex ], returnfalse. -
If
filter1 .it not equal todataPrefix[ byteIndex ] & filter2 .mask[ byteIndex ]filter2 ., returndataPrefix[ byteIndex ] & filter2 .mask[ byteIndex ]false. -
Set byteIndex to
byteIndex + 1.
-
-
Return
true.
getDevices()
method,
when
invoked
and
given
a
BluetoothPermissionStorage
storage
,
MUST
run
the
following
steps:
-
Let global be this ’s relevant global object .
-
If global ’s associated Document is not allowed to use the policy-controlled feature named " bluetooth ", return a promise rejected with a
SecurityError. -
Let promise be a new promise .
-
Run the following steps in parallel :
-
Let devices be a new empty
Array. -
For each allowedDevice in
storage ., add theallowedDevicesBluetoothDeviceobject representing allowedDevice @[[device]]to devices . -
Queue a global task on the Bluetooth task source given global to resolve promise with devices .
Note: TheBluetoothDevices in devices may not be in range of the Bluetooth radio. For a given device in devices , thewatchAdvertisements()method can be used to observe when device is in range and broadcasting advertisement packets. When anadvertisementreceivedevent event is fired on a device , it may indicate that it is close enough for a connection to be established by callingevent .device.gatt..connect() -
-
Return promise .
requestDevice(
options
)
method,
when
invoked,
MUST
run
the
following
steps:
-
If
options .is present andexclusionFiltersoptions .is not present, return a promise rejected with afiltersTypeError. -
If
options .is present andfiltersoptions .isacceptAllDevicestrue, or ifoptions .is not present andfiltersoptions .isacceptAllDevicesfalse, return a promise rejected with aTypeError.Note: This enforces that exactly one offiltersoris present.acceptAllDevices:true -
Let promise be a new promise .
-
Run the following steps in parallel :
-
Request Bluetooth devices , passing
options .iffiltersoptions .isacceptAllDevicesfalseornullotherwise, passingoptions .if it exists orexclusionFiltersnullotherwise, passingoptions ., and passingoptionalServicesoptions ., and let devices be the result.optionalManufacturerData -
Queue a global task on the Bluetooth task source given this ’s relevant global object to run the following steps:
-
If the previous step threw an exception, reject promise with that exception and abort these steps.
-
If devices is an empty sequence, reject promise with a
NotFoundErrorand abort these steps. -
Resolve promise with
devices [0].
-
-
-
Return promise .
BluetoothPermissionStorage
storage
and
a
sequence
of
BluetoothLEScanFilterInit
s
filters
,
which
can
be
null
to
represent
that
all
devices
can
match,
a
sequence
of
BluetoothLEScanFilterInit
s
exclusionFilters
,
which
can
be
null
if
no
exclusion
filters
have
been
set,
a
sequence
of
BluetoothServiceUUID
s
optionalServices
,
and
a
sequence
of
unsigned
short
s
optionalManufacturerData
,
the
UA
MUST
run
the
following
steps:
-
Let global be the relevant global object for storage .
-
Let document be global ’s associated Document .
-
If document is not allowed to use the policy-controlled feature named " bluetooth ", throw a
SecurityErrorand abort these steps. -
Check that the algorithm is triggered while its relevant global object has a transient activation , otherwise throw a
SecurityErrorand abort these steps. -
In order to convert the arguments from service names and aliases to just UUID s, do the following sub-steps:
-
If
filters !== null && filters .length === 0, throw aTypeErrorand abort these steps. -
If
exclusionFilters !== null && exclusionFilters .length === 0, throw aTypeErrorand abort these steps. -
Let uuidFilters be a new
Array, uuidExclusionFilters be a newArray, and requiredServiceUUIDs be a newSet. -
If filters is
null, then set requiredServiceUUIDs to the set of all UUIDs. -
If filters isn’t
null, then for each filter in filters , do the following steps:-
Let canonicalFilter be the result of canonicalizing filter .
-
Append canonicalFilter to uuidFilters .
-
Add the contents of
canonicalFilter .servicesto requiredServiceUUIDs .
-
-
If exclusionFilters isn’t
null, then for each exclusionFilter in exclusionFilters , do the following steps:-
Let canonicalExclusionFilter be the result of canonicalizing exclusionFilter .
-
Append canonicalExclusionFilter to uuidExclusionFilters .
-
-
Let optionalServiceUUIDs be
.Array.prototype.map.call( optionalServices ,BluetoothUUID.getService) -
If any of the
BluetoothUUID.getService()calls threw an exception, throw that exception and abort these steps. -
Remove from optionalServiceUUIDs any UUIDs that are blocklisted .
-
-
Let descriptor be
{ name: "bluetooth" , filters: uuidFilters optionalServices: optionalServiceUUIDs, optionalManufacturerData: optionalManufacturerData acceptAllDevices: filters!== null , } -
Let state be descriptor ’s permission state .
Note: state will be "denied" in non-secure contexts because powerful features can’t be used in non-secure contexts . -
If state is "
denied", return[]and abort these steps. -
If the UA can prove that no devices could possibly be found in the next step, for example because there is no Bluetooth adapter with which to scan, or because the filters can’t be matched by any possible advertising packet, the UA MAY return
[]and abort these steps. -
Let scanResult be the result of invoking scan for devices with global and requiredServiceUUIDs .
-
If filters isn’t
null, do the following sub-steps:-
Remove devices from scanResult if they do not match a filter in uuidFilters .
-
If exclusionFilters isn’t
null, remove devices from scanResult if they match a filter in uuidExclusionFilters .
-
-
Let navigable be document ’s navigable .
-
Let promptId be a new unique opaque string.
In
practice,
the
device
list
is
dynamically
updated
while
a
prompt
is
open.
The
spec
text
currently
does
not
reflect
that
but
this
event
might
be
emitted
multiple
times
with
the
same
promptId
and
the
fresh
device
list.
See
https://github.com/WebBluetoothCG/web-bluetooth/issues/621.
-
Trigger a prompt updated event given navigable , promptId , and scanResult .
-
Even if scanResult is empty, prompt the user to choose one of the devices in scanResult , associated with descriptor , and let device be the result.
The UA MAY allow the user to select a nearby device that does not match uuidFilters .
Note: The UA should show the user the human-readable name of each device. If this name is not available because, for example, the UA’s Bluetooth system doesn’t support privacy-enabled scans, the UA should allow the user to indicate interest and then perform a privacy-disabled scan to retrieve the name. -
Remove map of navigables to device prompts [ navigable ’s navigable id ].
-
The UA MAY add device to storage .
Note: Choosing a device probably indicates that the user intends that device to appear in theallowedDeviceslist of "bluetooth" ’s extra permission data for at least the current settings object , for itsmayUseGATTfield to betrue, for all the services in the union of requiredServiceUUIDs and optionalServiceUUIDs to appear in itsallowedServiceslist, in addition to any services that were already there, and for the manufacturer codes in optionalManufacturerData to appear in itsallowedManufacturerDatalist. -
If device is "
denied", return[]and abort these steps. -
The UA MAY populate the Bluetooth cache with all Services inside device . Ignore any errors from this step.
-
Get the
BluetoothDevicerepresenting device inside this , propagating any exception, and let deviceObj be the result. -
Return
[ deviceObj ].
BluetoothLEScanFilterInit
filter
,
is
the
BluetoothLEScanFilterInit
returned
from
the
following
steps:
-
If none of filter ’s members is present, throw a
TypeErrorand abort these steps. -
Let canonicalizedFilter be
{}. -
If
filter .is present, do the following sub-steps:services-
If
filter .services.length === 0, throw aTypeErrorand abort these steps. -
Let services be
.Array.prototype.map.call( filter .services,BluetoothUUID.getService) -
If any of the
BluetoothUUID.getService()calls threw an exception, throw that exception and abort these steps. -
If any service in services is blocklisted , throw a
SecurityErrorand abort these steps. -
Set
canonicalizedFilter .servicesto services .
-
-
If
filter .is present, do the following sub-steps.name-
If the UTF-8 encoding of
filter .nameis more than 248 bytes long, throw aTypeErrorand abort these steps.Note: 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name . -
Set
canonicalizedFilter .nametofilter .name.
-
-
If
filter .is present, do the following sub-steps.namePrefix-
If
filter .namePrefix.length === 0or if the UTF-8 encoding offilter .namePrefixis more than 248 bytes long, throw aTypeErrorand abort these steps.Note: 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name . -
Set
canonicalizedFilter .namePrefixtofilter .namePrefix.
-
-
Set
canonicalizedFilter ["manufacturerData"]to[]. -
If
filter ["is present andmanufacturerData"]filter ["manufacturerData"].length === 0, throw aTypeErrorand abort these steps. -
For each manufacturerData in
filter [", do the following sub-steps:manufacturerData"]-
If manufacturerData is a blocklisted manufacturer data filter , throw a
SecurityErrorand abort these steps. -
If there exists an object existing in
canonicalizedFilter ["manufacturerData"]whereexisting ["companyIdentifier"] === manufacturerData [", throw acompanyIdentifier"]TypeErrorand abort these steps. -
Let canonicalizedManufacturerDataFilter be the result of canonicalizing manufacturerData , converted to an ECMAScript value . If this throws an exception, propagate that exception and abort these steps.
-
Set
canonicalizedManufacturerDataFilter ["companyIdentifier"]tomanufacturerData [".companyIdentifier"] -
Append canonicalizedManufacturerDataFilter to
canonicalizedFilter ["manufacturerData"].
-
-
Set
canonicalizedFilter .serviceDatato[]. -
If
filter ["is present andserviceData"]filter ["serviceData"].length === 0, throw aTypeErrorand abort these steps. -
For each serviceData in
filter [", do the following sub-steps:serviceData"]-
Let service be
. If this throws an exception, propagate that exception and abort these steps.BluetoothUUID.getService( serviceData ["service"]) -
If service is blocklisted , throw a
SecurityErrorand abort these steps. -
Let canonicalizedServiceDataFilter be the result of canonicalizing serviceData , converted to an ECMAScript value . If this throws an exception, propagate that exception and abort these steps.
-
Set
canonicalizedServiceDataFilter ["service"]to service . -
Append canonicalizedServiceDataFilter to
canonicalizedFilter ["serviceData"].
-
-
Return canonicalizedFilter .
BluetoothDataFilterInit
filter
,
is
the
BluetoothDataFilterInit
returned
from
the
following
steps:
-
If
filter .is not present, let dataPrefix be an empty sequence of bytes. Otherwise, do the following sub-steps:dataPrefix-
Let dataPrefix be a copy of the bytes held by
filter .dataPrefix. -
If the length of dataPrefix is zero, throw a
TypeErrorand abort these steps.
-
-
If
filter .is present, let mask be a copy of the bytes held bymaskfilter .mask. Otherwise, let mask be a sequence of0xFFbytes the same length as dataPrefix . -
If mask is not the same length as dataPrefix , throw a
TypeErrorand abort these steps. -
Return
{dataPrefix: new Uint8Array(|dataPrefix|), mask: new Uint8Array(|mask|)}.
-
If the UA has scanned for devices recently with a set of UUIDs that was a superset of the UUIDs for the current scan, then the UA MAY return the result of that scan and abort these steps.
-
Let nearbyDevices be a set of Bluetooth device s, initially equal to the set of devices that are connected (have an ATT Bearer ) to the UA.
-
Let topLevelTraversable be the global ’s navigable ’s top-level traversable .
-
Let simulatedBluetoothDevices be an empty list .
-
If topLevelTraversable has a simulated Bluetooth adapter , let simulatedBluetoothDevices be the result of getting the values of its simulated Bluetooth device mapping .
-
If the UA supports the LE transport, perform the General Discovery Procedure , except that the UA may include devices that have no Discoverable Mode flag set, and add the discovered Bluetooth device s to nearbyDevices . The UA SHOULD enable the Privacy Feature .
Both passive scanning and the Privacy Feature avoid leaking the unique, immutable device ID. We ought to require UAs to use either one, but none of the OS APIs appear to expose either. Bluetooth also makes it hard to use passive scanning since it doesn’t require Central devices to support the Observation Procedure .
-
If the UA supports the BR/EDR transport, perform the Device Discovery Procedure and add the discovered Bluetooth device s to nearbyDevices .
All forms of BR/EDR inquiry/discovery appear to leak the unique, immutable device address.
-
Let result be a set of Bluetooth device s, initially empty.
-
For each Bluetooth device device in nearbyDevices and simulatedBluetoothDevices , do the following sub-steps:
-
If device ’s supported physical transports include LE and its Bluetooth Device Name is partial or absent, the UA SHOULD perform the Name Discovery Procedure to acquire a complete name.
-
If device ’s advertised Service UUIDs have a non-empty intersection with the set of Service UUIDs , add device to result and abort these sub-steps.
Note: For BR/EDR devices, there is no way to distinguish GATT from non-GATT services in the Extended Inquiry Response . If a site filters to the UUID of a non-GATT service, the user may be able to select a device for the result ofrequestDevicethat this API provides no way to interact with. -
The UA MAY connect to device and populate the Bluetooth cache with all Services whose UUIDs are in the set of Service UUIDs . If device ’s supported physical transports include BR/EDR, then in addition to the standard GATT procedures, the UA MAY use the Service Discovery Protocol ( Searching for Services ) when populating the cache.
Note: Connecting to every nearby device to discover services costs power and can slow down other use of the Bluetooth radio. UAs should only discover extra services on a device if they have some reason to expect that device to be interesting.UAs should also help developers avoid relying on this extra discovery behavior. For example, say a developer has previously connected to a device, so the UA knows the device’s full set of supported services. If this developer then filters using a non-advertised UUID, the dialog they see may include this device, even if the filter would likely exclude the device on users' machines. The UA could provide a developer option to warn when this happens or to include only advertised services in matching filters.
-
If the Bluetooth cache contains known-present Services inside device with UUIDs in the set of Service UUIDs , the UA MAY add device to result .
-
-
Return result from the scan.
We need a way for a site to register to receive an event when an interesting device comes within range.
BluetoothPermissionStorage
storage
given
a
set
of
requiredServiceUUIDs
and
a
set
of
optionalServiceUUIDs
,
the
UA
MUST
run
the
following
steps:
-
Let grantedServiceUUIDs be a new
Set. -
Add the contents of requiredServiceUUIDs to grantedServiceUUIDs .
-
Add the contents of optionalServiceUUIDs to grantedServiceUUIDs .
-
Search for an element allowedDevice in
storage .where device is equal toallowedDevicesallowedDevice @. If one is found, perform the following sub-steps:[[device]]-
Add the contents of
allowedDevice .to grantedServiceUUIDs .allowedServices
If one is not found, perform the following sub-steps:
-
Let allowedDevice .
deviceIdbe a unique ID to the extent that the UA can determine that two Bluetooth connections are the same device and to the extent that the user wants to expose that fact to script .
-
-
Set allowedDevice .
allowedServicesto grantedServiceUUIDs . -
Set allowedDevice .
mayUseGATTtotrue.
To
remove
an
allowed
Bluetooth
device
device
,
given
a
BluetoothPermissionStorage
storage
,
the
UA
MUST
run
the
following
steps:
-
Search for an element allowedDevice in
storage .where device is equal toallowedDevicesallowedDevice @. If no such element exists, abort these steps.[[device]] -
Remove allowedDevice from
storage ..allowedDevices
4.1. Permission API Integration
The [permissions] API provides a uniform way for websites to query which permissions they have.
navigator
.
permissions
.
query
({
name
:
"bluetooth"
,
...})
to
retrieve
those
devices
after
a
reload.
navigator. permissions. query({ name: "bluetooth" , deviceId: sessionStorage. lastDevice, }). then( result=> { if ( result. devices. length== 1 ) { return result. devices[ 0 ]; } else { throw new DOMException( "Lost permission" , "NotFoundError" ); } }). then(...);
The
Web
Bluetooth
API
is
a
powerful
feature
that
is
identified
by
the
name
"bluetooth"
.
Its
permission-related
algorithms
and
types
are
defined
as
follows:
- permission descriptor type
-
dictionary :BluetoothPermissionDescriptor PermissionDescriptor {DOMString ; // These match RequestDeviceOptions.deviceId sequence <BluetoothLEScanFilterInit >;filters sequence <BluetoothServiceUUID >= [];optionalServices sequence <unsigned short >= [];optionalManufacturerData boolean =acceptAllDevices false ; }; - extra permission data type
-
BluetoothPermissionStorage, defined as:dictionary {AllowedBluetoothDevice required DOMString ;deviceId required boolean ; // An allowedServices of "all" means all services are allowed.mayUseGATT required (DOMString or sequence <UUID >);allowedServices required sequence <unsigned short >; };allowedManufacturerData dictionary {BluetoothPermissionStorage required sequence <AllowedBluetoothDevice >; };allowedDevices AllowedBluetoothDeviceinstances have an internal slot[[device]]that holds a Bluetooth device . - extra permission data constraints
-
Distinct
elements
of
allowedDevicesmust have different[[device]]s and differentdeviceIds.If
mayUseGATTisfalse,allowedServicesandallowedManufacturerDatamust both be[].Note: AdeviceIdallows a site to track that aBluetoothDeviceinstance seen at one time represents the same device as anotherBluetoothDeviceinstance seen at another time, possibly in a different realm . UAs should consider whether their user intends that tracking to happen or not-happen when returning "bluetooth" ’s extra permission data .For example, users generally don’t intend two different origins to know that they’re interacting with the same device, and they generally don’t intend unique identifiers to persist after they’ve cleared an origin’s cookies.
- permission result type
-
[
Exposed =Window ]interface :BluetoothPermissionResult PermissionStatus {attribute FrozenArray <BluetoothDevice >; };devices - permission query algorithm
-
To
query
the
"bluetooth"
permission
with
a
BluetoothPermissionDescriptordesc and aBluetoothPermissionResultstatus , the UA must:-
Let global be the relevant global object for status .
-
Set
status .to desc ’s permission state .state -
If
status .is "statedenied", setstatus .devicesto an emptyFrozenArrayand abort these steps. -
Let matchingDevices be a new
Array. -
Let storage , a
BluetoothPermissionStorage, be "bluetooth" ’s extra permission data for the current settings object . -
For each allowedDevice in
storage .allowedDevices, run the following sub-steps:-
If
desc .deviceIdis set andallowedDevice .deviceId != desc .deviceId, continue to the next allowedDevice . -
If
desc .filtersis set, do the following sub-steps:-
Replace each filter in
desc .filterswith the result of canonicalizing it. If any of these canonicalizations throws an error, return that error and abort these steps. -
If
allowedDevice .does not match a filter in[[device]]desc .filters, continue to the next allowedDevice .
-
-
Get the
BluetoothDevicerepresentingallowedDevice .within[[device]]global .navigator.bluetooth, and add the result to matchingDevices .
Note: Thedesc .optionalServicesanddesc .optionalManufacturerDatafields do not affect the result. -
-
Set
status .devicesto a newFrozenArraywhose contents are matchingDevices .
-
- permission revocation algorithm
-
To
revoke
Bluetooth
access
to
devices
the
user
no
longer
intends
to
expose,
the
UA
MUST
run
the
following
steps:
-
Let storage , a
BluetoothPermissionStorage, be "bluetooth" ’s extra permission data for the current settings object . -
For each
BluetoothDeviceinstance deviceObj in the current realm , run the following sub-steps:-
If there is an
AllowedBluetoothDeviceallowedDevice instorage .such that:allowedDevices-
allowedDevice .is the same device as[[device]]deviceObj ., and[[representedDevice]]
then update
deviceObj .to be[[allowedServices]]allowedDevice ., and continue to the next deviceObj .allowedServices -
-
Otherwise, detach deviceObj from its device by running the remaining steps.
-
Call
deviceObj .gatt..disconnect()Note: This fires agattserverdisconnectedevent at deviceObj . -
Set
deviceObj .to[[representedDevice]]null.
-
-
4.2. Overall Bluetooth availability
The
UA
may
be
running
on
a
computer
that
has
no
Bluetooth
radio.
requestDevice()
handles
this
by
failing
to
discover
any
devices,
which
results
in
a
NotFoundError
,
but
websites
may
be
able
to
handle
it
more
gracefully.
const bluetoothUI= document. querySelector( '#bluetoothUI' ); navigator. bluetooth. getAvailability() . then( isAvailable=> { bluetoothUI. hidden= ! isAvailable; }); navigator. bluetooth. addEventListener( ' availabilitychanged ' , e=> { bluetoothUI. hidden= ! e. value; });
getAvailability()
method,
when
invoked,
MUST
return
a
new
promise
promise
and
run
the
following
steps
in
parallel
:
-
Let global be this ’s relevant global object .
-
If global ’s associated Document is not allowed to use the policy-controlled feature named " bluetooth ", queue a global task on the Bluetooth task source given global to resolve promise with
false, and abort these steps. -
If the user has configured the UA to return a particular answer from this function for the current origin, queue a task to resolve promise with the configured answer, and abort these steps.
Note: If the Web Bluetooth permission has been blocked by the user, the UA may resolve promise withfalse. -
Let simulatedBluetoothAdapter be this ’s navigable ’s top-level traversable ’s simulated Bluetooth adapter .
-
If simulatedBluetoothAdapter is not empty,
-
If simulatedBluetoothAdapter ’s adapter state is "absent", queue a global task on the Bluetooth task source given global to resolve promise with
false. -
If simulatedBluetoothAdapter ’s LE supported state is
false, queue a global task on the Bluetooth task source given global to resolve promise withfalse. -
Otherwise, queue a global task on the Bluetooth task source given global to resolve promise with
true. -
Abort these steps.
-
-
If the UA is running on a system that has a Bluetooth radio queue a global task on the Bluetooth task source given global to resolve promise with
trueregardless of the powered state of the Bluetooth radio. -
Otherwise, queue a global task on the Bluetooth task source given global to resolve promise with
false.Note: The promise is resolved in parallel to let the UA call out to other systems to determine whether Bluetooth is available.
getAvailability
promise
with
false,
the
following
can
be
used
to
detect
when
Bluetooth
is
available
again
to
show
Bluetooth
UI:
function checkAvailability() { const bluetoothUI= document. querySelector( '#bluetoothUI' ); navigator. bluetooth. getAvailability() . then( isAvailable=> { bluetoothUI. hidden= ! isAvailable; }); } navigator. permissions. query({ name: "bluetooth" }). then( status=> { if ( status. state!== 'denied' ) checkAvailability(); // Bluetooth is blocked, listen for change in PermissionStatus. status. onchange= () => { if ( this . state!== 'denied' ) checkAvailability(); }; });
getAvailability()
,
the
UA
must
queue
a
global
task
on
the
Bluetooth
task
source
given
each
global
object
global
to
run
the
following
steps:
-
Let oldAvailability be the value
getAvailability()would have returned before the change. -
Let newAvailability be the value
getAvailability()would return after the change. -
If oldAvailability is not the same as newAvailability ,
-
Let navigator be global ’s associated
Navigator. -
Let bluetooth be navigator ’s associated
Bluetooth. -
Fire an event named
availabilitychangedusing theValueEventinterface at bluetooth with itsvalueattribute initialized to newAvailability .
-
[Exposed =Window ,SecureContext ]interface :ValueEvent Event {(constructor DOMString ,type optional ValueEventInit = {});initDict readonly attribute any value ; };dictionary :ValueEventInit EventInit {any =value null ; };
ValueEvent
instances
are
constructed
as
specified
in
DOM
§ 2.5
Constructing
events
.
The
value
attribute
must
return
the
value
it
was
initialized
to.
Such a generic event type belongs in [HTML] or [DOM] , not here.
5. Device Representation
The UA needs to track Bluetooth device properties at several levels: globally, per origin, and per global object .
5.1. Global Bluetooth device properties
The physical Bluetooth device may be guaranteed to have some properties that the UA may not have received. Those properties are described as optional here.
A Bluetooth device has the following properties. Optional properties are not present, and sequence and map properties are empty, unless/until described otherwise. Other properties have a default specified or are specified when a device is introduced.
-
A set of supported physical transports , including one or both of BR/EDR and LE. This set will generally be filled based on the transports over which the device was discovered and the Flags Data Type in the Advertising Data or Extended Inquiry Response .
-
One or more of several kinds of 48-bit address: a Public Bluetooth Address , a (random) Static Address , and a resolvable or non-resolvable Private Address .
-
An optional 128-bit Identity Resolving Key .
-
An optional partial or complete Bluetooth Device Name . A device has a partial name when the Shortened Local Name AD data was received, but the full name hasn’t been read yet. The Bluetooth Device Name is encoded as UTF-8 and converted to a DOMString using the utf-8 decode without BOM algorithm.
-
An optional ATT Bearer , over which all GATT communication happens. The ATT Bearer is created by procedures described in "Connection Establishment" under GAP Interoperability Requirements . It is disconnected in ways [BLUETOOTH42] isn’t entirely clear about.
-
A list of advertised Service UUIDs from the Advertising Data or Extended Inquiry Response .
-
A hierarchy of GATT Attributes .
The UA SHOULD determine that two Bluetooth device s are the same Bluetooth device if and only if they have the same Public Bluetooth Address , Static Address , Private Address , or Identity Resolving Key , or if the Resolvable Private Address Resolution Procedure succeeds using one device’s IRK and the other’s Resolvable Private Address . However, because platform APIs don’t document how they determine device identity, the UA MAY use another procedure.
5.2. BluetoothDevice
A
BluetoothDevice
instance
represents
a
Bluetooth
device
for
a
particular
global
object
(or,
equivalently,
for
a
particular
Realm
or
Bluetooth
instance).
[Exposed =Window ,SecureContext ]interface :BluetoothDevice EventTarget {readonly attribute DOMString id ;readonly attribute DOMString ?name ;readonly attribute BluetoothRemoteGATTServer ?gatt ;Promise <undefined >forget ();Promise <undefined >watchAdvertisements (optional WatchAdvertisementsOptions = {});options readonly attribute boolean watchingAdvertisements ; };BluetoothDevice includes BluetoothDeviceEventHandlers ;BluetoothDevice includes CharacteristicEventHandlers ;BluetoothDevice includes ServiceEventHandlers ;dictionary {WatchAdvertisementsOptions AbortSignal ; };signal
BluetoothDevice
attributes
id
uniquely
identifies
a
device
to
the
extent
that
the
UA
can
determine
that
two
Bluetooth
connections
are
to
the
same
device
and
to
the
extent
that
the
user
wants
to
expose
that
fact
to
script
.
name
is
the
human-readable
name
of
the
device.
gatt
provides
a
way
to
interact
with
this
device’s
GATT
server
if
the
site
has
permission
to
do
so.
forget()
enables
the
page
to
revoke
access
to
the
device
that
the
user
has
granted
access
to.
watchingAdvertisements
is
true
if
the
UA
is
currently
scanning
for
advertisements
from
this
device
and
firing
events
for
them.
Instances
of
BluetoothDevice
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[context]]
| <always set in prose> |
The
Bluetooth
object
that
returned
this
BluetoothDevice
.
|
[[representedDevice]]
| <always set in prose> |
The
Bluetooth
device
this
object
represents,
or
null
if
access
has
been
revoked
.
|
[[gatt]]
|
a
new
BluetoothRemoteGATTServer
instance
with
its
device
attribute
initialized
to
this
and
its
connected
attribute
initialized
to
false
.
| Does not change. |
[[allowedServices]]
| <always set in prose> |
This
device’s
allowedServices
list
for
this
origin
or
"all"
if
all
services
are
allowed.
For
example,
a
UA
may
grant
an
origin
access
to
all
services
on
a
referringDevice
that
advertised
a
URL
on
that
origin.
|
[[allowedManufacturerData]]
| <always set in prose> |
This
device’s
allowedManufacturerData
list
for
this
origin.
|
[[watchAdvertisementsState]]
|
'not-watching'
|
An
string
enumeration
describing
the
current
state
of
a
watchAdvertisements()
operation.
The
possible
enumeration
values
are:
|
BluetoothDevice
representing
a
Bluetooth
device
device
inside
a
Bluetooth
instance
context
,
the
UA
MUST
run
the
following
steps:
-
Let storage , a
BluetoothPermissionStorage, be "bluetooth" ’s extra permission data for the current settings object . -
Find the allowedDevice in
storage .withallowedDevicesallowedDevice .the same device as device . If there is no such object, throw a[[device]]SecurityErrorand abort these steps. -
If there is no key in context .
[[deviceInstanceMap]]that is the same device as device , run the following sub-steps:-
Let result be a new instance of
BluetoothDevice. -
Initialize all of result ’s optional fields to
null. -
Initialize
result .to context .[[context]] -
Initialize
result .to device .[[representedDevice]] -
Initialize
result .idtoallowedDevice ., and initializedeviceIdresult .to[[allowedServices]]allowedDevice ..allowedServices -
If device has a partial or complete Bluetooth Device Name , set
result .nameto that string. -
Initialize
result .watchingAdvertisementstofalse. -
Add a mapping from device to result in context .
[[deviceInstanceMap]].
-
-
Return the value in context .
[[deviceInstanceMap]]whose key is the same device as device .
gatt
attribute
MUST
perform
the
following
steps:
-
If "bluetooth" ’s extra permission data for
this’s relevant settings object has anAllowedBluetoothDeviceallowedDevice in itsallowedDeviceslist withallowedDevice .the same device as[[device]]this.and[[representedDevice]]allowedDevice .equal tomayUseGATTtrue, returnthis..[[gatt]] -
Otherwise, return
null.
forget()
method,
when
invoked,
MUST
return
a
new
promise
promise
and
run
the
following
steps:
-
Let device be the target
BluetoothDeviceobject. -
Let storage be the
BluetoothPermissionStorageobject in the current script execution environment. -
Remove device from storage with storage .
-
Resolve promise .
A user agent has an associated watch advertisements manager which is the result of starting a new parallel queue .
watchAdvertisements(
options
)
method,
when
invoked,
MUST
return
a
new
promise
promise
and
run
the
following
steps:
-
Let global be the relevant global object of this .
-
If
options .is present, then perform the following sub-steps:signal-
If
options .is aborted , then abort watchAdvertisements withsignalthisand abort these steps. -
Add the following abort steps to
options .:signal-
Abort watchAdvertisements with
this. -
Reject promise with
AbortError
-
-
-
If
this.is:[[watchAdvertisementsState]]-
'not-watching' -
-
Set
this.to[[watchAdvertisementsState]]'pending-watch'. -
Enqueue the following steps to the watch advertisements manager , but abort when
this.becomes[[watchAdvertisementsState]]not-watching:-
Ensure that the UA is scanning for this device’s advertisements. The UA SHOULD NOT filter out "duplicate" advertisements for the same device.
-
If the UA fails to enable scanning, queue a global task on the Bluetooth task source given global to perform the following steps, and abort these steps:
-
Set
this.to[[watchAdvertisementsState]]'not-watching'. -
Reject promise with one of the following errors:
- The UA doesn’t support scanning for advertisements
- Bluetooth is turned off
- Other reasons
-
-
Queue a global task on the Bluetooth task source given global to perform the following steps, but abort when
this.becomes[[watchAdvertisementsState]]not-watching:-
Set
this.to[[watchAdvertisementsState]]watching. -
Set
this.towatchingAdvertisementstrue. -
Resolve promise with
undefined.
-
-
-
-
'pending-watch' -
-
Reject promise with
InvalidStateError.
-
-
'watching' -
-
Resolve promise with
undefined.
-
-
-
If aborted , reject promise with
AbortError.
Note:
Scanning
costs
power,
so
websites
should
avoid
watching
for
advertisements
unnecessarily,
and
should
use
their
AbortController
to
stop
using
power
as
soon
as
possible.
watchAdvertisements
for
a
BluetoothDevice
device
,
run
these
steps:
-
Set
this.to[[watchAdvertisementsState]]'not-watching'. -
Set
device .towatchingAdvertisementsfalse. -
Enqueue the following steps to watch advertisements manager :
-
If no more
BluetoothDevices in the whole UA havewatchingAdvertisementsset totrue, the UA SHOULD stop scanning for advertisements. Otherwise, if no moreBluetoothDevices representing the same device asthishavewatchingAdvertisementsset totrue, the UA SHOULD reconfigure the scan to avoid receiving reports for this device.
-
watchAdvertisements
operations
given
a
Bluetooth
bluetooth
,
run
these
steps:
-
For each device in bluetooth .
[[deviceInstanceMap]], perform the following steps:-
If device .
[[watchAdvertisementsState]]ispending-watchorwatching, run abort watchAdvertisements with device .
-
5.2.1. Handling Visibility Change
Operations
that
initiate
a
scan
for
Bluetooth
devices
may
only
run
in
a
visible
document
.
When
visibility
state
is
no
longer
"visible"
,
scanning
operations
for
that
document
need
to
be
aborted.
-
Let global be document ’s relevant global object .
-
Queue a global task on the Bluetooth task source given global to perform the following steps:
-
Let navigator be global ’s associated
Navigator. -
Let bluetooth be navigator ’s associated
Bluetooth. -
If visibilityState is not
"visible", then abort all active watchAdvertisements operations on bluetooth .
-
5.2.2. Handling Document Loss of Full Activity
Operations that initiate a scan for Bluetooth devices may only run in a fully active document . When full activity is lost, scanning operations for that document need to be aborted.
Document
is
no
longer
fully
active
,
it
must
run
these
steps:
-
Let document be the
Documentthat is no longer fully active . -
Let global be document ’s relevant global object .
-
Queue a global task on the Bluetooth task source given global to perform the following steps:
-
Let navigator be global ’s associated
Navigator. -
Let bluetooth be navigator ’s associated
Bluetooth. -
Run abort all active watchAdvertisements operations on bluetooth .
-
5.2.3. Responding to Advertising Events
When
an
advertising
event
arrives
for
a
BluetoothDevice
with
watchingAdvertisements
set,
the
UA
delivers
an
"
advertisementreceived
"
event.
[Exposed =Window ,SecureContext ]interface BluetoothManufacturerDataMap {readonly maplike <unsigned short ,DataView >; }; [Exposed =Window ,SecureContext ]interface BluetoothServiceDataMap {readonly maplike <UUID ,DataView >; }; [Exposed =Window ,SecureContext ]interface :BluetoothAdvertisingEvent Event {constructor (DOMString ,type BluetoothAdvertisingEventInit ); [init SameObject ]readonly attribute BluetoothDevice device ;readonly attribute FrozenArray <UUID >uuids ;readonly attribute DOMString ?name ;readonly attribute unsigned short ?appearance ;readonly attribute byte ?txPower ;readonly attribute byte ?rssi ; [SameObject ]readonly attribute BluetoothManufacturerDataMap manufacturerData ; [SameObject ]readonly attribute BluetoothServiceDataMap serviceData ; };dictionary :BluetoothAdvertisingEventInit EventInit {required BluetoothDevice ;device sequence <(DOMString or unsigned long )>;uuids DOMString ;name unsigned short ;appearance byte ;txPower byte ;rssi BluetoothManufacturerDataMap ;manufacturerData BluetoothServiceDataMap ; };serviceData
BluetoothAdvertisingEvent
attributes
device
is
the
BluetoothDevice
that
sent
this
advertisement.
uuids
lists
the
Service
UUIDs
that
this
advertisement
says
device
’s
GATT
server
supports.
name
is
device
’s
local
name,
or
a
prefix
of
it.
appearance
is
an
Appearance
,
one
of
the
values
defined
by
the
gap.appearance
characteristic.
txPower
is
the
transmission
power
at
which
the
device
is
broadcasting,
measured
in
dBm.
This
is
used
to
compute
the
path
loss
as
this.txPower
-
this.rssi
.
rssi
is
the
power
at
which
the
advertisement
was
received,
measured
in
dBm.
This
is
used
to
compute
the
path
loss
as
this.txPower
-
this.rssi
.
manufacturerData
maps
unsigned
short
Company
Identifier
Codes
to
DataView
s.
requestDevice
dialog.
var known_service= "A service in the iBeacon’s GATT server" ; return navigator. bluetooth. requestDevice({ filters: [{ services: [ known_service]}] }). then( device=> { device. watchAdvertisements(); device. addEventListener( 'advertisementreceived' , interpretIBeacon); }); function interpretIBeacon( event) { var rssi= event. rssi; var appleData= event. manufacturerData. get( 0x004C ); if ( appleData. byteLength!= 23 || appleData. getUint16( 0 , false ) !== 0x0215 ) { console. log({ isBeacon: false }); } var uuidArray= new Uint8Array( appleData. buffer, 2 , 16 ); var major= appleData. getUint16( 18 , false ); var minor= appleData. getUint16( 20 , false ); var txPowerAt1m= - appleData. getInt8( 22 ); console. log({ isBeacon: true , uuidArray, major, minor, pathLossVs1m: txPowerAt1m- rssi}); });
The format of iBeacon advertisements was derived from How do iBeacons work? by Adam Warski.
-
Let device be the Bluetooth device that sent the advertising event.
-
For each
BluetoothDevicedeviceObj in the UA such that device is the same device asdeviceObj ., queue a task on deviceObj ’s relevant settings object ’s responsible event loop to do the following sub-steps:[[representedDevice]]-
If
deviceObj .iswatchingAdvertisementsfalse, abort these sub-steps. -
Fire an
advertisementreceivedevent for the advertising event at deviceObj .
-
advertisementreceived
event
for
an
advertising
event
adv
at
a
BluetoothDevice
deviceObj
,
the
UA
MUST
perform
the
following
steps:
-
Let event be
{ bubbles: true , device: deviceObj, uuids: [], manufacturerData: new Map(), serviceData: new Map() } -
If the received signal strength is available for any packet in adv , set
event .rssito this signal strength in dBm. -
For each AD structure in adv ’s advertising packet and scan response, select from the following steps depending on the AD type:
-
Incomplete
List
of
16-bit
Service
UUIDs
- Complete List of 16-bit Service UUIDs
- Incomplete List of 32-bit Service UUIDs
- Complete List of 32-bit Service UUIDs
- Incomplete List of 128-bit Service UUIDs
- Complete List of 128-bit Service UUIDs
- Complete List of 16-bit Service UUIDs
-
For
each
uuidin the listed UUIDs, if it is inthis.device., then append[[allowedServices]]uuidtoevent .uuids. -
Shortened
Local
Name
- Complete Local Name
-
UTF-8
decode
without
BOM
the
AD
data
and
set
event .nameto the result.Note: We don’t expose whether the name is complete because existing APIs require reading the raw advertisement to get this information, and we want more evidence that it’s useful before adding a field to the API. - Manufacturer Specific Data
-
For
each
16-bit
Company
Identifier
Code
manufacturerCode, if it is inthis.device., and the manufacturer data is not a blocklisted manufacturer data then add a mapping of[[allowedManufacturerData]]manufacturerCodeto anArrayBuffercontaining the manufacturer-specific data toevent .manufacturerData. - TX Power Level
-
Set
event .txPowerto the AD data. -
Service
Data
-
16
bit
UUID
- Service Data - 32 bit UUID
- Service Data - 128 bit UUID
- Service Data - 32 bit UUID
-
For
each
UUID
uuidin the service data, if it is inthis.device., then add a mapping of uuid to an[[allowedServices]]ArrayBuffercontaining the service data toevent .serviceData. - Appearance
-
Set
event .appearanceto the AD data. - Otherwise
- Skip to the next AD structure.
-
Incomplete
List
of
16-bit
Service
UUIDs
-
Fire an event named "
advertisementreceived" usingBluetoothAdvertisingEventinitialized with event , with itsisTrustedattribute initialized totrue, at deviceObj .
All
fields
in
BluetoothAdvertisingEvent
return
the
last
value
they
were
initialized
or
set
to.
BluetoothAdvertisingEvent(type,
init)
constructor
MUST
perform
the
following
steps:
-
Let event be the result of running the steps from DOM § 2.5 Constructing events except for the
uuids,manufacturerData, andserviceDatamembers. -
If
init .uuidsis set, initializeevent .uuidsto a newFrozenArraycontaining the elements ofinit .uuids.map(. Otherwise initializeBluetoothUUID.getService)event .uuidsto an emptyFrozenArray. -
For each mapping in
init .manufacturerData:-
Let code be the key converted to an
unsigned short. -
Let value be the value.
-
If value is not a
BufferSource, throw aTypeError. -
Let bytes be a new read only ArrayBuffer containing a copy of the bytes held by value .
-
Add a mapping from code to
new DataView( bytes )inevent .manufacturerData..[[BackingMap]]
-
-
For each mapping in
init .serviceData:-
Let key be the key.
-
Let service be the result of calling
BluetoothUUID.getService( key ). -
Let value be the value.
-
If value is not a
BufferSource, throw aTypeError. -
Let bytes be a new read only ArrayBuffer containing a copy of the bytes held by value .
-
Add a mapping from service to
new DataView( bytes )inevent .serviceData..[[BackingMap]]
-
-
Return event .
5.2.3.1. BluetoothManufacturerDataMap
Instances
of
BluetoothManufacturerDataMap
have
a
[[BackingMap]]
slot
because
they
are
maplike
,
which
maps
manufacturer
codes
to
the
manufacturer’s
data,
converted
to
DataView
s.
5.2.3.2. BluetoothServiceDataMap
Instances
of
BluetoothServiceDataMap
have
a
[[BackingMap]]
slot
because
they
are
maplike
,
which
maps
service
UUIDs
to
the
service’s
data,
converted
to
DataView
s.
6. GATT Interaction
6.1. GATT Information Model
Profiles are purely logical: the specification of a Profile describes the expected interactions between the other GATT entities the Profile contains, but it’s impossible to query which Profiles a device supports.
GATT Client s can discover and interact with the Services, Characteristics, and Descriptors on a device using a set of GATT procedures . This spec refers to Services, Characteristics, and Descriptors collectively as Attribute s. All Attributes have a type that’s identified by a UUID . Each Attribute also has a 16-bit Attribute Handle that distinguishes it from other Attributes of the same type on the same GATT Server . Attributes are notionally ordered within their GATT Server by their Attribute Handle , but while platform interfaces provide attributes in some order, they do not guarantee that it’s consistent with the Attribute Handle order.
A Service contains a collection of Included Service s and Characteristic s. The Included Services are references to other Services, and a single Service can be included by more than one other Service. Services are known as Primary Services if they appear directly under the GATT Server , and Secondary Services if they’re only included by other Services, but Primary Services can also be included.
A Characteristic contains a value, which is an array of bytes, and a collection of Descriptor s. Depending on the properties of the Characteristic, a GATT Client can read or write its value, or register to be notified when the value changes.
Finally, a Descriptor contains a value (again an array of bytes) that describes or configures its Characteristic .
6.1.1. Persistence across connections
The
Bluetooth
Attribute
Caching
system
allows
bonded
clients
to
save
references
to
attributes
from
one
connection
to
the
next.
Web
Bluetooth
treats
websites
as
not
bonded
to
devices
they
have
permission
to
access:
BluetoothRemoteGATTService
,
BluetoothRemoteGATTCharacteristic
,
and
BluetoothRemoteGATTDescriptor
objects
become
invalid
on
disconnection
,
and
the
site
must
retrieved
them
again
when
it
re-connects.
6.1.2. The Bluetooth cache
The
UA
MUST
maintain
a
Bluetooth
cache
of
the
hierarchy
of
Services,
Characteristics,
and
Descriptors
it
has
discovered
on
a
device.
The
UA
MAY
share
this
cache
between
multiple
origins
accessing
the
same
device.
Each
potential
entry
in
the
cache
is
either
known-present,
known-absent,
or
unknown.
The
cache
MUST
NOT
contain
two
entries
that
are
for
the
same
attribute
.
Each
known-present
entry
in
the
cache
is
associated
with
an
optional
Promise<
,
BluetoothRemoteGATTService
>
Promise<
,
or
BluetoothRemoteGATTCharacteristic
>
Promise<
instance
for
each
BluetoothRemoteGATTDescriptor
>
Bluetooth
instance.
serviceA.getCharacteristic(uuid1)
function
with
an
initially
empty
Bluetooth
cache
,
the
UA
uses
the
Discover
Characteristics
by
UUID
procedure
to
fill
the
needed
cache
entries,
and
the
UA
ends
the
procedure
early
because
it
only
needs
one
Characteristic
to
fulfil
the
returned
Promise
,
then
the
first
Characteristic
with
UUID
uuid1
inside
serviceA
is
known-present,
and
any
subsequent
Characteristics
with
that
UUID
remain
unknown.
If
the
user
later
calls
serviceA.getCharacteristics(uuid1)
,
the
UA
needs
to
resume
or
restart
the
Discover
Characteristics
by
UUID
procedure.
If
it
turns
out
that
serviceA
only
has
one
Characteristic
with
UUID
uuid1
,
then
the
subsequent
Characteristics
become
known-absent.
The known-present entries in the Bluetooth cache are ordered: Primary Services appear in a particular order within a device, Included Services and Characteristics appear in a particular order within Services, and Descriptors appear in a particular order within Characteristics. The order SHOULD match the order of Attribute Handle s on the device, but UAs MAY use another order if the device’s order isn’t available.
-
Attempt to make all matching entries in the cache either known-present or known-absent, using any sequence of GATT procedures that [BLUETOOTH42] specifies will return enough information. Handle errors as described in § 6.7 Error handling .
-
If the previous step returns an error, return that error from this algorithm.
BluetoothDevice
instance
deviceObj
for
entries
matching
some
description,
the
UA
MUST
return
a
deviceObj
.
gatt
-
connection-checking
wrapper
around
a
new
promise
promise
and
run
the
following
steps
in
parallel
:
-
Let global be deviceObj ’s relevant global object .
-
Populate the Bluetooth cache with entries matching the description.
-
If the previous step returns an error, queue a global task on the Bluetooth task source given global to reject promise with that error and abort these steps.
-
Let entries be the sequence of known-present cache entries matching the description.
-
Let context be deviceObj .
[[context]]. -
Let result be a new sequence.
-
For each entry in entries :
-
If entry has no associated
Promise<BluetoothGATT*>instance in context .[[attributeInstanceMap]], create aBluetoothRemoteGATTServicerepresenting entry , create aBluetoothRemoteGATTCharacteristicrepresenting entry , or create aBluetoothRemoteGATTDescriptorrepresenting entry , depending on whether entry is a Service, Characteristic, or Descriptor, and add a mapping from entry to the resultingPromisein context .[[attributeInstanceMap]]. -
Append to result the
Promise<BluetoothGATT*>instance associated with entry in context .[[attributeInstanceMap]].
-
-
Queue a global task on the Bluetooth task source given global to resolve promise with the result of waiting for all elements of result .
6.1.3. Navigating the Bluetooth Hierarchy
single : boolean,
uuidCanonicalizer : function,
uuid : optional
(DOMString
or
unsigned
int)
,
allowedUuids : optional
("all"
or
Array<DOMString>)
,
child type : GATT declaration type),
the UA MUST perform the following steps:
-
If uuid is present, set it to uuidCanonicalizer ( uuid ). If uuidCanonicalizer threw an exception, return a promise rejected with that exception and abort these steps.
-
If uuid is present and is blocklisted , return a promise rejected with a
SecurityErrorand abort these steps. -
Let deviceObj be, depending on the type of attribute :
-
BluetoothDevice -
attribute -
BluetoothRemoteGATTService -
attribute .device -
BluetoothRemoteGATTCharacteristic -
attribute .service.device
-
-
If
deviceObj .gatt.isconnectedfalse, return a promise rejected with with aNetworkErrorand abort these steps. -
If Represented ( attribute ) is
null, return a promise rejected with anInvalidStateErrorand abort these steps.Note: This happens when a Service or Characteristic is removed from the device or invalidated by a disconnection, and then its object is used again.
-
Query the Bluetooth cache in
deviceObjfor entries that:-
are within Represented ( attribute ),
-
have a type described by child type ,
-
have a UUID that is not blocklisted ,
-
if uuid is present, have a UUID of uuid ,
-
if allowedUuids is present and not
"all", have a UUID in allowedUuids , and -
if the single flag is set, are the first of these.
Let promise be the result.
-
-
Upon fulfillment of promise with result , run the following steps:
-
If result is empty, throw a
NotFoundError. -
Otherwise, if the single flag is set, returns the first (only) element of result .
-
Otherwise, return result .
-
6.1.4. Identifying Services, Characteristics, and Descriptors
When checking whether two Services, Characteristics, or Descriptors a and b are the same attribute , the UA SHOULD determine that they are the same if a and b are inside the same device and have the same Attribute Handle , but MAY use any algorithm it wants with the constraint that a and b MUST NOT be considered the same attribute if they fit any of the following conditions:
-
They are not both Services, both Characteristics, or both Descriptors.
-
They are both Services, but are not both primary or both secondary services.
-
They have different UUIDs.
-
Their parent Devices aren’t the same device or their parent Services or Characteristics aren’t the same attribute .
x
===
y
returns
whether
the
objects
represent
the
same
attribute
,
because
of
how
the
query
the
Bluetooth
cache
algorithm
creates
and
caches
new
objects.
6.2. BluetoothRemoteGATTServer
BluetoothRemoteGATTServer
represents
a
GATT
Server
on
a
remote
device.
[Exposed =Window ,SecureContext ]interface { [BluetoothRemoteGATTServer SameObject ]readonly attribute BluetoothDevice device ;readonly attribute boolean connected ;Promise <BluetoothRemoteGATTServer >connect ();undefined disconnect ();Promise <BluetoothRemoteGATTService >getPrimaryService (BluetoothServiceUUID );service Promise <sequence <BluetoothRemoteGATTService >>getPrimaryServices (optional BluetoothServiceUUID ); };service
BluetoothRemoteGATTServer
attributes
device
is
the
device
running
this
server.
connected
is
true
while
this
instance
is
connected
to
this.device
.
It
can
be
false
while
the
UA
is
physically
connected,
for
example
when
there
are
other
connected
BluetoothRemoteGATTServer
instances
for
other
global
object
s.
When
no
ECMAScript
code
can
observe
an
instance
of
BluetoothRemoteGATTServer
server
anymore,
the
UA
SHOULD
run
server
.
.
disconnect()
BluetoothDevice
instances
are
stored
in
navigator.bluetooth.
[[deviceInstanceMap]]
,
this
can’t
happen
at
least
until
navigation
releases
the
global
object
or
closing
the
tab
or
window
destroys
the
browsing
context
.
Instances
of
BluetoothRemoteGATTServer
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[activeAlgorithms]]
|
new
|
Contains
a
Promise
corresponding
to
each
algorithm
using
this
server’s
connection.
disconnect()
empties
this
set
so
that
the
algorithm
can
tell
whether
its
realm
was
ever
disconnected
while
it
was
running.
|
[[automatedGATTConnectionResponse]]
|
"not-expected"
| The simulated GATT connection response code for a GATT connection attempt. |
connect()
method,
when
invoked,
MUST
perform
the
following
steps:
-
Let global be this ’s relevant global object .
-
If this .
device.[[representedDevice]]isnull, return a promise rejected with a "NetworkError"DOMException. -
If the UA is currently using the Bluetooth system, it MAY return a promise rejected with a "
NetworkError"DOMException.Implementations may be able to avoid this
NetworkError, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. [Issue #188] -
Let promise be a new promise .
-
If this .
connectedistrue, resolve promise with this and return promise . -
Add promise to this .
[[activeAlgorithms]]. -
Run the following steps in parallel :
-
If global ’s navigable ’s top-level traversable ’s simulated Bluetooth adapter is not empty, run the following steps:
-
Trigger a gatt connection attempted event given global ’s navigable and this .
device. -
If this .
[[automatedGATTConnectionResponse]]is"not-expected", set it to"expected". -
If this .
[[automatedGATTConnectionResponse]]is"expected", wait for it to change. -
Let response be this .
[[automatedGATTConnectionResponse]]. -
Set this .
[[automatedGATTConnectionResponse]]to"not-expected". -
If response is not
0, do the following sub-steps:-
Remove promise from this .
[[activeAlgorithms]]. -
Queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps.
-
-
-
Otherwise, run the following steps:
-
If this .
device.[[representedDevice]]has no ATT Bearer , do the following sub-steps:-
Attempt to create an ATT Bearer using the procedures described in "Connection Establishment" under GAP Interoperability Requirements . Abort this attempt if promise is removed from this .
[[activeAlgorithms]].Note: These procedures can wait forever if a connectable advertisement isn’t received. The website should calldisconnect()if it no longer wants to connect. -
If this attempt was aborted because promise was removed from this .
[[activeAlgorithms]], queue a global task on the Bluetooth task source given global to reject promise with an "AbortError"DOMExceptionand abort these steps. -
If this attempt failed for another reason, queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps. -
Use the Exchange MTU procedure to negotiate the largest supported MTU. Ignore any errors from this step.
-
The UA MAY attempt to bond with the remote device using the BR/EDR Bonding Procedure or the LE Bonding Procedure .
Note: We would normally prefer to give the website control over whether and when bonding happens, but the Core Bluetooth platform API doesn’t provide a way for UAs to implement such a knob. Having a bond is more secure than not having one, so this specification allows the UA to opportunistically create one on platforms where that’s possible. This may cause a user-visible pairing dialog to appear when a connection is created, instead of when a restricted characteristic is accessed.
-
-
-
Queue a global task on the Bluetooth task source given global to perform the following sub-steps:
-
If promise is not in this .
[[activeAlgorithms]], reject promise with an "AbortError"DOMException, garbage-collect the connection of this .device.[[representedDevice]], and abort these steps. -
Remove promise from this .
[[activeAlgorithms]]. -
If this .
device.[[representedDevice]]isnull, reject promise with a "NetworkError"DOMException, garbage-collect the connection of this .device.[[representedDevice]], and abort these steps.
-
-
-
Return promise .
disconnect()
method,
when
invoked,
MUST
perform
the
following
steps:
-
Clear
this.to abort any active[[activeAlgorithms]]connect()calls . -
If
this.isconnectedfalse, abort these steps. -
Clean up the disconnected device
this.device. -
Let device be
this.device..[[representedDevice]] -
Garbage-collect the connection of device .
-
If systems that aren’t using this API, either inside or outside of the UA, are using the device ’s ATT Bearer , abort this algorithm.
-
For all
BluetoothDevicesdeviceObjin the whole UA:-
If
deviceObj .is not the same device as device , continue to the next deviceObj .[[representedDevice]] -
If
deviceObj .gatt.isconnectedtrue, abort this algorithm. -
If
deviceObj .gatt.contains the[[activeAlgorithms]]Promiseof a call toconnect(), abort this algorithm.
-
-
Destroy device ’s ATT Bearer .
BluetoothRemoteGATTServer
was
disconnected
while
they
were
running,
even
if
the
UA
stays
connected
the
whole
time
and
the
BluetoothRemoteGATTServer
is
subsequently
re-connected
before
they
finish.
We
wrap
the
returned
Promise
to
accomplish
this.
To
create
a
gattServer
-
connection-checking
wrapper
around
a
Promise
promise
,
the
UA
MUST:
-
If
gattServer .connectedistrue, add promise togattServer ..[[activeAlgorithms]] -
React to promise :
-
If promise was fulfilled with value result , then:
-
If promise is in
gattServer ., remove it and return result .[[activeAlgorithms]] -
Otherwise, throw a
NetworkError.Note: This error is thrown because gattServer was disconnected during the execution of the main algorithm.
-
-
If promise was rejected with reason error , then:
-
If promise is in
gattServer ., remove it and throw error .[[activeAlgorithms]] -
Otherwise, throw a
NetworkError.Note: This error is thrown because gattServer was disconnected during the execution of the main algorithm.
-
-
getPrimaryService(
service
)
method,
when
invoked,
MUST
perform
the
following
steps:
-
If
this.device.is not[[allowedServices]]"all"and service is not inthis.device., return a promise rejected with a[[allowedServices]]SecurityErrorand abort these steps. -
Return GetGATTChildren ( attribute =
this.device,
single =true,
uuidCanonicalizer =BluetoothUUID.getService,
uuid =service,
allowedUuids =this.device.,[[allowedServices]]
child type ="GATT Primary Service")
getPrimaryServices(
service
)
method,
when
invoked,
MUST
perform
the
following
steps:
-
If
this.device.is not[[allowedServices]]"all", and service is present and not inthis.device., return a promise rejected with a[[allowedServices]]SecurityErrorand abort these steps. -
Return GetGATTChildren ( attribute =
this.device,
single =false,
uuidCanonicalizer =BluetoothUUID.getService,
uuid =service,
allowedUuids =this.device.,[[allowedServices]]
child type ="GATT Primary Service")
6.3. BluetoothRemoteGATTService
BluetoothRemoteGATTService
represents
a
GATT
Service
,
a
collection
of
characteristics
and
relationships
to
other
services
that
encapsulate
the
behavior
of
part
of
a
device.
[Exposed =Window ,SecureContext ]interface :BluetoothRemoteGATTService EventTarget { [SameObject ]readonly attribute BluetoothDevice device ;readonly attribute UUID uuid ;readonly attribute boolean isPrimary ;Promise <BluetoothRemoteGATTCharacteristic >getCharacteristic (BluetoothCharacteristicUUID );characteristic Promise <sequence <BluetoothRemoteGATTCharacteristic >>getCharacteristics (optional BluetoothCharacteristicUUID );characteristic Promise <BluetoothRemoteGATTService >getIncludedService (BluetoothServiceUUID );service Promise <sequence <BluetoothRemoteGATTService >>getIncludedServices (optional BluetoothServiceUUID ); };service BluetoothRemoteGATTService includes CharacteristicEventHandlers ;BluetoothRemoteGATTService includes ServiceEventHandlers ;
BluetoothRemoteGATTService
attributes
device
is
the
BluetoothDevice
representing
the
remote
peripheral
that
the
GATT
service
belongs
to.
uuid
is
the
UUID
of
the
service,
e.g.
'0000180d-0000-1000-8000-00805f9b34fb'
for
the
Heart
Rate
service.
isPrimary
indicates
whether
the
type
of
this
service
is
primary
or
secondary.
Instances
of
BluetoothRemoteGATTService
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[representedService]]
| <always set in prose> |
The
Service
this
object
represents,
or
null
if
the
Service
has
been
removed
or
otherwise
invalidated.
|
BluetoothRemoteGATTService
representing
a
Service
service
,
the
UA
must
run
the
following
steps:
-
Let global be this ’s relevant global object .
-
Let promise be a new promise .
-
Run the following steps in parallel :
-
Let result be a new instance of
BluetoothRemoteGATTServicewith its[[representedService]]slot initialized to service . -
Get the
BluetoothDevicerepresenting the device in which service appears, and let device be the result. -
If the previous step threw an error, queue a global task on the Bluetooth task source given global to reject promise with that error and abort these steps.
-
Initialize result .
devicefrom device . -
Initialize result .
uuidfrom the UUID of service . -
If service is a Primary Service, initialize result .
isPrimarytotrue. Otherwise, initialize result .isPrimarytofalse. -
Queue a global task on the Bluetooth task source given global to resolve promise with result .
-
-
Return promise .
getCharacteristic(
characteristic
)
method
retrieves
a
Characteristic
inside
this
Service.
When
invoked,
it
MUST
return
GetGATTChildren ( attribute =
this,
single =true,
uuidCanonicalizer =BluetoothUUID.getCharacteristic,
uuid =characteristic,
allowedUuids =undefined,
child type ="GATT Characteristic")
getCharacteristics(
characteristic
)
method
retrieves
a
list
of
Characteristic
s
inside
this
Service.
When
invoked,
it
MUST
return
GetGATTChildren ( attribute =
this,
single =false,
uuidCanonicalizer =BluetoothUUID.getCharacteristic,
uuid =characteristic,
allowedUuids =undefined,
child type ="GATT Characteristic")
getIncludedService(
service
)
method
retrieves
an
Included
Service
inside
this
Service.
When
invoked,
it
MUST
return
GetGATTChildren ( attribute =
this,
single =true,
uuidCanonicalizer =BluetoothUUID.getService,
uuid =service,
allowedUuids =undefined,
child type ="GATT Included Service")
getIncludedServices(
service
)
method
retrieves
a
list
of
Included
Service
s
inside
this
Service.
When
invoked,
it
MUST
return
GetGATTChildren ( attribute =
this,
single =false,
uuidCanonicalizer =BluetoothUUID.getService,
uuid =service,
allowedUuids =undefined,
child type ="GATT Included Service")
6.4. BluetoothRemoteGATTCharacteristic
BluetoothRemoteGATTCharacteristic
represents
a
GATT
Characteristic
,
which
is
a
basic
data
element
that
provides
further
information
about
a
peripheral’s
service.
[Exposed =Window ,SecureContext ]interface :BluetoothRemoteGATTCharacteristic EventTarget { [SameObject ]readonly attribute BluetoothRemoteGATTService service ;readonly attribute UUID uuid ;readonly attribute BluetoothCharacteristicProperties properties ;readonly attribute DataView ?value ;Promise <BluetoothRemoteGATTDescriptor >getDescriptor (BluetoothDescriptorUUID );descriptor Promise <sequence <BluetoothRemoteGATTDescriptor >>getDescriptors (optional BluetoothDescriptorUUID );descriptor Promise <DataView >readValue ();Promise <undefined >writeValue (BufferSource );value Promise <undefined >writeValueWithResponse (BufferSource );value Promise <undefined >writeValueWithoutResponse (BufferSource );value Promise <BluetoothRemoteGATTCharacteristic >startNotifications ();Promise <BluetoothRemoteGATTCharacteristic >stopNotifications (); };BluetoothRemoteGATTCharacteristic includes CharacteristicEventHandlers ;
BluetoothRemoteGATTCharacteristic
attributes
service
is
the
GATT
service
this
characteristic
belongs
to.
uuid
is
the
UUID
of
the
characteristic,
e.g.
'00002a37-0000-1000-8000-00805f9b34fb'
for
the
Heart
Rate
Measurement
characteristic.
properties
holds
the
properties
of
this
characteristic.
value
is
the
currently
cached
characteristic
value.
This
value
gets
updated
when
the
value
of
the
characteristic
is
read
or
updated
via
a
notification
or
indication.
Instances
of
BluetoothRemoteGATTCharacteristic
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[representedCharacteristic]]
| <always set in prose> |
The
Characteristic
this
object
represents,
or
null
if
the
Characteristic
has
been
removed
or
otherwise
invalidated.
|
[[automatedCharacteristicReadResponse]]
|
"not-expected"
| The simulated GATT characteristic response code for a GATT characteristic read attempt. |
[[automatedCharacteristicReadResponseData]]
| Empty byte sequence | The simulated GATT characteristic response data for a GATT characteristic read attempt. |
[[automatedCharacteristicWriteResponse]]
|
"not-expected"
| The simulated GATT characteristic response code for a GATT characteristic write attempt. |
[[automatedCharacteristicSubscribeToNotificationsResponse]]
|
"not-expected"
| The simulated GATT characteristic response code for an attempt to subscribe to GATT characteristic notifications. |
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]
|
"not-expected"
| The simulated GATT characteristic response code for an attempt to unsubscribe from GATT characteristic notifications. |
BluetoothRemoteGATTCharacteristic
representing
a
Characteristic
characteristic
,
the
UA
must
run
the
following
steps:
-
Let global be this ’s relevant global object .
-
Let promise be a new promise .
-
Run the following steps in parallel :
-
Let result be a new instance of
BluetoothRemoteGATTCharacteristicwith its[[representedCharacteristic]]slot initialized to characteristic . -
Initialize result .
service< from theBluetoothRemoteGATTServiceinstance representing the Service in which characteristic appears. -
Initialize result .
uuidfrom the UUID of characteristic . -
Create a
BluetoothCharacteristicPropertiesinstance from the Characteristic characteristic , and let properties be the result. -
If the previous step returned an error, queue a global task on the Bluetooth task source given global to reject promise with that error and abort these steps.
-
Initialize result .
propertiesto properties . -
Initialize result .
valuetonull. The UA MAY initialize result .valueto a newDataViewwrapping a newArrayBuffercontaining the most recently read value from characteristic if this value is available. -
Queue a global task on the Bluetooth task source given global to resolve promise with result .
-
-
Return promise .
getDescriptor(
descriptor
)
method
retrieves
a
Descriptor
inside
this
Characteristic.
When
invoked,
it
MUST
return
GetGATTChildren ( attribute =
this,
single =true,
uuidCanonicalizer =BluetoothUUID.getDescriptor,
uuid =descriptor,
allowedUuids =undefined,
child type ="GATT Descriptor")
getDescriptors(
descriptor
)
method
retrieves
a
list
of
Descriptor
s
inside
this
Characteristic.
When
invoked,
it
MUST
return
GetGATTChildren ( attribute =
this,
single =false,
uuidCanonicalizer =BluetoothUUID.getDescriptor,
uuid =descriptor,
allowedUuids =undefined,
child type ="GATT Descriptor")
readValue()
method,
when
invoked,
MUST
run
the
following
steps:
-
Let global be this ’s relevant global object .
-
If this .
uuidis blocklisted for reads , return a promise rejected with a "SecurityError"DOMExceptionand abort these steps. -
If gatt .
connectedisfalse, return a promise rejected with a "NetworkError"DOMExceptionand abort these steps. -
Let characteristic be this .
[[representedCharacteristic]]. -
If characteristic is
null, return a promise rejected with an "InvalidStateError"DOMExceptionand abort these steps. -
Return a gatt - connection-checking wrapper around a new promise promise and run the following steps in parallel :
-
If the
Readbit is not set in characteristic ’s properties , queue a global task on the Bluetooth task source given global to reject promise with a "NotSupportedError"DOMExceptionand abort these steps. -
If global ’s navigable ’s top-level traversable ’s simulated Bluetooth adapter is not empty, run the following steps:
If this .
[[automatedCharacteristicReadResponse]]is not"not-expected", queue a global task on the Bluetooth task source given global to reject promise with a "InvalidStateError"DOMExceptionand abort these steps.Trigger a simulated characteristic event given global ’s navigable , this .
device, characteristic , andread.Set this .
[[automatedCharacteristicReadResponse]]to"expected", and wait for it to change.Let response be this .
[[automatedCharacteristicReadResponse]].Set this .
[[automatedCharacteristicReadResponse]]to"not-expected".If response is not
0, do the following sub-steps:Queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps.
Otherwise, let buffer be a new
ArrayBuffercontaining this .[[automatedCharacteristicReadResponseData]].
Otherwise, run the following steps:
If the UA is currently using the Bluetooth system, it MAY queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps.Implementations may be able to avoid this
NetworkError, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. [Issue #188]-
Use any combination of the sub-procedures in the Characteristic Value Read procedure to retrieve the value of characteristic
.and let buffer be a newArrayBufferholding the retrieved value. Handle errors as described in § 6.7 Error handling .
-
Queue a global task on the Bluetooth task source given global to perform the following steps:
-
If promise is not in gatt .
[[activeAlgorithms]], reject promise with a "NetworkError"DOMExceptionand abort these steps. -
If the sub-procedures above returned an error, reject promise with that error and abort these steps.
-
Let buffer be a new ArrayBuffer holding the retrieved value, and assignAssign a newDataViewcreated with buffer to this .value. -
Fire an event named "
characteristicvaluechanged" with itsbubblesattribute initialized totrueat this .
-
-
value : BufferSource,
response : string),
the UA MUST perform the following steps:
-
Let global be this ’s relevant global object .
-
If this .
uuidis blocklisted for writes , return a promise rejected with a "SecurityError"DOMExceptionand abort these steps. -
Let bytes be a copy of the bytes held by value .
-
If bytes is more than 512 bytes long (the maximum length of an attribute value, per Long Attribute Values ) return a promise rejected with an "
InvalidModificationError"DOMExceptionand abort these steps. -
If gatt .
connectedisfalse, return a promise rejected with a "NetworkError"DOMExceptionand abort these steps. -
Let characteristic be this .
[[representedCharacteristic]]. -
If characteristic is
null, return a promise rejected with an "InvalidStateError"DOMExceptionand abort these steps. -
Return a gatt - connection-checking wrapper around a new promise promise and run the following steps in parallel .
-
Assert: response is one of "required", "never", or "optional".
-
If global ’s navigable ’s top-level traversable ’s simulated Bluetooth adapter is not empty, run the following steps:
If this .
[[automatedCharacteristicWriteResponse]]is not"not-expected", queue a global task on the Bluetooth task source given global to reject promise with a "InvalidStateError"DOMExceptionand abort these steps.Trigger a simulated characteristic event given global ’s navigable , this .
device, characteristic ,write, and bytes .Set this .
[[automatedCharacteristicWriteResponse]]to"expected", and wait for it to change.Let response be this .
[[automatedCharacteristicWriteResponse]].Set this .
[[automatedCharacteristicWriteResponse]]to"not-expected".If response is not
0, do the following sub-steps:Queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps.
Otherwise, run the following steps:
If the UA is currently using the Bluetooth system, it MAY queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps.Implementations may be able to avoid this
NetworkError, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. [Issue #188]-
Write bytes to characteristic by performing the following steps:
- If response is "required"
- Use the Write Characteristic Value procedure.
- If response is "never"
- Use the Write Without Response procedure.
- Otherwise
- Use any combination of the sub-procedures in the Characteristic Value Write procedure.
-
Queue a global task on global using the Bluetooth task source to perform the following steps:
-
If promise is not in gatt .
[[activeAlgorithms]], reject promise with a "NetworkError"DOMExceptionand abort these steps. -
If the procedure above returned an error, reject promise with that error and abort these steps.
-
Set this .
valueto a newDataViewwrapping a newArrayBuffercontaining bytes . -
Resolve promise with
undefined.
-
-
writeValueWithResponse()
and
writeValueWithoutResponse()
instead.
The
method,
when
invoked,
MUST
return
writeValue(
value
)
WriteCharacteristicValue ( this =
this,
value =value,
response ="optional")
This method is for backwards compatibility only. New implementations should not implement this method. [Issue #238]
writeValueWithResponse(
value
)
method,
when
invoked,
MUST
return
WriteCharacteristicValue ( this =
this,
value =value,
response ="required")
writeValueWithoutResponse(
value
)
method,
when
invoked,
MUST
return
WriteCharacteristicValue ( this =
this,
value =value,
response ="never")
The
UA
MUST
maintain
a
map
from
each
known
GATT
Characteristic
to
a
set
of
Bluetooth
objects
known
as
the
characteristic’s
active
notification
context
set
.
navigator.bluetooth
objects
for
each
Realm
that
has
registered
for
notifications.
All
notifications
become
inactive
when
a
device
is
disconnected.
A
site
that
wants
to
keep
getting
notifications
after
reconnecting
needs
to
call
startNotifications()
again,
and
there
is
an
unavoidable
risk
that
some
notifications
will
be
missed
in
the
gap
before
startNotifications()
takes
effect.
startNotifications()
method,
when
invoked,
MUST
run
the
following
steps.
See
§ 6.6.4
Responding
to
Notifications
and
Indications
for
details
of
receiving
notifications.
-
Let global be this ’s relevant global object .
-
If this .
uuidis blocklisted for reads , return a promise rejected with a "SecurityError"DOMException. -
If gatt .
connectedisfalse, return a promise rejected with with a "NetworkError"DOMException. -
Let characteristic be this .
[[representedCharacteristic]]. -
If characteristic is
null, return a promise rejected with an "InvalidStateError"DOMException. -
Return a gatt - connection-checking wrapper around a new promise promise and run the following steps in parallel .
-
If neither of the
NotifyorIndicatebits are set in characteristic ’s properties , queue a global task on the Bluetooth task source given global to reject promise with aNotSupportedErrorand abort these steps. -
If characteristic ’s active notification context set contains
navigator.bluetooth, queue a global task on the Bluetooth task source given global to resolve promise with this and abort these steps. -
If global ’s navigable ’s top-level traversable ’s simulated Bluetooth adapter is not empty, run the following steps:
If this .
[[automatedCharacteristicSubscribeToNotificationsResponse]]is not"not-expected", queue a global task on the Bluetooth task source given global to reject promise with a "InvalidStateError"DOMExceptionand abort these steps.Trigger a simulated characteristic event given global ’s navigable , this .
device, characteristic , andsubscribe-to-notifications.Set this .
[[automatedCharacteristicSubscribeToNotificationsResponse]]to"expected", and wait for it to change.Let response be this .
[[automatedCharacteristicSubscribeToNotificationsResponse]].Set this .
[[automatedCharacteristicSubscribeToNotificationsResponse]]to"not-expected".If response is not
0, do the following sub-steps:Queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps.
Otherwise, let success to be
true.
Otherwise, run the following steps:
If the UA is currently using the Bluetooth system, it MAY queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps.Implementations may be able to avoid this
NetworkError, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. [Issue #188]-
If the characteristic has a Client Characteristic Configuration descriptor, use any of the Characteristic Descriptors procedures to ensure that one of the
NotificationorIndicationbits in characteristic ’s Client Characteristic Configuration descriptor is set, matching the constraints in characteristic ’s properties . The UA SHOULD avoid setting both bits, and MUST deduplicate value-change events if both bits are set. Handle errors as described in § 6.7 Error handling .Note: Some devices have characteristics whose properties include the Notify or Indicate bit but that don’t have a Client Characteristic Configuration descriptor. These non-standard-compliant characteristics tend to send notifications or indications unconditionally, so this specification allows applications to simply subscribe to their messages. -
If the procedures were successful, let success to be
true.
If success is
true, addnavigator.bluetoothto characteristic ’s active notification context set .-
Queue a global task on the Bluetooth task source given global to perform the following steps:
-
If promise is not in gatt .
[[activeAlgorithms]], reject promise with a "NetworkError"DOMExceptionand abort these steps. -
If the procedures above returned an error, reject promise with that error and abort these steps.
-
-
.then
handler
of
the
result
promise.
stopNotifications()
method,
when
invoked,
MUST
return
a
new
promise
promise
and
run
the
following
steps
in
parallel
:
-
Let characteristic be
this..[[representedCharacteristic]] -
If characteristic is
null, return a promise rejected with anInvalidStateErrorand abort these steps. -
If characteristic ’s active notification context set contains
navigator.bluetooth, remove it.-
If global ’s navigable ’s top-level traversable ’s simulated Bluetooth adapter is not empty, run the following steps:
If this .
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]is not"not-expected", queue a global task on the Bluetooth task source given global to reject promise with a "InvalidStateError"DOMExceptionand abort these steps.Trigger a simulated characteristic event given global ’s navigable , this .
device, characteristic , andunsubscribe-from-notifications.Set this .
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]to"expected", and wait for it to change.Let response be this .
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]].Set this .
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]to"not-expected".If response is not
0, do the following sub-steps:Queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps..
Otherwise, run the following steps:
-
If characteristic ’s active notification context set became empty and the characteristic has a Client Characteristic Configuration descriptor, the UA SHOULD use any of the Characteristic Descriptors procedures to clear the
NotificationandIndicationbits in characteristic ’s Client Characteristic Configuration descriptor.
-
-
-
Queue a global task on the Bluetooth task source given this ’s relevant global object to resolve promise with this .
6.4.1. BluetoothCharacteristicProperties
Each
BluetoothRemoteGATTCharacteristic
exposes
its
characteristic
properties
through
a
BluetoothCharacteristicProperties
object.
These
properties
express
what
operations
are
valid
on
the
characteristic.
[Exposed =Window ,SecureContext ]interface {BluetoothCharacteristicProperties readonly attribute boolean ;broadcast readonly attribute boolean ;read readonly attribute boolean ;writeWithoutResponse readonly attribute boolean ;write readonly attribute boolean ;notify readonly attribute boolean ;indicate readonly attribute boolean ;authenticatedSignedWrites readonly attribute boolean ;reliableWrite readonly attribute boolean ; };writableAuxiliaries
BluetoothCharacteristicProperties
instance
from
the
Characteristic
characteristic
,
the
UA
MUST
run
the
following
steps:
-
Let propertiesObj be a new instance of
BluetoothCharacteristicProperties. -
Let properties be the characteristic properties of characteristic .
-
Initialize the attributes of propertiesObj from the corresponding bits in properties :
Attribute Bit broadcastBroadcast readRead writeWithoutResponseWrite Without Response writeWrite notifyNotify indicateIndicate authenticatedSignedWritesAuthenticated Signed Writes -
If the Extended Properties bit of the characteristic properties is not set, initialize propertiesObj .
reliableWriteand propertiesObj .writableAuxiliariestofalse. Otherwise, run the following steps:-
Discover the Characteristic Extended Properties descriptor for characteristic and read its value into extendedProperties . Handle errors as described in § 6.7 Error handling .
Characteristic Extended Properties isn’t clear whether the extended properties are immutable for a given Characteristic. If they are, the UA should be allowed to cache them.
-
If the previous step returned an error, return that error.
-
Initialize propertiesObj .
reliableWritefrom the Reliable Write bit of extendedProperties . -
Initialize propertiesObj .
writableAuxiliariesfrom the Writable Auxiliaries bit of extendedProperties .
-
-
Return propertiesObj .
6.5. BluetoothRemoteGATTDescriptor
BluetoothRemoteGATTDescriptor
represents
a
GATT
Descriptor
,
which
provides
further
information
about
a
Characteristic
’s
value.
[Exposed =Window ,SecureContext ]interface { [BluetoothRemoteGATTDescriptor SameObject ]readonly attribute BluetoothRemoteGATTCharacteristic characteristic ;readonly attribute UUID uuid ;readonly attribute DataView ?value ;Promise <DataView >readValue ();Promise <undefined >writeValue (BufferSource ); };value
BluetoothRemoteGATTDescriptor
attributes
characteristic
is
the
GATT
characteristic
this
descriptor
belongs
to.
uuid
is
the
UUID
of
the
characteristic
descriptor,
e.g.
'00002902-0000-1000-8000-00805f9b34fb'
for
the
Client
Characteristic
Configuration
descriptor.
value
is
the
currently
cached
descriptor
value.
This
value
gets
updated
when
the
value
of
the
descriptor
is
read.
Instances
of
BluetoothRemoteGATTDescriptor
are
created
with
the
internal
slots
described
in
the
following
table:
| Internal Slot | Initial Value | Description (non-normative) |
|---|---|---|
[[representedDescriptor]]
| <always set in prose> |
The
Descriptor
this
object
represents,
or
null
if
the
Descriptor
has
been
removed
or
otherwise
invalidated.
|
BluetoothRemoteGATTDescriptor
representing
a
Descriptor
descriptor
,
the
UA
MUST
run
the
following
steps.
-
Let promise be a new promise .
-
Run the following steps in parallel :
-
Let result be a new instance of
BluetoothRemoteGATTDescriptorwith its[[representedDescriptor]]slot initialized to descriptor . -
Initialize result .
characteristicfrom theBluetoothRemoteGATTCharacteristicinstance representing the Characteristic in which descriptor appears. -
Initialize result .
uuidfrom the UUID of descriptor . -
Initialize result .
valuetonull. The UA MAY initialize result .valuea newDataViewwrapping a newArrayBuffercontaining the most recently read value from descriptor if this value is available. -
Queue a global task on the Bluetooth task source given this ’s relevant global object to resolve promise with result .
-
-
Return promise .
readValue()
method,
when
invoked,
MUST
run
the
following
steps:
-
Let global be this ’s relevant global object .
-
Let gatt be this .
characteristic.service.device.gatt. -
If this .
uuidis blocklisted for reads , return a promise rejected with a "SecurityError"DOMException. -
If gatt .
connectedisfalse, return a promise rejected with a "NetworkError"DOMException. -
Let descriptor be this .
[[representedDescriptor]]. -
If descriptor is
null, return a promise rejected with an "InvalidStateError"DOMException. -
Return a gatt - connection-checking wrapper around a new promise promise and run the following steps in parallel :
-
If the UA is currently using the Bluetooth system, it MAY queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps.Implementations may be able to avoid this
NetworkError, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. [Issue #188] -
Use either the Read Characteristic Descriptors or the Read Long Characteristic Descriptors sub-procedure to retrieve the value of descriptor . Handle errors as described in § 6.7 Error handling .
-
Queue a global task on the Bluetooth task source given global to perform the following steps:
-
If promise is not in gatt .
[[activeAlgorithms]], reject promise with a "NetworkError"DOMExceptionand abort these steps. -
If the sub-procedure above returned an error, reject promise with that error and abort these steps.
-
Let buffer be a new
ArrayBufferholding the retrieved value, and assign a newDataViewcreated with buffer to this .value.
-
-
writeValue(
value
)
method,
when
invoked,
MUST
run
the
following
steps:
-
Let global be this ’s relevant global object .
-
Let gatt be this .
characteristic.service.device.gatt. -
If this .
uuidis blocklisted for writes , return a promise rejected with a "SecurityError"DOMException. -
Let bytes be a copy of the bytes held by value .
-
If bytes is more than 512 bytes long (the maximum length of an attribute value, per Long Attribute Values ) return a promise rejected with an "
InvalidModificationError"DOMException. -
If gatt .
connectedisfalse, return a promise rejected with a "NetworkError"DOMException. -
Let descriptor be this .
[[representedDescriptor]]. -
If descriptor is
null, return a promise rejected with an "InvalidStateError"DOMException. -
Return a gatt - connection-checking wrapper around a new promise promise and run the following steps in parallel .
-
If the UA is currently using the Bluetooth system, it MAY queue a global task on the Bluetooth task source given global to reject promise with a "
NetworkError"DOMExceptionand abort these steps.Implementations may be able to avoid this
NetworkError, but for now sites need to serialize their use of this API and/or give the user a way to retry failed operations. [Issue #188] -
Use either the Write Characteristic Descriptors or the Write Long Characteristic Descriptors sub-procedure to write bytes to descriptor . Handle errors as described in § 6.7 Error handling .
-
Queue a global task on the Bluetooth task source given global to perform the following steps:
-
If promise is not in gatt .
[[activeAlgorithms]], reject promise with a "NetworkError"DOMExceptionand abort these steps. -
If the sub-procedure above returned an error, reject promise with that error and abort these steps.
-
Set this .
valueto a newDataViewwrapping a newArrayBuffercontaining bytes . -
Resolve promise with
undefined.
-
-
6.6. Events
6.6.1. Bluetooth Tree
The
Bluetooth
tree
is
the
name
given
to
navigator.bluetooth
and
objects
implementing
the
BluetoothDevice
,
BluetoothRemoteGATTService
,
BluetoothRemoteGATTCharacteristic
,
or
BluetoothRemoteGATTDescriptor
interface
participate
in
a
tree
.
-
The children of
navigator.bluetoothare theBluetoothDeviceobjects representing devices in theallowedDeviceslist in "bluetooth" ’s extra permission data fornavigator.bluetooth’s relevant settings object , in an unspecified order. -
The children of a
BluetoothDeviceare theBluetoothRemoteGATTServiceobjects representing Primary and Secondary Service s on its GATT Server whose UUIDs are on the origin and device’sallowedServiceslist. The order of the primary services MUST be consistent with the order returned by the Discover Primary Service by Service UUID procedure, but secondary services and primary services with different UUIDs may be in any order. -
The children of a
BluetoothRemoteGATTServiceare theBluetoothRemoteGATTCharacteristicobjects representing its Characteristics. The order of the characteristics MUST be consistent with the order returned by the Discover Characteristics by UUID procedure, but characteristics with different UUIDs may be in any order. -
The children of a
BluetoothRemoteGATTCharacteristicare theBluetoothRemoteGATTDescriptorobjects representing its Descriptors in the order returned by the Discover All Characteristic Descriptors procedure.
6.6.2. Event types
-
advertisementreceived -
Fired
on
a
BluetoothDevicewhen an advertising event is received from that device . -
availabilitychanged -
Fired
on
navigator.bluetoothwhen the Bluetooth system as a whole becomes available or unavailable to the UA . -
characteristicvaluechanged -
Fired
on
a
BluetoothRemoteGATTCharacteristicwhen its value changes, either as a result of a read request , or a value change notification/indication . -
gattserverdisconnected -
Fired
on
a
BluetoothDevicewhen an active GATT connection is lost . -
serviceadded -
Fired
on
a
new
BluetoothRemoteGATTServicewhen it has been discovered on a remote device , just after it is added to the Bluetooth tree . -
servicechanged -
Fired
on
a
BluetoothRemoteGATTServicewhen its state changes . This involves any characteristics and/or descriptors that get added or removed from the service, as well as Service Changed indications from the remote device. -
serviceremoved -
Fired
on
a
BluetoothRemoteGATTServicewhen it has been removed from its device , just before it is removed from the Bluetooth tree .
6.6.3. Responding to Disconnection
BluetoothDevice
deviceObj
the
UA
MUST
queue
a
global
task
on
the
Bluetooth
task
source
given
deviceObj
’s
relevant
global
object
to
perform
the
following
steps:
-
If
deviceObj .is not the same device as device , abort these steps.[[representedDevice]] -
If
! deviceObj .gatt., abort these steps.connected -
Clean up the disconnected device deviceObj .
-
Set
deviceObj .gatt.toconnectedfalse. -
Clear
deviceObj .gatt..[[activeAlgorithms]] -
Set
deviceObj .gatt.to[[automatedGATTConnectionResponse]]"not-expected". -
Let context be
deviceObj ..[[context]] -
Remove all entries from
context .whose keys are inside[[attributeInstanceMap]]deviceObj ..[[representedDevice]] -
For each
BluetoothRemoteGATTServiceservice in deviceObj ’s realm , setservice .to[[representedService]]null. -
For each
BluetoothRemoteGATTCharacteristiccharacteristic in deviceObj ’s realm , do the following sub-steps:-
Let notificationContexts be
characteristic .’s active notification context set .[[representedCharacteristic]] -
Remove context from notificationContexts .
-
If notificationContexts became empty and there is still an ATT Bearer to
deviceObj .and characteristic has a Client Characteristic Configuration descriptor, the UA SHOULD use any of the Characteristic Descriptors procedures to clear the[[representedDevice]]NotificationandIndicationbits in characteristic ’s Client Characteristic Configuration descriptor. -
Set
characteristic .to[[representedCharacteristic]]null.
-
-
For each
BluetoothRemoteGATTDescriptordescriptor in deviceObj ’s realm , setdescriptor .to[[representedDescriptor]]null. -
Fire an event named
gattserverdisconnectedwith itsbubblesattribute initialized totrueatdeviceObj.Note: This event is not fired at theBluetoothRemoteGATTServer.
6.6.4. Responding to Notifications and Indications
-
For each bluetoothGlobal in the Characteristic’s active notification context set , queue a global task on the Bluetooth task source given bluetoothGlobal ’s relevant global object to do the following sub-steps:
-
Let characteristicObject be the
BluetoothRemoteGATTCharacteristicin the Bluetooth tree rooted at bluetoothGlobal that represents the Characteristic . -
If
characteristicObject .service.device.gatt.isconnectedfalse, abort these sub-steps. -
Set
characteristicObject .valueto a newDataViewwrapping a newArrayBufferholding the new value of the Characteristic . -
Fire an event named
characteristicvaluechangedwith itsbubblesattribute initialized totrueat characteristicObject .
-
6.6.5. Responding to Service Changes
-
Let removedAttributes be the list of attributes in the range indicated by the Service Changed characteristic that the UA had discovered before the Indication.
-
Use the Primary Service Discovery , Relationship Discovery , Characteristic Discovery , and Characteristic Descriptor Discovery procedures to re-discover attributes in the range indicated by the Service Changed characteristic. The UA MAY skip discovering all or part of the indicated range if it can prove that the results of that discovery could not affect the events fired below.
-
Let addedAttributes be the list of attributes discovered in the previous step.
-
If an attribute with the same definition (see the Service Interoperability Requirements ), ignoring Characteristic and Descriptor values, appears in both removedAttributes and addedAttributes , remove it from both.
Given the following device states:- State 1
-
-
Service
A
-
Characteristic
C:
value
[1, 2, 3]
-
Characteristic
C:
value
- Service B
-
Service
A
- State 2
-
-
Service
A
-
Characteristic
C:
value
[3, 2, 1]
-
Characteristic
C:
value
- Service B
-
Service
A
- State 3
-
-
Service
A
-
Characteristic
D:
value
[3, 2, 1]
-
Characteristic
D:
value
- Service B
-
Service
A
- State 4
-
-
Service
A
-
Characteristic
C:
value
[1, 2, 3]
-
Characteristic
C:
value
-
Service
B
- Include Service A
-
Service
A
A transition from state 1 to 2 leaves service A with "the same definition, ignoring Characteristic and Descriptor values", which means it’s removed from both removedAttributes and addedAttributes , and it wouldn’t appear in any
servicechangedevents.A transition from state 1 to 3 leaves service A with a different definition, because a service definition includes its characteristic definitions, so it’s left in both removedAttributes and addedAttributes . Then in step 8 , the service is moved to changedServices , which makes it cause a
servicechangedevent instead of both aserviceaddedandserviceremoved. Step 9 also adds service A to changedServices because characteristic C was removed and characteristic D was added.A transition from state 1 to 4 is similar to the 1->3 transition. Service B is moved to changedServices in step 8 , but no characteristics or descriptors have changed, so it’s not redundantly added in step 9 .
-
Let invalidatedAttributes be the attributes in removedAttributes but not addedAttributes .
-
For each environment settings object settings in the UA, queue a task on its responsible event loop to do the following sub-steps:
-
For each
BluetoothRemoteGATTServiceservice whose relevant settings object is settings , ifservice .is in invalidatedAttributes , set[[representedService]]service .to[[representedService]]null. -
For each
BluetoothRemoteGATTCharacteristiccharacteristic whose relevant settings object is settings , ifcharacteristic .is in invalidatedAttributes , set[[representedCharacteristic]]characteristic .to[[representedCharacteristic]]null. -
For each
BluetoothRemoteGATTDescriptordescriptor whose relevant settings object is settings , ifdescriptor .is in invalidatedAttributes , set[[representedDescriptor]]descriptor .to[[representedDescriptor]]null. -
Let global be settings ’ global object .
-
Remove every entry from
global .navigator.bluetooth.that represents an attribute that is in invalidatedAttributes .[[attributeInstanceMap]]
-
-
Let changedServices be a set of Service s, initially empty.
-
If the same Service appears in both removedAttributes and addedAttributes , remove it from both, and add it to changedServices .
-
For each Characteristic and Descriptor in removedAttributes or addedAttributes , remove it from its original list, and add its parent Service to changedServices .
Note: After this point, removedAttributes and addedAttributes contain only Service s. -
If a Service in addedAttributes would not have been returned from any previous call to
getPrimaryService,getPrimaryServices,getIncludedService, orgetIncludedServicesif it had existed at the time of the call, the UA MAY remove the Service from addedAttributes . -
Let changedDevices be the set of Bluetooth device s that contain any Service in removedAttributes , addedAttributes , and changedServices .
-
For each
BluetoothDevicedeviceObj that is connected to a device in changedDevices , queue a global task on the Bluetooth task source given deviceObj ’s relevant global object to do the following steps:-
For each Service service in removedAttributes :
-
If
deviceObj .is[[allowedServices]]"all"or contains the Service’s UUID, fire an event namedserviceremovedwith itsbubblesattribute initialized totrueat theBluetoothRemoteGATTServicerepresenting the Service . -
Remove this
BluetoothRemoteGATTServicefrom the Bluetooth tree .
-
-
For each Service in addedAttributes , if
deviceObj.is[[allowedServices]]"all"or contains the Service’s UUID, add theBluetoothRemoteGATTServicerepresenting this Service to the Bluetooth tree and then fire an event namedserviceaddedwith itsbubblesattribute initialized totrueat theBluetoothRemoteGATTService. -
For each Service in changedServices , if
deviceObj.is[[allowedServices]]"all"or contains the Service’s UUID, fire an event namedservicechangedwith itsbubblesattribute initialized totrueat theBluetoothRemoteGATTServicerepresenting the Service .
-
6.6.6. IDL event handlers
[SecureContext ]interface mixin {CharacteristicEventHandlers attribute EventHandler oncharacteristicvaluechanged ; };
oncharacteristicvaluechanged
is
an
Event
handler
IDL
attribute
for
the
characteristicvaluechanged
event
type.
[SecureContext ]interface mixin {BluetoothDeviceEventHandlers attribute EventHandler onadvertisementreceived ;attribute EventHandler ongattserverdisconnected ; };
onadvertisementreceived
is
an
Event
handler
IDL
attribute
for
the
advertisementreceived
event
type.
ongattserverdisconnected
is
an
Event
handler
IDL
attribute
for
the
gattserverdisconnected
event
type.
[SecureContext ]interface mixin {ServiceEventHandlers attribute EventHandler onserviceadded ;attribute EventHandler onservicechanged ;attribute EventHandler onserviceremoved ; };
onserviceadded
is
an
Event
handler
IDL
attribute
for
the
serviceadded
event
type.
onservicechanged
is
an
Event
handler
IDL
attribute
for
the
servicechanged
event
type.
onserviceremoved
is
an
Event
handler
IDL
attribute
for
the
serviceremoved
event
type.
6.7. Error handling
Error
Response
,
the
UA
MUST
perform
the
following
steps:
-
If the procedure times out or the ATT Bearer (described in Profile Fundamentals ) is absent or terminated for any reason, return a
NetworkErrorfrom the step and abort these steps. -
Take the following actions depending on the
Error Code:-
Invalid PDUInvalid OffsetAttribute Not FoundUnsupported Group Type -
These
error
codes
indicate
that
something
unexpected
happened
at
the
protocol
layer,
likely
either
due
to
a
UA
or
device
bug.
Return
a
NotSupportedErrorfrom the step. -
Invalid Handle -
Return
an
InvalidStateErrorfrom the step. -
Invalid Attribute Value Length -
Return
an
InvalidModificationErrorfrom the step. -
Attribute Not Long -
If this error code is received without having used a "Long" sub-procedure, this may indicate a device bug. Return a
NotSupportedErrorfrom the step.Otherwise, retry the step without using a "Long" sub-procedure. If this is impossible due to the length of the value being written, return an
InvalidModificationErrorfrom the step. -
Insufficient AuthenticationInsufficient EncryptionInsufficient Encryption Key Size -
The
UA
SHOULD
attempt
to
increase
the
security
level
of
the
connection.
If
this
attempt
fails
or
the
UA
doesn’t
support
any
higher
security,
Return
a
SecurityErrorfrom the step. Otherwise, retry the step at the new higher security level. -
Insufficient Authorization -
Return
a
SecurityErrorfrom the step. -
Application Error -
If
the
GATT
procedure
was
a
Write,
return
an
InvalidModificationErrorfrom the step. Otherwise, return aNotSupportedErrorfrom the step. -
Read Not PermittedWrite Not PermittedRequest Not SupportedPrepare Queue FullInsufficient ResourcesUnlikely Error- Anything else
-
Return
a
NotSupportedErrorfrom the step.
-
7. UUIDs
typedef DOMString ;UUID
A
UUID
string
represents
a
128-bit
[RFC4122]
UUID.
A
valid
UUID
is
a
string
that
matches
the
[ECMAScript]
regexp
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
.
That
is,
a
valid
UUID
is
lower-case
and
does
not
use
the
16-
or
32-bit
abbreviations
defined
by
the
Bluetooth
standard.
All
UUIDs
returned
from
functions
and
attributes
in
this
specification
MUST
be
valid
UUID
s.
If
a
function
in
this
specification
takes
a
parameter
whose
type
is
UUID
or
a
dictionary
including
a
UUID
attribute,
and
the
argument
passed
in
any
UUID
slot
is
not
a
valid
UUID
,
the
function
MUST
return
a
promise
rejected
with
a
TypeError
and
abort
its
other
steps.
BluetoothUUID.
canonicalUUID(
alias
)
function
to
map
a
16-
or
32-bit
Bluetooth
UUID
alias
to
its
128-bit
form.
7.1. Standardized UUIDs
The Bluetooth SIG maintains a registry at [BLUETOOTH-ASSIGNED] of UUIDs that identify services, characteristics, descriptors, and other entities. This section provides a way for script to look up those UUIDs by name so they don’t need to be replicated in each application.
A
valid
name
is
a
string
that
matches
the
[ECMAScript]
regexp
/^[a-z0-9_-.]+$/
.
[Exposed =Window ]interface {BluetoothUUID static UUID getService ((DOMString or unsigned long ));name static UUID getCharacteristic ((DOMString or unsigned long ));name static UUID getDescriptor ((DOMString or unsigned long ));name static UUID canonicalUUID ([EnforceRange ]unsigned long ); };alias typedef (DOMString or unsigned long )BluetoothServiceUUID ;typedef (DOMString or unsigned long )BluetoothCharacteristicUUID ;typedef (DOMString or unsigned long )BluetoothDescriptorUUID ;
The
static
BluetoothUUID.
method,
when
invoked,
MUST
return
the
128-bit
UUID
represented
by
the
16-
or
32-bit
UUID
alias
alias
.
canonicalUUID(
alias
)
00000000-0000-1000-8000-00805f9b34fb
"
with
the
bits
of
the
alias.
For
example,
canonicalUUID(0xDEADBEEF)
returns
"deadbeef-0000-1000-8000-00805f9b34fb"
.
BluetoothServiceUUID
represents
16-
and
32-bit
UUID
aliases,
valid
UUID
s,
and
valid
name
s
from
GATT
assigned
services
keys,
or,
equivalently,
the
values
for
which
BluetoothUUID.getService()
does
not
throw
an
exception.
BluetoothCharacteristicUUID
represents
16-
and
32-bit
UUID
aliases,
valid
UUID
s,
and
valid
name
s
from
GATT
assigned
characteristics
keys,
or,
equivalently,
the
values
for
which
BluetoothUUID.getCharacteristic()
does
not
throw
an
exception.
BluetoothDescriptorUUID
represents
16-
and
32-bit
UUID
aliases,
valid
UUID
s,
and
valid
name
s
from
GATT
assigned
descriptors
keys,
or,
equivalently,
the
values
for
which
BluetoothUUID.getDescriptor()
does
not
throw
an
exception.
-
If name is an
unsigned long, returnBluetoothUUID.canonicalUUID(name) and abort these steps. -
If name is a valid UUID , return name and abort these steps.
-
If name is a valid name and maps to a valid UUID in GATT assigned numbers , let alias be its assigned number, and return
BluetoothUUID.canonicalUUID( alias ). -
Otherwise, throw a
TypeError.
The
static
BluetoothUUID.
method,
when
invoked,
MUST
return
ResolveUUIDName
(
getService(
name
)
name
,
GATT
assigned
services
).
The
static
BluetoothUUID.
method,
when
invoked,
MUST
return
ResolveUUIDName
(
getCharacteristic(
name
)
name
,
GATT
assigned
characteristics
).
The
static
BluetoothUUID.
method,
when
invoked,
MUST
return
ResolveUUIDName
(
getDescriptor(
name
)
name
,
GATT
assigned
descriptors
).
BluetoothUUID.getService
("
cycling_power
")
returns
"00001818-0000-1000-8000-00805f9b34fb"
.
returns
BluetoothUUID.getService
("00001801-0000-1000-8000-00805f9b34fb")
"00001801-0000-1000-8000-00805f9b34fb"
.
throws
a
BluetoothUUID.getService
("unknown-service")
TypeError
.
returns
BluetoothUUID.getCharacteristic
("
ieee_11073-20601_regulatory_certification_data_list
")
"00002a2a-0000-1000-8000-00805f9b34fb"
.
returns
BluetoothUUID.getDescriptor
("
gatt.characteristic_presentation_format
")
"00002904-0000-1000-8000-00805f9b34fb"
.
7.2. GATT assigned numbers
This specification provides human-readable names for GATT assigned numbers to increase readability for developers using standardized GATT services, characteristics, and descriptors. The GATT assigned numbers files live in the https://github.com/WebBluetoothCG/registries repository.
-
Fetch url , and let contents be its body, decoded as UTF-8.
-
Let lines be contents split on
'\n'. -
Let result be an empty map.
-
For each line in lines , do the following sub-steps:
-
If line is empty or its first character is
'#', continue to the next line. -
If line consists of a valid name , a space (U+0020), and a valid UUID , let name be that name and let uuid be that UUID.
-
Otherwise, return an error and abort these steps.
-
If name is already in result , return an error and abort these steps.
-
Add a mapping in result from name to uuid .
-
-
Return result .
The GATT assigned services are the result of parsing the GATT assigned numbers at https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_services.txt . The UA should re-fetch this file periodically, but it’s unspecified how often.
The GATT assigned characteristics are the result of parsing the GATT assigned numbers at https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_characteristics.txt . The UA should re-fetch this file periodically, but it’s unspecified how often.
The GATT assigned descriptors are the result of parsing the GATT assigned numbers at https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_descriptors.txt . The UA should re-fetch this file periodically, but it’s unspecified how often.
8. Advertising Data Filter
An advertising data filter represents a way to match against manufacturer or service data.
-
Let words be input strictly split on
/. -
If the length of words is not equal to
2, return an error and abort these steps. -
If the length of words [0] is not equal to the length of words [1], return an error and abort these steps.
-
Let prefixData be words [0].
-
Let prefixMask be words [1].
-
If prefixData or prefixMask is not a sequence of ascii lower hex digit , return an error.
-
Let prefixIndex be
0. -
let dataList be an empty list.
-
let maskList be an empty list.
-
While prefixIndex is less than the length of prefixData , do the following sub-steps:
-
Let data be the result of interpreting the characters at index prefixIndex and
prefixIndex + 1of prefixData as a hexadecimal number. -
Let mask be the result of interpreting the characters at index prefixIndex and
prefixIndex + 1of prefixMask as a hexadecimal number. -
Append data to dataList .
-
Append mask to maskList .
-
Set prefixIndex to
|prefixIndex| + 2.
-
-
Let result be a new
BluetoothDataFilterInitdictionary. -
Set result [
dataPrefix] to anUint8Arrayconstructed with dataList . -
Set result [
mask] to anUint8Arrayconstructed with maskList . -
Return result .
9. The Blocklist
This specification relies on blocklist files in the https://github.com/WebBluetoothCG/registries repository to restrict the set of GATT attributes and manufacturer data a website can access.
A
valid
company
identifier
string
is
a
seqeunce
of
ascii
lower
hex
digit
that
its
length
is
bigger
than
0
and
less
than
5
.
The
official
list
of
company
identifies
can
be
found
on
Bluetooth
Assigned
Numbers
website
.
BluetoothDataFilterInit
,
or
an
error,
produced
by
the
following
algorithm:
-
Fetch url , and let contents be its body, decoded as UTF-8.
-
Let lines be the result of invoking
split(separator, limit)on contents with separator'\n'. -
Let result be an empty map.
-
For each line in lines , do the following sub-steps:
-
If line is empty or its first character is
'#', continue to the next line. -
Let regExp be a
RegExpconstructed with 'manufacturer\ ([0-9a-f]+)\ ([0-9a-f]+\/[0-9a-f]+)'. -
Let matchResult be the result of invoking regExp .
exec(string)on line , or return an error if matchResult isnullor the length of matchResult is not equal to3. -
Let companyIdentifierStr be matchResult [1] if matchResult [1] is a valid company identifier string , otherwise return an error.
-
Let companyIdentifier be the result of interpreting companyIdentifierStr as a hexadecimal number.
-
Let dataPrefixStr be matchResult [2].
-
If companyIdentifier is not in result , set result [ companyIdentifier ] to be an empty list.
-
Let dataFilter be the result of parsing an advertising data filter at dataPrefixStr if the result is not an error, otherwise return an error.
-
Append dataFilter to result [ companyIdentifier ].
-
-
Return result .
-
Fetch url , and let contents be its body, decoded as UTF-8.
-
Let lines be contents split on
'\n'. -
Let result be an empty map.
-
For each line in lines , do the following sub-steps:
-
If line is empty or its first character is
'#', continue to the next line. -
If line consists of just a valid UUID , let uuid be that UUID and let token be "
exclude". -
If line consists of a valid UUID , a space (U+0020), and one of the tokens "
exclude-reads" or "exclude-writes", let uuid be that UUID and let token be that token. -
Otherwise, return an error and abort these steps.
-
If uuid is already in result , return an error and abort these steps.
-
Add a mapping in result from uuid to token .
-
-
Return result .
The GATT blocklist is the result of parsing the gatt blocklist at https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt . The Manufacturer Data blocklist is the result of parsing the manufacturer data blocklist at https://github.com/WebBluetoothCG/registries/blob/master/manufacturer_data_blocklist.txt . The UA should re-fetch the blocklist periodically, but it’s unspecified how often.
A
UUID
is
blocklisted
if
either
the
GATT
blocklist
’s
value
is
an
error,
or
the
UUID
maps
to
"
exclude
"
in
the
GATT
blocklist
.
A
UUID
is
blocklisted
for
reads
if
either
the
GATT
blocklist
’s
value
is
an
error,
or
the
UUID
maps
to
either
"
exclude
"
or
"
exclude-reads
"
in
the
GATT
blocklist
.
A
UUID
is
blocklisted
for
writes
if
either
the
GATT
blocklist
’s
value
is
an
error,
or
the
UUID
maps
to
either
"
exclude
"
or
"
exclude-writes
"
in
the
GATT
blocklist
.
blocked
:
-
If the Manufacturer Data blocklist ’s value is an error, return
blocked. -
Let manufacturerBlocklist be the Manufacturer Data blocklist ’s value.
-
Let companyIdentifier be the company identifier of manufacturerData .
-
If companyIdentifier is not in manufacturerBlocklist , return
unblocked. -
For each dataFilter in manufacturerBlocklist [ companyIdentifier ], do the following sub-steps:
-
If the advertising data of manufacturerData matches dataFilter , return
blocked.
-
-
Return
unblocked.
blocked
:
-
If the Manufacturer Data blocklist ’s value is an error, return
blocked. -
Let manufacturerBlocklist be the Manufacturer Data blocklist ’s value.
-
Let companyIdentifier be manufacturerDataFilter ["
companyIdentifier"]. -
If companyIdentifier is not in manufacturerBlocklist , return
unblocked. -
For each dataFilter in manufacturerBlocklist [ companyIdentifier ], do the following sub-steps:
-
If manufacturerDataFilter is a strict subset of dataFilter , return
blocked.
-
-
Return
unblocked.
10. Extensions to the Navigator Interface
[SecureContext ]partial interface Navigator { [SameObject ]readonly attribute Bluetooth bluetooth ; };
Each
Navigator
has
an
associated
Bluetooth
,
which
is
a
Bluetooth
object.
Upon
creation
of
the
Navigator
object,
its
associated
Bluetooth
must
be
set
to
a
new
Bluetooth
object
created
in
the
Navigator
object’s
relevant
realm
.
Navigator
’s
bluetooth
getter
steps
are
to
return
this
’s
associated
Bluetooth
.
11. Integrations
11.1. Permissions Policy
This
specification
defines
a
policy-controlled
feature
,
identified
by
the
token
"
bluetooth
",
that
controls
whether
the
methods
exposed
by
the
bluetooth
attribute
on
the
Navigator
object
may
be
used.
The
default
allowlist
for
this
feature
is
["self"]
.
12. Automated testing
For the purposes of user-agent automation and application testing, this document defines extensions to the [WebDriver-BiDi] specification.
The Web Bluetooth API and its extension specifications pose a challenge to test authors, as fully exercising those interfaces requires physical hardware devices that respond in predictable ways. To address this challenge this document defines a number of WebDriver-BiDi extension commands that allow defining and controlling simulated peripherals and advertisements that behave like physical device peripherals and their advertisements. These simulated peripherals and advertisements represent devices with particular properties and whose readings can be entirely defined by users.
Each top-level traversable may have a simulated Bluetooth adapter , that is a software defined Bluetooth adapter that has a set of discovered simulated Bluetooth devices and can assume roles like Central .
Each
simulated
Bluetooth
adapter
has
a
simulated
Bluetooth
device
mapping
,
which
is
an
ordered
map
of
Bluetooth
address
strings
to
simulated
Bluetooth
devices
.
Each simulated Bluetooth adapter has an adapter state that is a string enumeration describing the current state of the adapter. The possible enumeration values are:
-
"powered-on"
-
"powered-off"
-
"absent"
Each simulated Bluetooth adapter has a low-energy supported state that is a boolean describing if the adapter supports Bluetooth Low Energy.
A simulated Bluetooth device is a software defined Bluetooth device that behaves like a physical device, may be attached to a simulated Bluetooth adapter , may have associated properties like Manufacturer Specific Data and Service UUIDs , and has a simulated GATT service mapping , which is an ordered map of Bluetooth UUID strings to simulated GATT services .
A simulated GATT service is a software defined Service that belongs to a simulated Bluetooth device , has a property of UUID , is known-present in the Bluetooth cache . and has a simulated GATT characteristic mapping , which is an ordered map of Bluetooth UUID strings to simulated GATT characteristics .
A simulated GATT characteristic is a software defined Characteristic that belongs to a simulated GATT service , has a property of UUID , a property of Characteristic Properties , and is known-present in the Bluetooth cache .
Simulated GATT characteristic properties are software defined Characteristic Properties that belong to a simulated GATT characteristic and are known-present in the Bluetooth cache .
CDDL snippetes use the "text" type instead of "browsingContext.BrowsingContext" to allow indepedent programmatic processing of CDDL snippets. Currently, other modules cannot be referenced.
12.1. Definitions
bluetooth.BluetoothUuid= text;bluetooth.BluetoothManufacturerData= {key: uint,data: tstr };bluetooth.CharacteristicProperties= { ?broadcast: bool, ?read: bool, ?writeWithoutResponse: bool, ?write: bool, ?notify: bool, ?indicate: bool, ?authenticatedSignedWrites: bool, ?extendedProperties: bool }
-
key - is the Company Identifier Code.
-
data - is the manufacturer data byte sequence , base64 encoded.
12.2. The bluetooth module
The bluetooth module contains commands for managing the remote end Bluetooth behavior.
12.2.1. Types
12.2.1.1. The bluetooth.RequestDevice Type
bluetooth.RequestDevice = text
A bluetooth.RequestDevice is an identifier for a single device in a request device prompt.
A
device
prompt
is
a
tuple
consisting
of
a
device
prompt
id
(a
string)
and
a
set
of
devices
which
is
a
set
of
BluetoothDevice
objects.
It
represents
a
prompt
which
allows
a
user
to
choose
a
Bluetooth
device
.
12.2.1.2. The bluetooth.RequestDeviceInfo Type
bluetooth.RequestDeviceInfo = { id : bluetooth.RequestDevice , name : text/ null, }
A bluetooth.RequestDeviceInfo represents a single device in a request device prompt.
BluetoothDevice
device
:
12.2.1.3. The bluetooth.RequestDevicePrompt Type
bluetooth.RequestDevicePrompt = text
A bluetooth.RequestDevicePrompt is an identifier for a single prompt.
A remote end has a map of navigables to device prompts which is a map whose keys are navigable ids and values are device prompts .
-
Let promptMap be the map of navigables to device prompts .
-
If promptMap [ navigableId ] does not exist :
-
Return error with error code no such prompt .
-
-
Let prompt be map of navigables to device prompts [ navigableId ].
-
If prompt ’s device prompt id is not promptId :
-
Return error with error code no such prompt .
-
-
Return success with data prompt .
-
For each device in prompt ’s set of devices :
-
Otherwise:
-
Return error with error code no such device .
-
-
Let devices be an empty list .
-
For each device in prompt ’s set of devices .
-
Append the result of serializing device to devices .
-
-
Return devices .
12.2.1.4. The bluetooth.ScanRecord Type
bluetooth.ScanRecord = { ? name : text, ? uuids : [ * bluetooth.BluetoothUuid ], ? appearance : number, ? manufacturerData : [ * bluetooth.BluetoothManufacturerData ], }
A
bluetooth.ScanRecord
represents
data
of
the
advertisement
packet
sent
by
a
Bluetooth
device
.
-
name - is the Bluetooth device ’s local name, or a prefix of it.
-
uuids - lists the Service UUIDs that this scan record says the Bluetooth device ’s GATT server supports.
-
appearance -
is
an
Appearance
,
one
of
the
values
defined
by
the
gap.appearancecharacteristic. -
manufacturerData -
list
of
BluetoothManufacturerDatathat mapsunsigned shortCompany Identifier Codes to base64 encoded manufacturer data byte sequences .
12.2.2. Errors
This specification extends the set of error codes from WebDriver BiDi with the following additional codes:
- no such device
-
Tried
to
reference
an
unknown
BluetoothDevice. - no such prompt
- Tried to reference an unknown device prompt .
12.2.3. Commands
BluetoothCommand = ( bluetooth.HandleRequestDevicePrompt // bluetooth.SimulateAdapter // bluetooth.DisableSimulation // bluetooth.SimulatePreconnectedPeripheral // bluetooth.SimulateAdvertisement // bluetooth.SimulateGattConnectionResponse // bluetooth.SimulateGattDisconnection // bluetooth.SimulateService // bluetooth.SimulateCharacteristic // bluetooth.SimulateCharacteristicResponse // bluetooth.SimulateDescriptor // bluetooth.SimulateDescriptorResponse // )
12.2.3.1. The bluetooth.handleRequestDevicePrompt Command
bluetooth.HandleRequestDevicePrompt = ( method : "bluetooth.handleRequestDevicePrompt" , params : bluetooth.HandleRequestDevicePromptParameters , ) bluetooth.HandleRequestDevicePromptParameters = { context : text, prompt : bluetooth.RequestDevicePrompt , ( bluetooth.HandleRequestDevicePromptAcceptParameters // bluetooth.HandleRequestDevicePromptCancelParameters ) } bluetooth.HandleRequestDevicePromptAcceptParameters = ( accept : true, device : bluetooth.RequestDevice , ) bluetooth.HandleRequestDevicePromptCancelParameters = ( accept : false, )
-
Let contextId be params [
"context"]. -
Let promptId be params [
"prompt"]. -
Let prompt be the result of trying to get a prompt with contextId and promptId .
-
Let accept be the value of the
acceptfield of command parameters . -
If accept is true:
-
Let deviceId be the value of the
devicefield of command parameters . -
Let device be the result of trying to match a device in prompt given prompt and deviceId .
-
Acknowledge prompt with device .
-
-
Otherwise:
-
Dismiss prompt .
-
-
Return success with data
null.
{ "method" : "bluetooth.handleRequestDevicePrompt" , "params" : { "context" : "cxt-d03fdd81" , "prompt" : "pmt-e0a234b" , "accept" : true , "device" : "dvc-9b3b872" } }
12.2.3.2. The bluetooth.simulateAdapter Command
bluetooth.SimulateAdapter = ( method : "bluetooth.simulateAdapter" , params : bluetooth.SimulateAdapterParameters , ) bluetooth.SimulateAdapterParameters = { context : text, ? leSupported : bool, state : "absent" / "powered-off" / "powered-on" }
-
Let contextId be params [
"context"]. -
Let navigable be the result of trying to get a navigable with contextId .
-
If navigable is not a top-level traversable , return error with error code invalid argument .
-
Let simulatedBluetoothAdapter be navigable ’s simulated Bluetooth adapter .
-
If simulatedBluetoothAdapter is empty, run the following steps:
-
If params [
"leSupported"] does not exist , set params ["leSupported"] totrue. -
Let simulatedBluetoothAdapter be a new simulated Bluetooth adapter .
-
Set simulatedBluetoothAdapter ’s LE supported state to params [
"leSupported"]. -
Set simulatedBluetoothAdapter ’s adapter state to params [
"state"]. -
Set navigable ’s simulated Bluetooth adapter to simulatedBluetoothAdapter .
-
Return success with data
null.
-
-
If simulatedBluetoothAdapter is not empty, run the following steps:
-
If params [
"leSupported"] exists , return error with error code invalid argument . -
Set simulatedBluetoothAdapter ’s adapter state to params [
"state"]. -
Return success with data
null.
-
{ "method" : "bluetooth.simulateAdapter" , "params" : { "context" : "cxt-d03fdd81" , "leSupported" : true , "state" : "powered-on" , } }
{ "method" : "bluetooth.simulateAdapter" , "params" : { "context" : "cxt-d03fdd81" , "state" : "powered-off" , } }
12.2.3.3. The bluetooth.disableSimulation Command
bluetooth.DisableSimulation = ( method : "bluetooth.disableSimulation" , params : bluetooth.DisableSimulationParameters , ) bluetooth.DisableSimulationParameters = { context : text}
-
Let contextId be params [
"context"]. -
Let navigable be the result of trying to get a navigable with contextId .
-
If navigable is not a top-level traversable , return error with error code invalid argument .
-
Set navigable ’s simulated Bluetooth adapter to empty.
-
Return success with data
null.
{ "method" : "bluetooth.disableSimulation" , "params" : { "context" : "cxt-d03fdd81" } }
12.2.3.4. The bluetooth.simulatePreconnectedPeripheral Command
bluetooth.SimulatePreconnectedPeripheral = ( method : "bluetooth.simulatePreconnectedPeripheral" , params : bluetooth.SimulatePreconnectedPeripheralParameters , ) bluetooth.SimulatePreconnectedPeripheralParameters = { context : text, address : text, name : text, manufacturerData : [ * bluetooth.BluetoothManufacturerData ], knownServiceUuids : [ * bluetooth.BluetoothUuid ] }
-
Let contextId be params["context"].
-
Let navigable be the result of trying to get a navigable with contextId .
-
If navigable is not a top-level traversable , return error with error code invalid argument .
-
Let simulatedBluetoothAdapter be navigable ’s simulated Bluetooth adapter .
-
If simulatedBluetoothAdapter is empty, return error with error code invalid argument .
-
Let deviceAddress be params [
"address"]. -
Let deviceMapping be simulatedBluetoothAdapter ’s simulated Bluetooth device mapping .
-
If deviceMapping [ deviceAddress ] exists , return error with error code invalid argument .
-
Let simulatedBluetoothDevice be a new simulated Bluetooth device .
-
Set simulatedBluetoothDevice ’s name to params [
"name"]. -
Set simulatedBluetoothDevice ’s address to params [
"address"]. -
Set simulatedBluetoothDevice ’s manufacturer specific data to the output of forgiving-base64 decode performed on params [
"manufacturerData"]. -
Set simulatedBluetoothDevice ’s service UUIDs to params [
"knownServiceUuids"]. -
Set deviceMapping [ deviceAddress ] to simulatedBluetoothDevice .
-
Return success with data
null.
{ "method" : "bluetooth.simulatePreconnectedPeripheral" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "name" : "Some Device" , "manufacturerData" : [ { key: 17 , data : "AP8BAX8=" } ], "knownServiceUuids" : [ "12345678-1234-5678-9abc-def123456789" , ], } }
12.2.3.5. The bluetooth.simulateAdvertisement Command
bluetooth.SimulateAdvertisement = ( method : "bluetooth.simulateAdvertisement" , params : bluetooth.SimulateAdvertisementParameters , ) bluetooth.SimulateAdvertisementParameters = { context : text, scanEntry : bluetooth.SimulateAdvertisementScanEntryParameters } bluetooth.SimulateAdvertisementScanEntryParameters = { deviceAddress : text, rssi : number, scanRecord : bluetooth.ScanRecord }
-
Let contextId be params [
"context"]. -
Let topLevelNavigable be the result of trying to get a navigable with contextId .
-
If topLevelNavigable is not a top-level traversable , return error with error code invalid argument .
-
Let scanEntry be params [
"scanEntry"]. -
Let deviceAddress be scanEntry [
"deviceAddress"]. -
Let simulatedBluetoothAdapter be topLevelNavigable ’s simulated Bluetooth adapter .
-
If simulatedBluetoothAdapter is empty, return error with error code invalid argument .
-
Let deviceMapping be simulatedBluetoothAdapter ’s simulated Bluetooth device mapping .
-
If deviceMapping [ deviceAddress ] exists , let simulatedDevice be deviceMapping [ deviceAddress ]. Otherwise, let simulatedDevice be a new simulated Bluetooth device with deviceAddress and set deviceMapping [ deviceAddress ] to simulatedDevice .
-
If topLevelNavigable is currently executing the scan for devices algorithm, insert simulatedDevice into the simulatedBluetoothDevices variable within that algorithm.
Inserting data into variables from another algorithm is not well defined. The scan for devices algorithm needs to define asynchronous device discovery in order to match implementations.
-
Let navigables be the inclusive descendant navigables of topLevelNavigable ’s active document .
-
For each navigable of navigables :
-
Let document be navigable ’s active document .
-
Queue a task on document ’s relevant settings object ’s responsible event loop to do the following sub-steps:
-
Let simulatedDeviceInstance be the result of get the
BluetoothDevicerepresenting simulatedDevice inside navigable ’s active window ’s associatedNavigator’s associated Bluetooth . -
If simulatedDeviceInstance .
[[watchAdvertisementsState]]isnot-watching, abort these sub-steps. -
Fire an
advertisementreceivedevent for the advertising event represented by scanEntry ["scanRecord"], at simulatedDeviceInstance .
-
-
-
Return success with data
null.
{ "method" : "bluetooth.simulateAdvertisement" , "params" : { "context" : "cxt-d03fdd81" , "scanEntry" : { "deviceAddress" : "08:08:08:08:08:08" , "rssi" : -10 , "scanRecord" : { "name" : "Heart Rate" , "uuids" : [ "0000180d-0000-1000-8000-00805f9b34fb" ], "manufacturerData" : [ { key: 17 , data : "AP8BAX8=" } ], "appearance" : 1 , "txPower" : 1 } } } }
12.2.3.6. The bluetooth.simulateGattConnectionResponse Command
bluetooth.SimulateGattConnectionResponse = ( method : "bluetooth.simulateGattConnectionResponse" , params : bluetooth.SimulateGattConnectionResponseParameters , ) bluetooth.SimulateGattConnectionResponseParameters = { context : text, address : text, code : uint}
-
Let contextId be params [
"context"]. -
Let navigable be the result of trying to get a navigable with contextId .
-
Let deviceAddress be params [
"address"]. -
Let simulatedBluetoothAdapter be navigable ’s simulated Bluetooth adapter .
-
If simulatedBluetoothAdapter is empty, return error with error code invalid argument .
-
Let deviceMapping be simulatedBluetoothAdapter ’s simulated Bluetooth device mapping .
-
If deviceMapping [ deviceAddress ] exists , let simulatedDevice be deviceMapping [ deviceAddress ]. Otherwise, return error with error code invalid argument .
-
Let simulatedDeviceInstance be the result of get the
BluetoothDevicerepresenting simulatedDevice inside navigable ’s active window ’s associatedNavigator’s associated Bluetooth . -
If simulatedDeviceInstance .
[[gatt]].[[automatedGATTConnectionResponse]]is"expected", set simulatedDeviceInstance .[[gatt]].[[automatedGATTConnectionResponse]]to params ["code"]. -
Otherwise, return error with error code invalid element state .
0x00
according
to
List
of
Error
Codes
)
by
sending
the
following
message:
{ "method" : "bluetooth.simulateGattConnectionResponse" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "code" : 0 } }
12.2.3.7. The bluetooth.simulateGattDisconnection Command
bluetooth.SimulateGattDisconnection = ( method : "bluetooth.simulateGattDisconnection" , params : bluetooth.SimulateGattDisconnectionParameters , ) bluetooth.SimulateGattDisconnectionParameters = { context : text, address : text, }
-
Let contextId be params [
"context"]. -
Let navigable be the result of trying to get a navigable with contextId .
-
Let deviceAddress be params [
"address"]. -
Let simulatedBluetoothAdapter be navigable ’s simulated Bluetooth adapter .
-
If simulatedBluetoothAdapter is empty, return error with error code invalid argument .
-
Let deviceMapping be simulatedBluetoothAdapter ’s simulated Bluetooth device mapping .
-
If deviceMapping [ deviceAddress ] exists , let simulatedDevice be deviceMapping [ deviceAddress ]. Otherwise, return error with error code invalid argument .
-
Let simulatedDeviceInstance be the result of get the
BluetoothDevicerepresenting simulatedDevice inside navigable ’s active window ’s associatedNavigator’s associated Bluetooth . -
If simulatedDeviceInstance .
[[gatt]].[[automatedGATTConnectionResponse]]is"expected", set simulatedDeviceInstance .[[gatt]].[[automatedGATTConnectionResponse]]to0x15.0x15represents"Remote Device Terminated Connection due to Power Off"according to the List of Error Codes . This simulates a scenario where the Bluetooth device is not able to respond to a GATT connection attempt. -
Otherwise, clean up the disconnected device simulatedDeviceInstance .
{ "method" : "bluetooth.simulateGattDisconnection" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , } }
12.2.3.8. The bluetooth.simulateService Command
bluetooth.SimulateService = ( method : "bluetooth.simulateService" , params : bluetooth.SimulateServiceParameters , ) bluetooth.SimulateServiceParameters = { context : text, address : text, uuid : bluetooth.BluetoothUuid , type : "add" / "remove" , }
-
Let contextId be params [
"context"]. -
Let navigable be the result of trying to get a navigable with contextId .
-
Let deviceAddress be params [
"address"]. -
Let simulatedBluetoothAdapter be navigable ’s simulated Bluetooth adapter .
-
If simulatedBluetoothAdapter is empty, return error with error code invalid argument .
-
Let deviceMapping be simulatedBluetoothAdapter ’s simulated Bluetooth device mapping .
-
If deviceMapping [ deviceAddress ] exists , let simulatedDevice be deviceMapping [ deviceAddress ].
-
Otherwise, return error with error code invalid argument .
-
Let simulatedDeviceInstance be the result of get the
BluetoothDevicerepresenting simulatedDevice inside navigable ’s active window ’s associatedNavigator’s associated Bluetooth . -
Let serviceMapping be simulatedDevice ’s simulated GATT service mapping .
-
Let uuid be params [
"uuid"]. -
If params [
"type"] is"add":-
If serviceMapping [ uuid ] exists , return error with error code invalid element state .
-
Let simulatedGattService be a new simulated GATT service .
-
Set simulatedGattService ’s UUID to uuid .
-
Set serviceMapping [ uuid ] to simulatedGattService .
-
Create a
BluetoothRemoteGATTServicerepresenting simulatedGattService and add a mapping from simulatedGattService to the resultingPromisein simulatedDeviceInstance .[[context]].[[attributeInstanceMap]]. -
Return success with data
null.
-
-
Else if params [
"type"] is"remove":-
If serviceMapping [ uuid ] exists , let simulatedGattService be serviceMapping [ uuid ].
-
Otherwise, return error with error code invalid element state .
-
Remove simulatedGattService from simulatedDeviceInstance .
[[context]].[[attributeInstanceMap]]. -
Remove uuid from serviceMapping .
-
Return success with data
null.
-
-
Return error with error code invalid argument .
{ "method" : "bluetooth.simulateService" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "uuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "type" : "add" } }
{ "method" : "bluetooth.simulateService" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "uuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "type" : "remove" } }
12.2.3.9. The bluetooth.simulateCharacteristic Command
bluetooth.SimulateCharacteristic = ( method : "bluetooth.simulateCharacteristic" , params : bluetooth.SimulateCharacteristicParameters , ) bluetooth.SimulateCharacteristicParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , ? characteristicProperties : bluetooth.CharacteristicProperties , type : "add" / "remove" }
-
Let contextId be params [
"context"]. -
Let navigable be the result of trying to get a navigable with contextId .
-
Let deviceAddress be params [
"address"]. -
Let simulatedBluetoothAdapter be navigable ’s simulated Bluetooth adapter .
-
If simulatedBluetoothAdapter is empty, return error with error code invalid argument .
-
Let deviceMapping be simulatedBluetoothAdapter ’s simulated Bluetooth device mapping .
-
If deviceMapping [ deviceAddress ] exists , let simulatedDevice be deviceMapping [ deviceAddress ].
-
Otherwise, return error with error code invalid argument .
-
Let simulatedDeviceInstance be the result of get the
BluetoothDevicerepresenting simulatedDevice inside navigable ’s active window ’s associatedNavigator’s associated Bluetooth . -
Let serviceMapping be simulatedDevice ’s simulated GATT service mapping .
-
Let serviceUuid be params [
"serviceUuid"]. -
If serviceMapping [ serviceUuid ] exists , let simulatedService be serviceMapping [ serviceUuid ].
-
Otherwise, return error with error code invalid argument .
-
Let characteristicMapping be simulatedService ’s simulated GATT characteristic mapping .
-
Let characteristicUuid be params [
"characteristicUuid"]. -
If params [
"type"] is"add":-
If characteristicMapping [ characteristicUuid ] exists , return error with error code invalid element state .
-
If params [
"characteristicProperties"] does not exist , return error with error code invalid argument . -
Let simulatedGattCharacteristicProperties be new simulated GATT characteristic properties and run the following steps:
-
Let properties be params [
"characteristicProperties"]. -
If properties [
"broadcast"] exists , set simulatedGattCharacteristicProperties ’sBroadcastbit if properties ["broadcast"] istrue. -
If properties [
"read"] exists , set simulatedGattCharacteristicProperties ’sReadbit if properties ["read"] istrue. -
If properties [
"writeWithoutResponse"] exists , set simulatedGattCharacteristicProperties ’sWrite Without Responsebit if properties ["writeWithoutResponse"] istrue. -
If properties [
"write"] exists , set simulatedGattCharacteristicProperties ’sWritebit if properties ["write"] istrue. -
If properties [
"notify"] exists , set simulatedGattCharacteristicProperties ’sNotifybit if properties ["notify"] istrue. -
If properties [
"indicate"] exists , set simulatedGattCharacteristicProperties ’sIndicatebit if properties ["indicate"] istrue. -
If properties [
"authenticatedSignedWrites"] exists , set simulatedGattCharacteristicProperties ’sAuthenticated Signed Writesbit if properties ["authenticatedSignedWrites"] istrue. -
If properties [
"extendedProperties"] exists , set simulatedGattCharacteristicProperties ’sExtended Propertiesbit if properties ["extendedProperties"] istrue.
-
-
Let simulatedGattCharacteristic be a new simulated GATT characteristic .
-
Set simulatedGattCharacteristic ’s UUID to characteristicUuid .
-
Set simulatedGattCharacteristic ’s Characteristic Properties to simulatedGattCharacteristicProperties .
-
Set characteristicMapping [ characteristicUuid ] to simulatedGattCharacteristic .
-
Create a
BluetoothRemoteGATTCharacteristicrepresenting simulatedGattCharacteristic and add a mapping from simulatedGattCharacteristic to the resultingPromisein simulatedDeviceInstance .[[context]].[[attributeInstanceMap]]. -
Return success with data
null.
-
-
Else if params [
"type"] is"remove":-
If params [
"characteristicProperties"] exists , return error with error code invalid argument . -
If characteristicMapping [ characteristicUuid ] exists , let simulatedGattCharacteristic be characteristicMapping [ characteristicUuid ].
-
Otherwise, return error with error code invalid element state .
-
Remove simulatedGattCharacteristic from simulatedDeviceInstance .
[[context]].[[attributeInstanceMap]]. -
Remove characteristicUuid from characteristicMapping .
-
Return success with data
null.
-
-
Return error with error code invalid argument .
{ "method" : "bluetooth.simulateCharacteristic" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "characteristicProperties" : { "read" : true , "write" : true , "notify" : true }, "type" : "add" } }
{ "method" : "bluetooth.simulateCharacteristic" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "type" : "remove" } }
12.2.3.10. The bluetooth.simulateCharacteristicResponse Command
bluetooth.SimulateCharacteristicResponse = ( method : "bluetooth.simulateCharacteristicResponse" , params : bluetooth.SimulateCharacteristicResponseParameters , ) bluetooth.SimulateCharacteristicResponseParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , type : "read" / "write" / "subscribe-to-notifications" / "unsubscribe-from-notifications" , code : uint, ? data : [ * uint] }
Let contextId be params [
"context"].Let navigable be the result of trying to get a navigable with contextId .
Let deviceAddress be params [
"address"].Let simulatedBluetoothAdapter be navigable ’s simulated Bluetooth adapter .
If simulatedBluetoothAdapter is empty, return error with error code invalid argument .
Let deviceMapping be simulatedBluetoothAdapter ’s simulated Bluetooth device mapping .
If deviceMapping [ deviceAddress ] exists , let simulatedDevice be deviceMapping [ deviceAddress ]. Otherwise, return error with error code invalid argument .
Let serviceMapping be simulatedDevice ’s simulated GATT service mapping .
Let serviceUuid be params [
"serviceUuid"].If serviceMapping [ serviceUuid ] exists , let simulatedService be serviceMapping [ serviceUuid ].
Otherwise, return error with error code invalid argument .
Let characteristicMapping be simulatedService ’s simulated GATT characteristic mapping .
Let characteristicUuid be params [
"characteristicUuid"].If characteristicMapping [ characteristicUuid ] exists , let simulatedGattCharacteristic be characteristicMapping [ characteristicUuid ].
Otherwise, return error with error code invalid element state .
Let simulatedDeviceInstance be the result of get the
BluetoothDevicerepresenting simulatedDevice inside navigable ’s active window ’s associatedNavigator’s associated Bluetooth .Let promise be simulatedDeviceInstance .
[[context]].TODO: Finish[[attributeInstanceMap]][ simulatedGattCharacteristic ].Upon fulfillment of promise with characteristic , run the
algorithmfollowing steps:If params [
"type"] isread, run the following steps:If characteristic .
[[automatedCharacteristicReadResponse]]isexpected, set characteristic .[[automatedCharacteristicReadResponse]]to params ["code"] and characteristic .[[automatedCharacteristicReadResponseData]]to a copy ofbluetooth.simulateCharacteristicResponse.the bytes held by params ["data"].Otherwise, return error with error code invalid element state .
If params [
"type"] iswrite, run the following steps:If characteristic .
[[automatedCharacteristicWriteResponse]]isexpected, set characteristic .[[automatedCharacteristicWriteResponse]]to params ["code"].Otherwise, return error with error code invalid element state .
If params [
"type"] issubscribe-to-notifications, run the following steps:-
If characteristic .
[[automatedCharacteristicSubscribeToNotificationsResponse]]isexpected, set characteristic .[[automatedCharacteristicSubscribeToNotificationsResponse]]to params ["code"]. Otherwise, return error with error code invalid element state .
-
If params [
"type"] isunsubscribe-from-notifications, run the following steps:If characteristic .
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]isexpected, set characteristic .[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]to params ["code"].Otherwise, return error with error code invalid element state .
Otherwise, return error with error code invalid argument .
0x00
according
to
Error
Response
)
with
data
for
a
characteristic
read
operation
by
sending
the
following
message:
{ "method" : "bluetooth.simulateCharacteristicResponse" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "type" : "read" , "code" : 0 , "data" : [ 1 , 2 ] } }
12.2.3.11. The bluetooth.simulateDescriptor Command
bluetooth.SimulateDescriptor = ( method : "bluetooth.simulateDescriptor" , params : bluetooth.SimulateDescriptorParameters , ) bluetooth.SimulateDescriptorParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , descriptorUuid : bluetooth.BluetoothUuid , type : "add" / "remove" }
{ "method" : "bluetooth.simulateDescriptor" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "descriptorUuid" : "00002901-0000-1000-8000-00805f9b34fb" , "type" : "add" } }
{ "method" : "bluetooth.simulateDescriptor" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "descriptorUuid" : "00002901-0000-1000-8000-00805f9b34fb" , "type" : "remove" } }
12.2.3.12. The bluetooth.simulateDescriptorResponse Command
bluetooth.SimulateDescriptorResponse = ( method : "bluetooth.simulateDescriptorResponse" , params : bluetooth.SimulateDescriptorResponseParameters , ) bluetooth.SimulateDescriptorResponseParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , descriptorUuid : bluetooth.BluetoothUuid , type : "read" / "write" , code : uint, ? data : [ * uint] }
0x00
according
to
Error
Response
)
with
data
for
a
descriptor
read
operation
by
sending
the
following
message:
{ "method" : "bluetooth.simulateDescriptorResponse" , "params" : { "context" : "cxt-d03fdd81" , "address" : "09:09:09:09:09:09" , "serviceUuid" : "0000180d-0000-1000-8000-00805f9b34fb" , "characteristicUuid" : "00002a21-0000-1000-8000-00805f9b34fb" , "descriptorUuid" : "00002901-0000-1000-8000-00805f9b34fb" , "type" : "read" , "code" : 0 , "data" : [ 1 , 2 ] } }
12.2.4. Events
BluetoothEvent = ( bluetooth.RequestDevicePromptUpdated // bluetooth.GattConnectionAttempted )
12.2.4.1. The bluetooth.requestDevicePromptUpdated Event
bluetooth.RequestDevicePromptUpdated = ( method : "bluetooth.requestDevicePromptUpdated" , params : bluetooth.RequestDevicePromptUpdatedParameters ) bluetooth.RequestDevicePromptUpdatedParameters = { context : text, prompt : bluetooth.RequestDevicePrompt , devices : [ * bluetooth.RequestDeviceInfo ], }
-
Let navigableId be navigable ’s navigable id .
-
Let prompt be the device prompt ( promptId , devices ).
-
Let serialized devices be the result of serialize prompt devices with prompt .
-
Set map of navigables to device prompts [ navigableId ] to prompt .
-
Let params be a map matching the
bluetooth.RequestDevicePromptUpdatedParametersproduction with thecontextfield set to navigableId , thepromptfield set to promptId , and thedevicesfield set to serialized devices . -
Let body be a map matching the
bluetooth.RequestDevicePromptUpdatedproduction, with theparamsfield set to params . -
Let relatedNavigables be a set containing navigable .
-
For each session in the set of sessions for which an event is enabled given "
bluetooth.requestDevicePromptUpdated" and relatedNavigables :-
Emit an event with session and body .
-
12.2.4.2. The bluetooth.gattConnectionAttempted Event
bluetooth.GattConnectionAttempted = ( method : "bluetooth.gattConnectionAttempted" , params : bluetooth.GattConnectionAttemptedParameters ) bluetooth.GattConnectionAttemptedParameters = { context : text, address : text}
BluetoothDevice
device
:
-
Let navigableId be navigable ’s navigable id .
-
Let params be a map matching the
bluetooth.GattConnectionAttemptedParametersproduction with thecontextfield set to navigableId and theaddressfield set to device .[[representedDevice]]’s address. -
Let body be a map matching the
bluetooth.GattConnectionAttemptedproduction, with theparamsfield set to params . -
Let relatedNavigables be a set containing navigable .
-
For each session in the set of sessions for which an event is enabled given "
bluetooth.gattEventGenerated" and relatedNavigables :-
Emit an event with session and body .
-
12.2.4.3. The bluetooth.characteristicEventGenerated Event
bluetooth.CharacteristicEventGenerated = ( method : "bluetooth.characteristicEventGenerated" , params : bluetooth.CharacteristicEventGeneratedParameters ) bluetooth.CharacteristicEventGeneratedParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , type : "read" / "write-with-response" / "write-without-response" / "subscribe-to-notifications" / "unsubscribe-from-notifications" , ? data : [ * uint] }
To
trigger
a
simulated
characteristic
event
given
a
navigable
navigable
,
a
BluetoothDevice
device
,
a
simulated
GATT
characteristic
TODO:
Finish
characteristic
,
string
type
,
and
an
optional
byte
sequence
bytes
:
Let navigableId be navigable ’s navigable id .
Let params be a map matching the
algorithmbluetooth.CharacteristicEventGeneratedParametersproduction and run the following steps:Set params [
"context"] to navigableId .Set params [
"address"] to device .[[representedDevice]]’s address.Let service be the simulated GATT service containing characteristic .
Set params [
"serviceUuid"] to service ’s UUID .Set params [
"characteristicUuid"] to characteristic ’s UUID .Set params [
"type"] to type .If type is
write, set params ["data"] to a newUint8Arraywrapping a newArrayBuffercontaining bytes .
Let body be a map matching the
bluetooth.CharacteristicEventGeneratedproduction, with theparamsfield set to params .Let relatedNavigables be a set containing navigable .
For each session in the set of
bluetooth.characteristicEventGenerated.sessions for which an event is enabled given "bluetooth.characteristicEventGenerated" and relatedNavigables :-
Emit an event with session and body .
-
12.2.4.4. The bluetooth.descriptorEventGenerated Event
bluetooth.DescriptorEventGenerated = ( method : "bluetooth.descriptorEventGenerated" , params : bluetooth.DescriptorEventGeneratedParameters ) bluetooth.DescriptorEventGeneratedParameters = { context : text, address : text, serviceUuid : bluetooth.BluetoothUuid , characteristicUuid : bluetooth.BluetoothUuid , descriptorUuid : bluetooth.BluetoothUuid , type : "read" / "write" , ? data : [ * uint] }
13. Terminology and Conventions
This specification uses a few conventions and several terms from other specifications. This section lists those and links to their primary definitions.
When
an
algorithm
in
this
specification
uses
a
name
defined
in
this
or
another
specification,
the
name
MUST
resolve
to
its
initial
value,
ignoring
any
changes
that
have
been
made
to
the
name
in
the
current
execution
environment.
For
example,
when
the
requestDevice()
algorithm
says
to
call
,
this
MUST
apply
the
Array.prototype.map
.call(
filter
.services,
BluetoothUUID.getService
)
Array.prototype.map
algorithm
defined
in
[ECMAScript]
with
filter
.services
as
its
this
parameter
and
the
algorithm
defined
in
§ 7.1
Standardized
UUIDs
for
BluetoothUUID.getService
as
its
callbackfn
parameter,
regardless
of
any
modifications
that
have
been
made
to
window
,
Array
,
Array.prototype
,
Array.prototype.map
,
Function
,
Function.prototype
,
BluetoothUUID
,
BluetoothUUID.getService
,
or
other
objects.
This
specification
uses
a
read-only
type
that
is
similar
to
WebIDL’s
FrozenArray
.
-
A read only ArrayBuffer has
ArrayBuffer’s values and interface, except that attempting to write to its contents or transfer it has the same effect as trying to write to aFrozenArray’s contents. This applies toTypedArrays andDataViews wrapped around theArrayBuffertoo.
- [BLUETOOTH42]
-
-
Architecture
&
Terminology
Overview
-
General
Description
- Overview of Bluetooth Low Energy Operation (defines advertising events )
-
Communication
Topology
and
Operation
-
Operational
Procedures
and
Modes
-
BR/EDR
Procedures
-
Inquiry
(Discovering)
Procedure
- Extended Inquiry Response
-
Inquiry
(Discovering)
Procedure
-
BR/EDR
Procedures
-
Operational
Procedures
and
Modes
-
General
Description
-
Core
System
Package
[BR/EDR
Controller
volume]
-
Error
Codes
-
Overview
of
Error
Codes
- List of Error Codes
-
Overview
of
Error
Codes
-
Host
Controller
Interface
Functional
Specification
-
HCI
Commands
and
Events
-
Informational
Parameters
- Read BD_ADDR Command
-
Status
Parameters
- Read RSSI Command
-
Informational
Parameters
-
HCI
Commands
and
Events
-
Error
Codes
-
Core
System
Package
[Host
volume]
-
Service
Discovery
Protocol
(SDP)
Specification
-
Overview
-
Searching
for
Services
- UUID (defines UUID alias es and the algorithm to compute the 128-bit UUID represented by a UUID alias)
-
Searching
for
Services
-
Overview
-
Generic
Access
Profile
-
Profile
Overview
-
Profile
Roles
-
Roles
when
Operating
over
an
LE
Physical
Transport
- Broadcaster Role
- Observer Role
- Peripheral Role
- Central Role
-
Roles
when
Operating
over
an
LE
Physical
Transport
-
Profile
Roles
-
User
Interface
Aspects
-
Representation
of
Bluetooth
Parameters
- Bluetooth Device Name (the user-friendly name)
-
Representation
of
Bluetooth
Parameters
-
Idle
Mode
Procedures
—
BR/EDR
Physical
Transport
- Device Discovery Procedure
- BR/EDR Bonding Procedure
-
Operational
Modes
and
Procedures
—
LE
Physical
Transport
-
Broadcast
Mode
and
Observation
Procedure
- Observation Procedure
-
Discovery
Modes
and
Procedures
- General Discovery Procedure
- Name Discovery Procedure
- Connection Modes and Procedures
-
Bonding
Modes
and
Procedures
- LE Bonding Procedure
-
Broadcast
Mode
and
Observation
Procedure
-
Security
Aspects
—
LE
Physical
Transport
- Privacy Feature
-
Random
Device
Address
- Static Address
-
Private
address
- Resolvable Private Address Resolution Procedure
- Advertising Data and Scan Response Data Format (defines AD structure )
-
Bluetooth
Device
Requirements
-
Bluetooth
Device
Address
(defines
BD_ADDR
)
-
Bluetooth
Device
Address
Types
- Public Bluetooth Address
-
Bluetooth
Device
Address
Types
-
Bluetooth
Device
Address
(defines
BD_ADDR
)
- Definitions (defines bond )
-
Profile
Overview
-
Attribute
Protocol
(ATT)
-
Protocol
Requirements
-
Basic
Concepts
- Attribute Type
- Attribute Handle
- Long Attribute Values
-
Attribute
Protocol
Pdus
-
Error
Handling
- Error Response
-
Error
Handling
-
Basic
Concepts
-
Protocol
Requirements
-
Generic
Attribute
Profile
(GATT)
-
Profile
Overview
- Configurations and Roles (defines GATT Client and GATT Server )
- Profile Fundamentals , defines the ATT Bearer
-
Attribute
Protocol
- Attribute Caching
-
GATT
Profile
Hierarchy
- Service
- Included Service s
- Characteristic
-
Service
Interoperability
Requirements
- Service Definition
-
Characteristic
Definition
-
Characteristic
Declaration
- Characteristic Properties
-
Characteristic
Descriptor
Declarations
- Characteristic Extended Properties
- Client Characteristic Configuration
-
Characteristic
Declaration
-
GATT
Feature
Requirements
—
defines
the
GATT
procedures
.
-
Server
Configuration
- Exchange MTU
-
Primary
Service
Discovery
- Discover All Primary Services
- Discover Primary Service by Service UUID
-
Relationship
Discovery
- Find Included Services
-
Characteristic
Discovery
- Discover All Characteristics of a Service
- Discover Characteristics by UUID
-
Characteristic
Descriptor
Discovery
- Discover All Characteristic Descriptors
- Characteristic Value Read
-
Characteristic
Value
Write
- Write Without Response
- Write Characteristic Value
- Characteristic Value Notification
- Characteristic Value Indications
-
Characteristic
Descriptors
- Read Characteristic Descriptors
- Read Long Characteristic Descriptors
- Write Characteristic Descriptors
- Write Long Characteristic Descriptors
- Procedure Timeouts
-
Server
Configuration
-
GAP
Interoperability
Requirements
-
BR/EDR
GAP
Interoperability
Requirements
- Connection Establishment
-
LE
GAP
Interoperability
Requirements
- Connection Establishment
-
BR/EDR
GAP
Interoperability
Requirements
-
Defined
Generic
Attribute
Profile
Service
- Service Changed
-
Profile
Overview
-
Security
Manager
Specification
-
Security
Manager
-
Security
in
Bluetooth
Low
Energy
- Definition of Keys and Values , defines the Identity Resolving Key ( IRK )
-
Security
in
Bluetooth
Low
Energy
-
Security
Manager
-
Service
Discovery
Protocol
(SDP)
Specification
-
Core
System
Package
[Low
Energy
Controller
volume]
-
Link
Layer
Specification
-
General
Description
-
Device
Address
- Public Device Address
-
Random
Device
Address
- Static Device Address
-
Device
Address
-
Air
Interface
Protocol
-
Non-Connected
States
-
Scanning
State
- Passive Scanning
-
Scanning
State
-
Non-Connected
States
-
General
Description
-
Link
Layer
Specification
-
Architecture
&
Terminology
Overview
- [BLUETOOTH-SUPPLEMENT6]
-
-
Data
Types
Specification
-
Data
Types
Definitions
and
Formats
- Service UUID Data Type
- Local Name Data Type
- Flags Data Type (defines the Discoverable Mode flags)
- Manufacturer Specific Data
- TX Power Level
- Service Data
- Appearance
-
Data
Types
Definitions
and
Formats
-
Data
Types
Specification