diff --git a/scanning.bs b/scanning.bs
new file mode 100644
index 0000000..10e2854
--- /dev/null
+++ b/scanning.bs
@@ -0,0 +1,1068 @@
+
+Title: Web Bluetooth Scanning
+Repository: WebBluetoothCG/web-bluetooth
+Status: CG-DRAFT
+ED: https://webbluetoothcg.github.io/web-bluetooth/scanning.html
+Shortname: web-bluetooth-scanning
+Level: 1
+Editor: See contributors on GitHub, , https://github.com/WebBluetoothCG/web-bluetooth/graphs/contributors
+Abstract: This document describes an API to scan for nearby Bluetooth Low Energy devices in real time.
+
+Group: web-bluetooth-cg
+!Participate: Join the W3C Community Group
+!Participate: Fix the text through GitHub
+!Participate: public-web-bluetooth@w3.org (archives )
+!Participate: IRC: #web-bluetooth on W3C's IRC
+
+Markup Shorthands: css no, markdown yes
+
+
+
+{
+ "BLUETOOTH42": {
+ "href": "https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439",
+ "title": "BLUETOOTH SPECIFICATION Version 4.2",
+ "publisher": "Bluetooth SIG",
+ "date": "2 December 2014"
+ },
+ "BLUETOOTH-GATT-REST": {
+ "href": "https://www.bluetooth.org/docman/handlers/downloaddoc.ashx?doc_id=285910",
+ "title": "GATT REST API",
+ "publisher": "Bluetooth Internet WG",
+ "date": "7 April 2014"
+ },
+ "BLUETOOTH-ASSIGNED": {
+ "href": "https://www.bluetooth.org/en-us/specification/assigned-numbers",
+ "title": "Assigned Numbers",
+ "status": "Living Standard",
+ "publisher": "Bluetooth SIG"
+ },
+ "BLUETOOTH-ASSIGNED-BASEBAND": {
+ "href": "https://www.bluetooth.org/en-us/specification/assigned-numbers/baseband",
+ "title": "Assigned Numbers for Baseband",
+ "status": "Living Standard",
+ "publisher": "Bluetooth SIG"
+ },
+ "BLUETOOTH-ASSIGNED-SERVICES": {
+ "href": "https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx",
+ "title": "Bluetooth GATT Specifications > Services",
+ "status": "Living Standard",
+ "publisher": "Bluetooth SIG"
+ },
+ "BLUETOOTH-ASSIGNED-CHARACTERISTICS": {
+ "href": "https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx",
+ "title": "Bluetooth GATT Specifications > Characteristics",
+ "status": "Living Standard",
+ "publisher": "Bluetooth SIG"
+ },
+ "BLUETOOTH-ASSIGNED-DESCRIPTORS": {
+ "href": "https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorsHomePage.aspx",
+ "title": "Bluetooth GATT Specifications > Descriptors",
+ "status": "Living Standard",
+ "publisher": "Bluetooth SIG"
+ },
+ "BLUETOOTH-SUPPLEMENT6": {
+ "href": "https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=302735",
+ "title": "Supplement to the Bluetooth Core Specification Version 6",
+ "date": "14 July 2015",
+ "publisher": "Bluetooth SIG"
+ }
+}
+
+
+
+spec: BLUETOOTH-ASSIGNED
+ type: enum; urlPrefix: https://developer.bluetooth.org/gatt/
+ urlPrefix: characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.
+ text: org.bluetooth.characteristic.body_sensor_location; url: body_sensor_location.xml#
+ text: org.bluetooth.characteristic.gap.appearance; url: gap.appearance.xml#
+ text: org.bluetooth.characteristic.heart_rate_control_point; url: heart_rate_control_point.xml#
+ text: org.bluetooth.characteristic.heart_rate_measurement; url: heart_rate_measurement.xml#
+ text: org.bluetooth.characteristic.ieee_11073-20601_regulatory_certification_data_list; url: ieee_11073-20601_regulatory_certification_data_list.xml#
+ text: org.bluetooth.characteristic.pnp_id; url: pnp_id.xml#
+ urlPrefix: descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.
+ text: org.bluetooth.descriptor.gatt.characteristic_presentation_format; url: gatt.characteristic_presentation_format.xml#
+ text: org.bluetooth.descriptor.gatt.client_characteristic_configuration; url: gatt.client_characteristic_configuration.xml#
+ urlPrefix: services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.
+ text: org.bluetooth.service.cycling_power; url: cycling_power.xml#
+ text: org.bluetooth.service.device_information; url: device_information.xml#
+ text: org.bluetooth.service.heart_rate; url: heart_rate.xml#
+ type: dfn
+ text: Shortened Local Name; url: https://www.bluetooth.org/en-us/specification/assigned-numbers/generic-access-profile#
+
+spec: ECMAScript; urlPrefix: https://tc39.github.io/ecma262/#
+ type: dfn
+ text: Realm; url: sec-code-realms
+ type: method
+ text: Array.prototype.map; url: sec-array.prototype.map
+ type: interface
+ text: Array; url: sec-array-objects
+ text: ArrayBuffer; url: sec-arraybuffer-constructor
+ text: DataView; url: sec-dataview-constructor
+ text: Map; url: sec-map-constructor
+ text: Promise; url:sec-promise-objects
+ text: Set; url: sec-set-objects
+ text: TypeError; url: sec-native-error-types-used-in-this-standard-typeerror
+ text: TypedArray; url: sec-typedarray-constructors
+
+spec: WebIDL; urlPrefix: https://heycam.github.io/webidl/#
+ type: dfn
+ text: a copy of the bytes held; url: dfn-get-buffer-source-copy
+
+
+spec: html
+ type: dfn
+ text: browsing context
+ text: environment settings object
+ text: event handler idl attribute
+ text: global object
+ text: in parallel
+ text: incumbent settings object
+ text: perform a microtask checkpoint
+ text: queue a task
+ text: relevant settings object
+ text: responsible event loop
+ text: triggered by user activation
+
+
+
+
+
+ Introduction
+
+ This section is non-normative.
+
+
+ Bluetooth Low Energy (BLE)
+ allows devices to broadcast advertisements to nearby observers .
+ These advertisements can contain small amounts of data
+ of a variety of types defined in [[BLUETOOTH-SUPPLEMENT6]].
+
+
+
+ For example, a beacon might announce that it's next to a particular museum exhibit
+ and is advertising with 1mW of power,
+ which would let nearby observers know their approximate distance to that exhibit.
+
+
+
+ This specification extends [[web-bluetooth]] to allow websites to
+ receive these advertisements from nearby BLE devices,
+ with the user's permission.
+
+
+
+ Examples
+
+
+
+ To discover what iBeacons are nearby and measure their distance,
+ a website could use code like the following:
+
+
+ function recordNearbyBeacon(major, minor, pathLossVs1m) { ... }
+ let myBeaconUuid = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
+
+ navigator.bluetooth.requestLEScan ({
+ filters: [{manufacturerData: 0x004C}],
+ options: {
+ keepRepeatedDevices: true,
+ }
+ }).then(() => {
+ navigator.bluetooth.addEventListener('advertisementreceived ', event => {
+ let appleData = event.manufacturerData.get(0x004C );
+ if (appleData.byteLength != 23 ||
+ appleData.getUint16(0, false) !== 0x0215) {
+ // Isn't an iBeacon.
+ return;
+ }
+ let uuidArray = new Uint8Array(appleData.buffer, 2, 16);
+ for (let i = 0; i < 16; i++) {
+ if (uuidArray[i] != myBeaconUuid[i]) {
+ // Not my class of beacon.
+ return;
+ }
+ }
+ let major = appleData.getUint16(18, false);
+ let minor = appleData.getUint16(20, false);
+ let txPowerAt1m = -appleData.getInt8(22);
+ let pathLossVs1m = txPowerAt1m - event.rssi;
+
+ recordNearbyBeacon(major, minor, pathLossVs1m);
+ });
+ })
+
+
+
+
+
+
+ Privacy considerations
+
+ This section is non-normative.
+
+
+ The ambient advertisements in a user's area are unlikely to directly include GPS coordinates,
+ but are likely to contain unique identifiers
+ that could be manually correlated with particular physical locations
+ or with particular other people.
+ Given that, the user needs to give permission
+ before a website gets access to nearby advertisements.
+
+
+
+ If a user has already given a site permission to know their location,
+ it might be ok to implicitly grant access to BLE advertisements.
+ However, BLE advertisements give away
+ strictly less location information than full [[geolocation-api]] access,
+ so UAs should allow users to grant that intermediate level of access.
+
+
+
+ BLE advertisements are usually fully public,
+ since they're broadcast unencrypted on 2.4GHz radio waves.
+ However, it's possible that a user would
+ have a device broadcast private information in a radio-shielded room.
+ This is probably an inappropriate use for BLE advertisements,
+ but might argue for requiring explicit permission to scan,
+ rather than inferring it from having permission to get a geolocation.
+
+
+
+
+ Security considerations
+
+ This section is non-normative.
+
+
+ Because this API doesn't write anything,
+ there are few if any security implications.
+ A device in a shielded room might broadcast security-sensitive information,
+ but we don't have any actual attack scenarios for that.
+
+
+
+
+ Scanning for BLE advertisements
+
+
+ dictionary BluetoothLEScanFilterInit {
+ BluetoothServiceUUID serviceUUID;
+ unsigned short manufacturerData;
+ BluetoothServiceUUID serviceData;
+ };
+
+ dictionary BluetoothLEScanOptions {
+ required sequence<BluetoothLEScanFilterInit> filters;
+ boolean keepRepeatedDevices = false;
+ };
+
+ partial interface Bluetooth {
+ [SecureContext]
+ Promise<BluetoothLEScan> requestLEScan(BluetoothLEScanOptions options);
+ };
+
+
+
+ navigator.bluetooth.{{requestLEScan(options)}}
+ starts scanning for BLE advertisements,
+ asking the user for permission if they haven't yet granted it.
+
+
+ Because this could show a prompt,
+ it can only be called from a user gesture
+ and requires a secure context .
+
+
+ Advertising events that match
+ a {{BluetoothLEScanFilter}} in an active {{BluetoothLEScan}}
+ cause {{advertisementreceived}} events to be dispatched
+ to the sending {{BluetoothDevice}}.
+ A filter matches if the advertisement includes data equal to each present member.
+ Usually, you'll only include one member in each filter.
+
+
+ Normally scans will discard
+ the second and subsequent advertisements from a single device
+ to save power.
+ If you need to receive them,
+ set keepRepeatedDevices to `true`.
+ Note that setting {{BluetoothLEScanOptions/keepRepeatedDevices}} to `false`
+ doesn't guarantee you won't get redundant events;
+ it just allows the UA to save power by omitting them.
+
+
+
+
+
+ The requestLEScan(|options|)
method,
+ when invoked, MUST return a new promise |promise|
+ and run the following steps in parallel :
+
+
+
+ Let |filters| be
+ |options|.filters.map(filter=>new
+ {{BluetoothLEScanFilter/BluetoothLEScanFilter()|BluetoothLEScanFilter}}(filter))
.
+ If this throws an exception,
+ reject |promise| with that exception and abort these steps.
+
+
+ Let |scan| be a new {{BluetoothLEScan}} instance
+ whose fields are initialized as in the following table:
+
+ Field Initial value
+ {{BluetoothLEScan/filters}} |filters|
+
+ {{BluetoothLEScan/keepRepeatedDevices}}
+ |options|.keepRepeatedDevices
+
+ {{BluetoothLEScan/active}} `true`
+
+
+
+ Request permission to use {name: {{"bluetooth-le-scan"}}}
.
+
+ Note: This may require that this algorithm was triggered by user activation .
+
+
+ If the result is {{"denied"}},
+ reject |promise| with a {{NotAllowedError}} and abort these steps.
+
+
+ Add |scan| to navigator.bluetooth.{{[[activeScans]]}}
.
+
+
+ Ensure the UA is scanning for BLE advertisements
+ in a mode that will receive at least
+ all advertisements matching any scan
+ in any {{[[activeScans]]}} set in the whole UA.
+
+
+ If the UA fails to start scanning,
+ remove |scan| from navigator.bluetooth.{{[[activeScans]]}}
,
+ reject |promise| with one of the following errors,
+ and abort these steps:
+
+
+ The UA doesn't support scanning for advertisements
+ {{NotSupportedError}}
+
+ Bluetooth is turned off
+ {{InvalidStateError}}
+
+ Other reasons
+ {{UnknownError}}
+
+
+
+ Resolve |promise| with |scan|.
+
+
+
+
+
+ Controlling a BLE scan
+
+
+ [Constructor(BluetoothLEScanFilterInit init)]
+ interface BluetoothLEScanFilter {
+ readonly attribute UUID? serviceUUID;
+ readonly attribute unsigned short? manufacturerData;
+ readonly attribute UUID? serviceData;
+ };
+
+ interface BluetoothLEScan {
+ readonly attribute FrozenArray<BluetoothLEScanFilter> filters;
+ readonly attribute boolean keepRepeatedDevices;
+
+ readonly attribute boolean active;
+
+ void stop();
+ };
+
+
+
+
+ {{BluetoothLEScan/stop()|BluetoothLEScan.stop()}}
+ stops a previously-requested scan.
+ Sites should do this as soon as possible to avoid wasting power.
+
+
+
+
+
+ The BluetoothLEScanFilter(|init|)
+ constructor, when invoked MUST perform the following steps:
+
+
+
+ Initialize all fields to `null`.
+
+
+ For each present member in |init|,
+ set `this`'s attribute with a matching identifier to the value of the member.
+ If the member's type is {{BluetoothServiceUUID}},
+ pass its value through {{BluetoothUUID/getService()|BluetoothUUID.getService()}}
+ to get the value with which to initialize the attribute.
+ If any of these calls throw an exception,
+ propagate that exception from this constructor.
+
+
+
+
+
+
+ The stop() method, when invoked,
+ MUST perform the following steps:
+
+
+ Set this.{{BluetoothLEScan/active}}
to `false`.
+ Remove `this` from navigator.bluetooth.{{[[activeScans]]}}
.
+
+ The UA SHOULD reconfigure or stop its BLE scan to save power
+ while still receiving any advertisements that
+ match any scan
+ in any {{[[activeScans]]}} set in the whole UA.
+
+
+
+
+
+
+ Permission to scan
+
+
+ The "bluetooth-le-scan"
+ powerful feature 's
+ permission-related algorithms and types
+ are defined as follows:
+
+
+ permission descriptor type
+
+
+ dictionary BluetoothLEScanPermissionDescriptor : PermissionDescriptor {
+ // These match BluetoothLEScanOptions.
+ sequence<BluetoothLEScanFilterInit> filters;
+ boolean keepRepeatedDevices;
+ };
+
+
+
+ permission result type
+
+
+ interface BluetoothLEScanPermissionResult : PermissionStatus {
+ attribute FrozenArray<BluetoothLEScan> scans;
+ };
+
+
+
+ permission query algorithm
+
+
+ Given a {{BluetoothLEScanPermissionDescriptor}} |descriptor|
+ and a {{BluetoothLEScanPermissionResult}} |result|:
+
+
+
+ Update |result|.{{PermissionStatus/state}}
+ to |descriptor|'s permission state .
+
+
+ If |result|.{{PermissionStatus/state}}
is {{"denied"}},
+ set |result|.scans
to an empty {{FrozenArray}}
+ and abort these steps.
+
+
+ Update |result|.{{scans}}
to
+ a new {{FrozenArray}} containing
+ the elements of navigator.bluetooth.{{[[activeScans]]}}
.
+
+
+ Consider filtering the result to active scans that
+ match the fields of the descriptor.
+
+
+
+
+
+ permission request algorithm
+
+
+ Given a {{BluetoothLEScanPermissionDescriptor}} |descriptor|
+ and a {{BluetoothLEScanPermissionResult}} |result|:
+
+
+
+ Let |promise| be the result of
+ navigator.bluetooth.{{requestLEScan()|requestLEScan}}(|descriptor|)
.
+
+ Wait for |promise| to settle.
+
+ If |promise| rejected, throw the reason it rejected with,
+ and abort these steps.
+
+
+ Update |result|.status
to
+ |descriptor|'s permission state .
+
+
+ Update |result|.scans
to
+ a new {{FrozenArray}} whose single element is the value in |promise|.
+
+
+
+
+
+ permission revocation algorithm
+
+
+
+
+ For each |activeScan| in navigator.bluetooth.{{[[activeScans]]}}
,
+ call |activeScan|.{{stop()}}
.
+
+
+
+
+
+
+
+
+ Event handling
+
+
+ Responding to advertising events
+
+
+
+ When the UA receives an advertising event |event|
+ (consisting of an advertising packet and an optional scan response),
+ it MUST run the following steps:
+
+
+
+ Let device be the Bluetooth device that sent the advertising event.
+
+
+ For each {{Bluetooth}} instance |bluetooth| in the UA,
+ queue a task on
+ |bluetooth|'s relevant settings object 's responsible event loop
+ to do the following sub-steps:
+
+
+ Let |scans| be the set of
+ {{BluetoothLEScan}}s in |bluetooth|.{{[[activeScans]]}}
+ that match |event|.
+
+ If |scans| is empty, abort these sub-steps.
+
+ Get the `BluetoothDevice` representing |device| inside |bluetooth|,
+ with the following modification to the algorithm,
+ and let |deviceObj| be the result.
+
+
+ If there is no entry in
+ storage.{{BluetoothPermissionStorage/allowedDevices}}
+ for |device|,
+ then initialize |result|.{{BluetoothDevice/id}}
to
+ a per-origin ID
+ that's stable until the user revokes
+ their permission for this origin to scan ,
+ and initialize |result|.{{BluetoothDevice/gatt}}
to `null`.
+
+
+
+ Make this more rigorous once [[Permissions]] is in shape.
+
+
+
+ Add each {{BluetoothLEScan}} in |scans|
+ to |deviceObj|.{{[[returnedFromScans]]}}
.
+
+
+ Fire an `advertisementreceived` event
+ for |event| at |deviceObj|.
+
+
+
+
+
+
+
+
+ An advertising event |event|
+ matches a {{BluetoothLEScan}} |scan|
+ if the following steps return `match`:
+
+
+
+ If |event| doesn't match
+ any filter in |scan|.{{BluetoothLEScan/filters}}
,
+ return `no match`.
+
+
+ If |scan|.{{BluetoothLEScan/keepRepeatedDevices}}
is `false`,
+ there is a {{BluetoothDevice}} |device| that
+ represents the same Bluetooth device as the one that sent |event|,
+ and |device|.{{[[returnedFromScans]]}}
includes |scan|,
+ the UA MAY return `no match`.
+
+ Return `match`.
+
+
+
+
+
+ An advertising event |event|
+ matches
+ a {{BluetoothLEScanFilter}} |filter|
+ if all of the following conditions hold:
+
+
+
+ If |filter|.serviceUUID
is non-`null`,
+ it is equal to a Service UUID in |event|.
+
+
+ If |filter|.manufacturerData
is non-`null`,
+ it is equal to the Company Identifier Code
+ in some Manufacturer Specific Data in |event|.
+
+
+ If |filter|.serviceData
is non-`null`,
+ it is the 128-bit UUID representation of the UUID
+ in some Service Data in |event|.
+
+
+
+
+
+
+
+ Changes to existing interfaces
+
+
+ Instances of {{Bluetooth}} additionally have the following internal slots:
+
+
+
+ Internal Slot
+ Initial Value
+ Description (non-normative)
+
+
+ \[[activeScans]]
+
+ An empty set of {{BluetoothLEScan}} instances.
+
+
+ The contents of this set will have {{BluetoothLEScan/active}} equal to `true`.
+
+
+
+
+
+ Instances of {{BluetoothDevice}} additionally have the following internal slots:
+
+
+
+ Internal Slot
+ Initial Value
+ Description (non-normative)
+
+
+ \[[returnedFromScans]]
+
+ An empty set of {{BluetoothLEScan}} objects.
+
+
+ Used to implement {{BluetoothLEScanOptions/keepRepeatedDevices}}.
+
+
+
+
+
+
+ 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 {{Bluetooth/requestLEScan()}} algorithm says to call
+ |options|.filters.map(filter=>new
+ {{BluetoothLEScanFilter/BluetoothLEScanFilter()|BluetoothLEScanFilter}}(filter))
,
+ this MUST apply the
+ {{Array.prototype.map}} algorithm defined in [[ECMAScript]]
+ with |options|.services
as its this
parameter and
+ the algorithm defined at {{BluetoothLEScanFilter/BluetoothLEScanFilter()}}
+ as its callbackfn
parameter,
+ regardless of any modifications that have been made to window
,
+ Array
, Array.prototype
, Array.prototype.map
,
+ Function
, Function.prototype
,
+ BluetoothLEScanFilter
, or other objects.
+
+
+
+ [[!BLUETOOTH42]]
+
+
+ Architecture & Terminology Overview
+
+ General Description
+
+ Overview of Bluetooth Low Energy Operation
+ (defines advertising events )
+
+
+
+
+
+ Core System Package [BR/EDR Controller volume]
+
+ Host Controller Interface Functional Specification
+
+ HCI Commands and Events
+
+ Informational Parameters
+
+ Read BD_ADDR Command
+
+
+ Status Parameters
+
+
+ Read RSSI Command
+
+
+
+
+
+
+
+
+
+ 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)
+
+
+
+
+
+
+
+ Generic Access Profile
+
+ Profile Overview
+
+ Profile Roles
+
+ Roles when Operating over an LE Physical Transport
+
+ Broadcaster Role
+ Observer Role
+ Peripheral Role
+ Central Role
+
+
+
+
+
+
+ User Interface Aspects
+
+ Representation of Bluetooth Parameters
+
+ Bluetooth Device Name (the user-friendly name)
+
+ Class of Device
+
+
+
+
+ Idle Mode Procedures — BR/EDR Physical Transport
+
+ Device Discovery 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
+
+
+ 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
+ Bluetooth Device Requirements
+
+ Bluetooth Device Address (defines BD_ADDR )
+
+ Bluetooth Device Address Types
+
+ Public Bluetooth Address
+
+
+
+
+
+
+
+
+ Attribute Protocol (ATT)
+
+ Protocol Requirements
+
+ Basic Concepts
+
+ Attribute Type
+ Attribute Handle
+ Long Attribute Values
+
+
+ Attribute Protocol Pdus
+
+ Error Handling
+
+ Error Response
+
+
+
+
+
+
+
+
+ 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
+
+ Characteristic Definition
+
+ Characteristic Declaration
+
+ Characteristic Properties
+
+
+ Characteristic Descriptor Declarations
+
+ Characteristic Extended Properties
+ Client Characteristic Configuration
+
+
+
+
+
+
+ GATT Feature Requirements — defines the
+ GATT procedures .
+
+ 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
+ Characteristic Value Notification
+ Characteristic Value Indications
+ Characteristic Descriptors
+
+ Read Characteristic Descriptors
+ Read Long Characteristic Descriptors
+ Write Characteristic Descriptors
+ Write Long Characteristic Descriptors
+
+
+ Procedure Timeouts
+
+
+ GAP Interoperability Requirements
+
+ BR/EDR GAP Interoperability Requirements
+
+ Connection Establishment
+
+
+ LE GAP Interoperability Requirements
+
+ Connection Establishment
+
+
+
+
+ Defined Generic Attribute Profile Service
+
+ Service Changed
+
+
+
+
+ Security Manager Specification
+
+ Security Manager
+
+ Security in Bluetooth Low Energy
+
+ Definition of Keys and Values ,
+ defines the
+ Identity Resolving Key
+ (IRK )
+
+
+
+
+
+
+
+
+
+ Core System Package [Low Energy Controller volume]
+
+ Link Layer Specification
+
+ General Description
+
+ Device Address
+
+ Public Device Address
+ Random Device Address
+
+ Static Device Address
+
+
+
+
+
+
+ Air Interface Protocol
+
+ Non-Connected States
+
+ Scanning State
+
+ Passive Scanning
+
+
+
+
+
+
+
+
+
+
+
+
+ [[!BLUETOOTH-SUPPLEMENT6]]
+
+
+ Data Types Specification
+
+ Data Types Definitions and Formats
+
+ Service UUID
+ Local Name
+ Manufacturer Specific Data
+ TX Power Level
+ Service Data
+ Appearance
+
+
+
+
+
+
+
+
diff --git a/scanning.html b/scanning.html
new file mode 100644
index 0000000..3ff93e5
--- /dev/null
+++ b/scanning.html
@@ -0,0 +1,2848 @@
+
+
+
+
+ Web Bluetooth Scanning
+
+
+
+
+
+
+
+
+
+
+
+ Abstract
+
+
This document describes an API to scan for nearby Bluetooth Low Energy devices in real time.
+
+ Status of this document
+
+
+
+ Table of Contents
+
+
+ 1 Introduction
+
+ 1.1 Examples
+
+ 2 Privacy considerations
+ 3 Security considerations
+
+ 4 Scanning for BLE advertisements
+
+ 4.1 Controlling a BLE scan
+ 4.2 Permission to scan
+
+
+ 5 Event handling
+
+ 5.1 Responding to advertising events
+
+ 6 Changes to existing interfaces
+ 7 Terminology and conventions
+ Conformance
+
+ Index
+
+ Terms defined by this specification
+ Terms defined by reference
+
+
+ References
+
+ Normative References
+ Informative References
+
+ IDL Index
+ Issues Index
+
+
+
+
+ 1. Introduction
+ This section is non-normative.
+ Bluetooth Low Energy (BLE) allows devices to broadcast advertisements to nearby observers .
+ These advertisements can contain small amounts of data
+ of a variety of types defined in [BLUETOOTH-SUPPLEMENT6] .
+ For example, a beacon might announce that it’s next to a particular museum exhibit
+ and is advertising with 1mW of power,
+ which would let nearby observers know their approximate distance to that exhibit.
+ This specification extends [web-bluetooth] to allow websites to
+ receive these advertisements from nearby BLE devices,
+ with the user’s permission.
+
+ 1.1. Examples
+
+
+
To discover what iBeacons are nearby and measure their distance,
+ a website could use code like the following:
+
function recordNearbyBeacon ( major , minor , pathLossVs1m ) { ... }
+let myBeaconUuid = new Uint8Array ([ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 ]);
+
+navigator . bluetooth . requestLEScan ({
+ filters : [{ manufacturerData : 0x004C }],
+ options : {
+ keepRepeatedDevices : true ,
+ }
+}). then (() => {
+ navigator . bluetooth . addEventListener ( ' advertisementreceived ' , event => {
+ let appleData = event . manufacturerData . get ( 0x004C );
+ if ( appleData . byteLength != 23 ||
+ appleData . getUint16 ( 0 , false ) !== 0x0215 ) {
+ // Isn’t an iBeacon.
+ return ;
+ }
+ let uuidArray = new Uint8Array ( appleData . buffer , 2 , 16 );
+ for ( let i = 0 ; i < 16 ; i ++ ) {
+ if ( uuidArray [ i ] != myBeaconUuid [ i ]) {
+ // Not my class of beacon.
+ return ;
+ }
+ }
+ let major = appleData . getUint16 ( 18 , false );
+ let minor = appleData . getUint16 ( 20 , false );
+ let txPowerAt1m = - appleData . getInt8 ( 22 );
+ let pathLossVs1m = txPowerAt1m - event . rssi ;
+
+ recordNearbyBeacon ( major , minor , pathLossVs1m );
+ });
+})
+
+
+
+
+
+ 2. Privacy considerations
+ This section is non-normative.
+ The ambient advertisements in a user’s area are unlikely to directly include GPS coordinates,
+ but are likely to contain unique identifiers
+ that could be manually correlated with particular physical locations
+ or with particular other people.
+ Given that, the user needs to give permission
+ before a website gets access to nearby advertisements.
+ If a user has already given a site permission to know their location,
+ it might be ok to implicitly grant access to BLE advertisements.
+ However, BLE advertisements give away
+ strictly less location information than full [geolocation-api] access,
+ so UAs should allow users to grant that intermediate level of access.
+ BLE advertisements are usually fully public,
+ since they’re broadcast unencrypted on 2.4GHz radio waves.
+ However, it’s possible that a user would
+ have a device broadcast private information in a radio-shielded room.
+ This is probably an inappropriate use for BLE advertisements,
+ but might argue for requiring explicit permission to scan,
+ rather than inferring it from having permission to get a geolocation.
+
+
+ 3. Security considerations
+ This section is non-normative.
+ Because this API doesn’t write anything,
+ there are few if any security implications.
+ A device in a shielded room might broadcast security-sensitive information,
+ but we don’t have any actual attack scenarios for that.
+
+
+ 4. Scanning for BLE advertisements
+dictionary BluetoothLEScanFilterInit {
+ BluetoothServiceUUID serviceUUID ;
+ unsigned short manufacturerData ;
+ BluetoothServiceUUID serviceData ;
+};
+
+dictionary BluetoothLEScanOptions {
+ required sequence <BluetoothLEScanFilterInit > filters ;
+ boolean keepRepeatedDevices = false ;
+};
+
+partial interface Bluetooth {
+ [SecureContext ]
+ Promise <BluetoothLEScan > requestLEScan (BluetoothLEScanOptions options );
+};
+
+
+
+
navigator.bluetooth.requestLEScan(options)
starts scanning for BLE advertisements,
+ asking the user for permission if they haven’t yet granted it.
+
Because this could show a prompt,
+ it can only be called from a user gesture
+ and requires a secure context .
+
Advertising events that match a BluetoothLEScanFilter
in an active BluetoothLEScan
cause advertisementreceived
events to be dispatched
+ to the sending BluetoothDevice
.
+ A filter matches if the advertisement includes data equal to each present member.
+ Usually, you’ll only include one member in each filter.
+
Normally scans will discard
+ the second and subsequent advertisements from a single device
+ to save power.
+ If you need to receive them,
+ set keepRepeatedDevices to true
.
+ Note that setting keepRepeatedDevices
to false
doesn’t guarantee you won’t get redundant events;
+ it just allows the UA to save power by omitting them.
+
+
+
+ 4.1. Controlling a BLE scan
+[Constructor (BluetoothLEScanFilterInit init )]
+interface BluetoothLEScanFilter {
+ readonly attribute UUID ? serviceUUID ;
+ readonly attribute unsigned short ? manufacturerData ;
+ readonly attribute UUID ? serviceData ;
+};
+
+interface BluetoothLEScan {
+ readonly attribute FrozenArray <BluetoothLEScanFilter > filters ;
+ readonly attribute boolean keepRepeatedDevices ;
+
+ readonly attribute boolean active ;
+
+ void stop ();
+};
+
+
+
+
BluetoothLEScan.stop()
stops a previously-requested scan.
+ Sites should do this as soon as possible to avoid wasting power.
+
+
+
The BluetoothLEScanFilter(init ) constructor, when invoked MUST perform the following steps:
+
+ Initialize all fields to null
.
+ For each present member in init ,
+ set this
's attribute with a matching identifier to the value of the member.
+ If the member’s type is BluetoothServiceUUID
,
+ pass its value through BluetoothUUID.getService()
to get the value with which to initialize the attribute.
+ If any of these calls throw an exception,
+ propagate that exception from this constructor.
+
+
+
+
The stop() method, when invoked,
+ MUST perform the following steps:
+
+ Set this.active
to false
.
+ Remove this
from navigator.bluetooth.[[activeScans]]
.
+ The UA SHOULD reconfigure or stop its BLE scan to save power
+ while still receiving any advertisements that match any scan
+ in any [[activeScans]]
set in the whole UA.
+
+
+
+
+
+
+ 5. Event handling
+
+ 5.1. Responding to advertising events
+
+
+
+
An advertising event event matches a BluetoothLEScanFilter
filter if all of the following conditions hold:
+
+ If filter .serviceUUID
is non-null
,
+ it is equal to a Service UUID in event .
+ If filter .manufacturerData
is non-null
,
+ it is equal to the Company Identifier Code
+ in some Manufacturer Specific Data in event .
+ If filter .serviceData
is non-null
,
+ it is the 128-bit UUID representation of the UUID
+ in some Service Data in event .
+
+
+
+
+
+ 6. Changes to existing interfaces
+ Instances of Bluetooth
additionally have the following internal slots:
+
+
+
+ Internal Slot
+ Initial Value
+ Description (non-normative)
+
+
+ [[activeScans]]
+ An empty set of BluetoothLEScan
instances.
+ The contents of this set will have active
equal to true
.
+
+ Instances of BluetoothDevice
additionally have the following internal slots:
+
+
+
+ Internal Slot
+ Initial Value
+ Description (non-normative)
+
+
+ [[returnedFromScans]]
+ An empty set of BluetoothLEScan
objects.
+ Used to implement keepRepeatedDevices
.
+
+
+
+ 7. 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 requestLEScan()
algorithm says to call options .filters.map(filter=>new BluetoothLEScanFilter
(filter))
,
+ this MUST apply the Array.prototype.map
algorithm defined in [ECMAScript] with options .services
as its this
parameter and
+ the algorithm defined at BluetoothLEScanFilter()
as its callbackfn
parameter,
+ regardless of any modifications that have been made to window
, Array
, Array.prototype
, Array.prototype.map
, Function
, Function.prototype
, BluetoothLEScanFilter
, or other objects.
+
+ [BLUETOOTH42]
+
+
+
+ Architecture & Terminology Overview
+
+
+ General Description
+
+ Overview of Bluetooth Low Energy Operation
+ (defines advertising events )
+
+
+
+ Core System Package [BR/EDR Controller volume]
+
+
+ Host Controller Interface Functional Specification
+
+
+ HCI Commands and Events
+
+
+ Informational Parameters
+
+ Read BD_ADDR Command
+
+
+ Status Parameters
+
+ Read Command
+
+
+
+
+
+ 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)
+
+
+
+
+ Generic Access Profile
+
+
+ Profile Overview
+
+
+ Profile Roles
+
+
+ Roles when Operating over an LE Physical Transport
+
+ Broadcaster Role
+ Observer Role
+ Peripheral Role
+ Central Role
+
+
+
+
+ User Interface Aspects
+
+
+ Representation of Bluetooth Parameters
+
+ Bluetooth Device Name (the user-friendly name)
+ Class of Device
+
+
+
+ Idle Mode Procedures — BR/EDR Physical Transport
+
+ Device Discovery 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
+
+
+ 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
+
+ Bluetooth Device Requirements
+
+
+ Bluetooth Device Address (defines BD_ADDR )
+
+
+ Bluetooth Device Address Types
+
+ Public Bluetooth Address
+
+
+
+
+
+ Attribute Protocol (ATT)
+
+
+ Protocol Requirements
+
+
+ Basic Concepts
+
+ Attribute Type
+ Attribute Handle
+ Long Attribute Values
+
+
+ Attribute Protocol Pdus
+
+
+ Error Handling
+
+ Error Response
+
+
+
+
+
+ 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
+
+
+ Characteristic Definition
+
+
+ Characteristic Declaration
+
+ Characteristic Properties
+
+
+ Characteristic Descriptor Declarations
+
+ Characteristic Extended Properties
+ Client Characteristic Configuration
+
+
+
+
+ GATT Feature Requirements — defines the GATT procedures .
+
+
+ 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
+ Characteristic Value Notification
+ Characteristic Value Indications
+
+ Characteristic Descriptors
+
+ Read Characteristic Descriptors
+ Read Long Characteristic Descriptors
+ Write Characteristic Descriptors
+ Write Long Characteristic Descriptors
+
+ Procedure Timeouts
+
+
+ GAP Interoperability Requirements
+
+
+ BR/EDR GAP Interoperability Requirements
+
+ Connection Establishment
+
+
+ LE GAP Interoperability Requirements
+
+ Connection Establishment
+
+
+
+ Defined Generic Attribute Profile Service
+
+ Service Changed
+
+
+
+ Security Manager Specification
+
+
+ Security Manager
+
+
+ Security in Bluetooth Low Energy
+
+ Definition of Keys and Values ,
+ defines the Identity Resolving Key (IRK )
+
+
+
+
+
+ Core System Package [Low Energy Controller volume]
+
+
+ Link Layer Specification
+
+
+ General Description
+
+
+ Device Address
+
+ Public Device Address
+
+ Random Device Address
+
+ Static Device Address
+
+
+
+
+ Air Interface Protocol
+
+
+ Non-Connected States
+
+
+ Scanning State
+
+ Passive Scanning
+
+
+
+
+
+
+ [BLUETOOTH-SUPPLEMENT6]
+
+
+
+ Data Types Specification
+
+
+ Data Types Definitions and Formats
+
+ Service UUID
+ Local Name
+ Manufacturer Specific Data
+ TX Power Level
+ Service Data
+ Appearance
+
+
+
+
+
+
+
+
+
Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology.
+ The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL”
+ in the normative parts of this document
+ are to be interpreted as described in RFC 2119.
+ However, for readability,
+ these words do not appear in all uppercase letters in this specification.
+
All of the text of this specification is normative
+ except sections explicitly marked as non-normative, examples, and notes. [RFC2119]
+
Examples in this specification are introduced with the words “for example”
+ or are set apart from the normative text with class="example"
, like this:
+
This is an example of an informative example.
+
Informative notes begin with the word “Note”
+ and are set apart from the normative text with class="note"
, like this:
+
Note, this is an informative note.
+
+
+ Index
+ Terms defined by this specification
+
+ active , in §4.1
+ [[activeScans]] , in §6
+ Advertising Data , in §7
+ advertising event , in §7
+ advertising events , in §7
+ Appearance , in §7
+ ATT Bearer , in §7
+ Attribute Caching , in §7
+ Attribute Handle , in §7
+ Attribute Type , in §7
+ BD_ADDR , in §7
+ Bluetooth Device Name , in §7
+ BluetoothLEScan , in §4.1
+ "bluetooth-le-scan" , in §4.2
+ BluetoothLEScanFilter , in §4.1
+ BluetoothLEScanFilterInit , in §4
+ BluetoothLEScanFilter(init) , in §4.1
+ BluetoothLEScanOptions , in §4
+ BluetoothLEScanPermissionDescriptor , in §4.2
+ BluetoothLEScanPermissionResult , in §4.2
+ Broadcaster , in §7
+ Central , in §7
+ Characteristic , in §7
+ Characteristic Descriptor Discovery , in §7
+ Characteristic Descriptors , in §7
+ Characteristic Discovery , in §7
+ Characteristic Extended Properties , in §7
+ Characteristic Properties , in §7
+ Characteristic Value Indications , in §7
+ Characteristic Value Notification , in §7
+ Characteristic Value Read , in §7
+ Characteristic Value Write , in §7
+ Class of Device , in §7
+ Client Characteristic Configuration , in §7
+ Connection Modes and Procedures , in §7
+ Definition of Keys and Values , in §7
+ Descriptor , in §7
+ Device Discovery Procedure , in §7
+ Discover All Characteristic Descriptors , in §7
+ Discover All Characteristics of a Service , in §7
+ Discover All Primary Services , in §7
+ Discover Characteristics by UUID , in §7
+ Discover Primary Service by Service UUID , in §7
+ Error Response , in §7
+
+ filters
+
+ Find Included Services , in §7
+ GAP Interoperability Requirements , in §7
+ GATT , in §7
+ GATT Client , in §7
+ GATT procedure , in §7
+ GATT procedures , in §7
+ GATT Profile Hierarchy , in §7
+ GATT Server , in §7
+ General Discovery Procedure , in §7
+ Generic Attribute Profile , in §7
+ Identity Resolving Key , in §7
+ Included Service , in §7
+ IRK , in §7
+
+ keepRepeatedDevices
+
+ Local Name , in §7
+ Long Attribute Values , in §7
+
+ manufacturerData
+
+ Manufacturer Specific Data , in §7
+
+ match
+
+ Name Discovery Procedure , in §7
+ Observation Procedure , in §7
+ Observer , in §7
+ Passive Scanning , in §7
+ Peripheral , in §7
+ Primary Service Discovery , in §7
+ Privacy Feature , in §7
+ Private address , in §7
+ Procedure Timeouts , in §7
+ procedure times out , in §7
+ Profile Fundamentals , in §7
+ Public Bluetooth Address , in §7
+ Public Device Address , in §7
+ Read BD_ADDR Command , in §7
+ Read Characteristic Descriptors , in §7
+ Read Long Characteristic Descriptors , in §7
+ Received Signal Strength Indication , in §7
+ Relationship Discovery , in §7
+ requestLEScan(options) , in §4
+ Resolvable Private Address Resolution Procedure , in §7
+ [[returnedFromScans]] , in §6
+ RSSI , in §7
+ scans , in §4.2
+ Searching for Services , in §7
+ Service , in §7
+ Service Changed , in §7
+ Service Data , in §7
+
+ serviceData
+
+ Service UUID , in §7
+
+ serviceUUID
+
+ Static Address , in §7
+ Static Device Address , in §7
+ stop() , in §4.1
+ the 128-bit UUID represented , in §7
+ TX Power Level , in §7
+ UUID , in §7
+ UUID alias , in §7
+ Write Characteristic Descriptors , in §7
+ Write Long Characteristic Descriptors , in §7
+
+ Terms defined by reference
+
+ References
+ Normative References
+
+ [BLUETOOTH-SUPPLEMENT6]
+ Supplement to the Bluetooth Core Specification Version 6 . 14 July 2015. URL: https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=302735
+ [BLUETOOTH42]
+ BLUETOOTH SPECIFICATION Version 4.2 . 2 December 2014. URL: https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439
+ [ECMAScript]
+ ECMAScript Language Specification . URL: https://tc39.github.io/ecma262/
+ [HTML]
+ Ian Hickson. HTML Standard . Living Standard. URL: https://html.spec.whatwg.org/multipage/
+ [Permissions]
+ Mounir Lamouri; Marcos Caceres. The Permissions API . 7 April 2015. WD. URL: https://w3c.github.io/permissions/
+ [PROMISES-GUIDE]
+ Domenic Denicola. Writing Promise-Using Specifications . 16 February 2016. Finding of the W3C TAG. URL: https://www.w3.org/2001/tag/doc/promises-guide
+ [RFC2119]
+ S. Bradner. Key words for use in RFCs to Indicate Requirement Levels . March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
+ [WEB-BLUETOOTH]
+ Jeffrey Yasskin. Web Bluetooth . Draft Community Group Report. URL: https://webbluetoothcg.github.io/web-bluetooth/
+ [WebIDL-1]
+ Cameron McCormack; Boris Zbarsky. WebIDL Level 1 . 8 March 2016. CR. URL: https://heycam.github.io/webidl/
+
+
+
+ [GEOLOCATION-API]
+ Andrei Popescu. Geolocation API Specification . 28 May 2015. PER. URL: http://dev.w3.org/geo/api/spec-source.html
+ [SECURE-CONTEXTS]
+ Mike West. Secure Contexts . 18 July 2016. WD. URL: https://w3c.github.io/webappsec-secure-contexts/
+
+ IDL Index
+dictionary BluetoothLEScanFilterInit {
+ BluetoothServiceUUID serviceUUID ;
+ unsigned short manufacturerData ;
+ BluetoothServiceUUID serviceData ;
+};
+
+dictionary BluetoothLEScanOptions {
+ required sequence <BluetoothLEScanFilterInit > filters ;
+ boolean keepRepeatedDevices = false ;
+};
+
+partial interface Bluetooth {
+ [SecureContext ]
+ Promise <BluetoothLEScan > requestLEScan (BluetoothLEScanOptions options );
+};
+
+[Constructor (BluetoothLEScanFilterInit init )]
+interface BluetoothLEScanFilter {
+ readonly attribute UUID ? serviceUUID ;
+ readonly attribute unsigned short ? manufacturerData ;
+ readonly attribute UUID ? serviceData ;
+};
+
+interface BluetoothLEScan {
+ readonly attribute FrozenArray <BluetoothLEScanFilter > filters ;
+ readonly attribute boolean keepRepeatedDevices ;
+
+ readonly attribute boolean active ;
+
+ void stop ();
+};
+
+dictionary BluetoothLEScanPermissionDescriptor : PermissionDescriptor {
+ // These match BluetoothLEScanOptions.
+ sequence <BluetoothLEScanFilterInit > filters ;
+ boolean keepRepeatedDevices ;
+};
+
+interface BluetoothLEScanPermissionResult : PermissionStatus {
+ attribute FrozenArray <BluetoothLEScan > scans ;
+};
+
+
+ Issues Index
+
+
Consider filtering the result to active scans that
+ match the fields of the descriptor.
↵
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file