BluetoothLE

This API allows you to interact with Bluetooth LE devices.

Classes

BluetoothLE

initialize

Initialize Bluetooth on the device. Must be called before anything else. Callback will continuously be used whenever Bluetooth is enabled or disabled. Note: Although Bluetooth initialization could initially be successful, there's no guarantee whether it will stay enabled. Each call checks whether Bluetooth is disabled. If it becomes disabled, the user must connect to the device, start a read/write operation, etc again. If Bluetooth is disabled, you can request the user to enable it by setting the request property to true. The request property in the params argument is optional and defaults to false. The restoreKey property requires using the Bluetooth Central background mode. This function should only be called once.

initialize(initializeResult, options: InitializeOptions): Promise<ResultInitialize>

PARAMETERS
options: InitializeOptions

RETURN
returns: Promise<ResultInitialize>
enable
enable(): Promise<any>

Enable Bluetooth on the device

RETURN
returns: Promise<any>
disable
disable(): Promise<any>

Disable Bluetooth on the device.

RETURN
returns: Promise<any>
getAdapterInfo

Retrieve useful information such as the address, name, and various states (initialized, enabled, scanning, discoverable). This can be very useful when the general state of the adapter has been lost, and we would otherwise need to go through a series of callbacks to get the correct state (first initialized, then enabled, then isScanning, and so forth). The result of this method allows us to take business logic decisions while avoiding a large part of the callback hell.

Currently the discoverable state does not have any relevance because there is no "setDiscoverable" functionality in place. That may change in the future.

getAdapterInfo(): Promise<ResultGetAdapterInfo>
RETURN
returns: Promise<ResultGetAdapterInfo>
startScan

Scan for Bluetooth LE devices. Since scanning is expensive, stop as soon as possible. The Cordova app should use a timer to limit the scan interval. Also, devices uses an AND operator for filtering. The API requires ACCESS_COARSE_LOCATION permissions to find unpaired devices. Permissions can be requested by using the hasPermission and requestPermission functions. The API also requires location services to be enabled. Use isLocationEnabled to determine whether location services are enabled. If not enabled, use requestLocation to prompt the location services settings page.

startScan(options: StartScanOptions): Promise<ResultStartScan>

PARAMETERS
options: StartScanOptions

RETURN
returns: Promise<ResultStartScan>
stopScan

Stop scan for Bluetooth LE devices. Since scanning is expensive, stop as soon as possible. The app should use a timer to limit the scanning time.

stopScan(): Promise<ResultStopScan>
RETURN
returns: Promise<ResultStopScan>
retrieveConnected

Retrieved paired Bluetooth LE devices.

retrieveConnected(options: RetrieveConnectedOptions): Promise<ResultRetrieveConnected>

PARAMETERS
option: RetrieveConnectedOptions

RETURN
returns: Promise<ResultRetrieveConnected>
bond

Bond with a device. The first success callback should always return with status == bonding. If the bond is created, the callback will return again with status == bonded. If the bonding popup is canceled or the wrong code is entered, the callback will return again with status == unbonded. The device doesn't need to be connected to initiate bonding.

bond(options: Identifier): Promise<ResultObject>

PARAMETERS
options: Identifier

RETURN
returns: Promise<ResultObject>
unbond

Unbond with a device. The device doesn't need to be connected to initiate bonding.

unbond(option: Identifier): Promise<ResultObject>

PARAMETERS
option: Identifier

RETURN
returns: Promise<ResultObject>
connect

Connect to a Bluetooth LE device. The app should use a timer to limit the connecting time in case connecting is never successful. Once a device is connected, it may disconnect without user intervention. The original connection callback will be called again and receive an object with status => disconnected. To reconnect to the device, use the reconnect method. If a timeout occurs, the connection attempt should be canceled using disconnect(). For simplicity, I recommend just using connect() and close(), don't use reconnect() or disconnect().

connect(options: ConnectOptions): Promise<ResultObject>

PARAMETERS
options: ConnectOptions

RETURN
returns: Promise<ResultObject>
reconnect

Reconnect to a previously connected Bluetooth device. The app should use a timer to limit the connecting time. If a timeout occurs, the reconnection attempt should be canceled using disconnect() or close().

reconnect(options: ConnectOptions): Promise<ResultObject>

PARAMETERS
options: ConnectOptions

RETURN
returns: Promise<ResultObject>
disconnect

Disconnect from a Bluetooth LE device. It's simpler to just call close().

disconnect(option: Identifier): Promise<ResultObject>

PARAMETERS
option: Identifier

RETURN
returns: Promise<ResultObject>
close

Close/dispose a Bluetooth LE device. You needed to disconnect to the device before closing, but this is no longer the case.

close(option: Identifier): Promise<ResultObject>

PARAMETERS
option: Identifier

RETURN
returns: Promise<ResultObject>
discover

Discover all the devices services, characteristics and descriptors. Doesn't need to be called again after disconnecting and then reconnecting. On some devices, the discovered services may be cached for a device. Subsequent discover events will make use of this cache. If your device's services change, set the clearCache parameter to force to re-discover services.

discover(options: DiscoverOptions): Promise<ResultDisconnect>

PARAMETERS
option: DiscoverOptions

RETURN
returns: Promise<ResultDisconnect>
read

Read a particular service's characteristic once.

read(options: ServiceCharacteristicOptions): Promise<ResultRead>

PARAMETERS
options: ServiceCharacteristicOptions

RETURN
returns: Promise<ResultRead>
subscribe

Subscribe to a particular service's characteristic. Once a subscription is no longer needed, execute unsubscribe in a similar fashion. The Client Configuration descriptor will automatically be written to enable notification/indication based on the characteristic's properties.

subscribe(options: ServiceCharacteristicOptions): Promise<ResultSubscribe>

PARAMETERS
options: ServiceCharacteristicOptions

RETURN
returns: Promise<ResultSubscribe>
unsubscribe

Unsubscribe to a particular service's characteristic.

unsubscribe(options: ServiceCharacteristicOptions): Promise<ResultSubscribe>

PARAMETERS
options: ServiceCharacteristicOptions

RETURN
returns: Promise<ResultSubscribe>
write

Write a particular service's characteristic.

write(options: WriteOptions): Promise<ResultWrite>

PARAMETERS
options: WriteOptions

RETURN
returns: Promise<ResultWrite>
writeQ

Write Quick / Queue, use this method to quickly execute write without response commands when writing more than 20 bytes at a time. The data will automatically be split up into 20 bytes packets by default or you can increase that by setting chunkSize. A queue isn't used internally. Instead another call shouldn't be made until onCharacteristicWrite is called. This could be done at the Javascript layer, but the Javascript to API "bridge" must be crossed twice, which leads to some significant slow downs when milliseconds make a difference. For even better write throughput, use requestConnectionPriority('high') and mtu(SAME_VALUE_AS_CHUNK_SIZE_PARAM) as well.

Warnings

  • This is experimental. Test heavily before using in any production code.
  • To see a performance gain you should use this in combination with requestConnectionPriority('high') and mtu(MTU_VALUE) and then calling this method with type="noResponse" and set chunkSize to MTU_VALUE.
  • Only supports one call at a time. Don't execute back to back, use on multiple devices, or multiple characteristics.
writeQ(options: WriteqOptions): Promise<ResultWrite>

PARAMETERS
options: WriteqOptions

RETURN
returns: Promise<ResultWrite>
readDescriptor

Read a particular characterist's descriptor

read(options: ReadDescriptorOptions): Promise<ResultReadDescriptor>

PARAMETERS
options: ReadDescriptorOptions

RETURN
returns: Promise<ResultReadDescriptor>
writeDescriptor

Write a particular characteristic's descriptor. Use subscribe/unsubscribe, which will automatically enable/disable notification.

writeDescriptor(options: WriteDescriptorOptions): Promise<ResultWriteDescriptor>

PARAMETERS
options: WriteDescriptorOptions

RETURN
returns: Promise<ResultWriteDescriptor>
RSSI

Read RSSI of a connected device. RSSI is also returned with scanning.

rssi(options: Identifier): Promise<ResultRSSI>

PARAMETERS
options: Identifier

RETURN
returns: Promise<ResultRSSI>
MTU

Set MTU of a connected device.

mtu(options: MTUOptions): Promise<ResultMTU>

PARAMETERS
options: MTUOptions

RETURN
returns: Promise<ResultMTU>
requestConnectionPriority

Request a change in the connection priority to improve throughput when transfer large amounts of data via BLE.

requestConnectionPriority(options: RequestConnectionPriorityOptions): Promise<ResultRequestConnectionPriority>

PARAMETERS
options: RequestConnectionPriorityOptions

RETURN
returns: Promise<ResultRequestConnectionPriority>
isInitialized

Determine whether the adapter is initialized.

isInitialized(): Promise<ResultIsInitialized>

RETURN
returns: Promise<ResultIsInitialized>
isEnabled

Determine whether the adapter is enabled.

isEnabled(): Promise<ResultIsEnabled>

RETURN
returns: Promise<ResultIsEnabled>
isScanning

Determine whether the adapter is initialized.

isScanning(): Promise<ResultIsScanning>

RETURN
returns: Promise<ResultIsScanning>
isBonded

Determine whether the device is bonded or not, or error if not initialized.

isBonded(option: Identifier): Promise<ResultIsScanning>

PARAMETERS
option: Identifier

RETURN
returns: Promise<ResultIsScanning>
wasConnected

Determine whether the device was connected, or error if not initialized.

wasConnected(option: Identifier): Promise<ResultWasConnected>
option: Identifier

RETURN
returns: Promise<ResultWasConnected>
isConnected

Determine whether the device is connected, or error if not initialized or never connected to device.

isConnected(option: Identifier): Promise<ResultIsConnected>

PARAMETERS
option: Identifier

RETURN
returns: Promise<ResultIsConnected>
isDiscovered

Determine whether the device's characteristics and descriptors have been discovered, or error if not initialized or not connected to device. Note you can connect, discover and then disconnect. isDiscovered will return an error due to the device not being connected. But if you call reconnect and call isDiscovered again, it will return isDiscovered => true since the device stays discovered until calling close().

isDiscovered(option: Identifier): Promise<ResultisDiscovered>

PARAMETERS
option: Identifier

RETURN
returns: Promise<ResultisDiscovered>
hasPermission

Determine whether coarse location privileges are granted since scanning for unpaired devices requies it.

hasPermission(): Promise<ResultHasPermission>

RETURN
returns: Promise<ResultHasPermission>
requestPermission

Request coarse location privileges since scanning for unpaired devices requires it.

RequestPermission();

RETURN
returns: Promise<ResultRequestPermission>
isLocationEnabled

Determine if location services are enabled or not. Location Services are required to find devices.

isLocationEnabled(): Promise<ResultIsLocationEnabled>

RETURN
returns: Promise<ResultIsLocationEnabled>
requestLocation

Prompt location services settings pages. requestLocation property returns whether location services are enabled or disabled. Location Services are required to find devices.

requestLocation(): Promise<ResultRequestLocation>

RETURN
returns: Promise<ResultRequestLocation>
initializePeripheral

Initialize Bluetooth on the device. Must be called before anything else. Note that although Bluetooth initialization could initially be successful, there's no guarantee whether it will stay enabled. Each call checks whether Bluetooth is disabled. If it becomes disabled, the user must readd services, start advertising, etc again. If Bluetooth is disabled, you can request the user to enable it by setting the request property to true. The request property in the options argument is optional and defaults to false. The restoreKey property requires using the Bluetooth Peripheral background mode. This function should only be called once.

Additionally this where new events are delivered for read, write, and subscription requests.

initializePeripheral(options: InitializePeripheralOptions): Promise<ResultInitializePeripheral>

PARAMETERS
options: InitializePeripheralOptions

RETURN
returns: Promise<ResultInitializePeripheral>
addService

Add a service with characteristics and descriptors. If more than one service is added, add them sequentially.

addService(options: AddServiceOptions): Promise<ResultAddService>

PARAMETERS
options: AddServiceOptions

RETURN
returns: Promise<ResultAddService>
removeService

Remove a service.

removeService(options: RemoveServiceOptions): Promise<ResultRemoveService>

PARAMETERS
options: RemoveServiceOptions

RETURN
returns: Promise<ResultRemoveService>
removeAllServices

Remove all services.

removeAllService(): Promise<ResultRemoveAllServices>

RETURN
returns: Promise<ResultRemoveAllServices>
startAdvertising

Start advertising as a BLE device.

startAdvertising(options: StartAdvertisingOptions): Promise<ResultstartAdvertising>

PARAMETERS
options: StartAdvertisingOptions

RETURN
returns: Promise<ResultstartAdvertising>
stopAdvertising

Stop advertising.

stopAdvertising(): Promise<ResultStopAdvertising>

RETURN
returns: Promise<ResultStopAdvertising>
isAdvertising

Stop advertising.

isAdvertising(): Promise<ResultisAdvertising>

RETURN
returns: Promise<ResultisAdvertising>
respond

Respond to a read or write request.

respond(options: RespondOptions): Promise<Resultrespond>

PARAMETERS
options: RespondOptions

RETURN
returns: Promise<Resultrespond>
notify

Update a value for a subscription.

notify(options: NotifyOptions): Promise<ResultNotify>

PARAMETERS
options: NotifyOptions

RETURN
returns: Promise<ResultNotify>
encodedStringToBytes

Helper function to convert a base64 encoded string from a characteristic or descriptor value into a uint8Array object.

encodedStringToBytes(option: string): Promise<any>

PARAMETERS
option: string

RETURN
returns: Promise<any>
bytesToEncodedString

Helper function to convert a unit8Array to a base64 encoded string for a characteric or descriptor write.

bytesToEncodedString(option: string): Promise<any>

PARAMETERS
option: string

RETURN
returns: Promise<any>
stringToBytes

Helper function to convert a string to bytes.

stringToBytes(option: string): Promise<any>

PARAMETERS
option: string

RETURN
returns: Promise<any>
bytesToString

Helper function to convert bytes to a string.

bytesToString(option: string): Promise<any>

PARAMETERS
option: string

RETURN
returns: Promise<any>
Data Parsing Example
if (obj.status == "subscribedResult"){
        //Turn the base64 string into an array of unsigned 8bit integers
        var bytes = bluetoothle.encodedStringToBytes(obj.value);
        if (bytes.length === 0){
            return;
        }
    
        //NOTE: Follow along to understand how the parsing works
        //https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml
    
        //First byte provides instructions on what to do with the remaining bytes
        var flag = bytes[0];
    
        //Offset from beginning of the array
        var offset = 1;
    
        //If the first bit of the flag is set, the HR is in 16 bit form
        if ((flag & 0x01) == 1) {
            //Extract second and third bytes and convert to 16bit unsigned integer
            var u16bytesHr = bytes.buffer.slice(offset, offset + 2);
            var u16Hr = new Uint16Array(u16bytesHr)[0];
            //16 bits takes up 2 bytes, so increase offset by two
            offset += 2;
        }
        //Else the HR is in 8 bit form
        else {
            //Extract second byte and convert to 8bit unsigned integer
            var u8bytesHr = bytes.buffer.slice(offset, offset + 1);
            var u8Hr = new Uint8Array(u8bytesHr)[0];
    
            //Or I believe I could just do this: var u8Hr = u8bytesHr[offset]
    
            //8 bits takes up 1 byte, so increase offset by one
            offset += 1;
        }
    
        //NOTE: I'm ignoring the second and third bit because I'm not interested in the sensor contact, and it doesn't affect the offset
    
        //If the fourth bit is set, increase the offset to skip over the energy expended information
        if ((flag & 0x08) == 8) {
            offset += 2;
        }
    
        //If the fifth bit is set, get the RR interval(s)
        if ((flag & 0x10) == 16) {
            //Number of rr intervals
            var rrCount = (bytes.length - offset) / 2;
    
            for (var i = rrCount - 1; i >= 0; i--)
            {
                //Cast to 16 bit unsigned int
                var u16bytesRr = bytes.buffer.slice(offset, offset + 2);
                var u16Rr = new Uint16Array(u16bytesRr)[0];
                //Increase offset
                offset += 2;
            }
        }
    }
Sample: Discover and interact with Bluetooth LE devices

We'll build an app that lets you discover Bluetooth Low Energy (LE) devices that are around you, connect to a one, and then look at all of the information that you can obtain from that device such as signal strength, supported services, battery level and more.

You could use an app like this to find a lost device or to debug a device that isn't behaving as expected.

Our code performs these tasks:

  • Initialize the BluetoothLE adapter;
  • Scan for devices;
  • Connect to a device;
  • Show device services;
  • Show service characteristics.

Also, we'll use a Promise object for each of the Bluetooth LE functions. If you're unfamiliar with promises, it's just a cleaner way to organize asynchronous functions.

If you're ready to go, let's start.

Initialize the Bluetooth adapter

The BluetoothLE API uses an adapter to interact with each device's Bluetooth LE capability so you'll have to initialize it. To do that, call the initialize function.

document.addEventListener('deviceready', function () {
    
        new Promise(function (resolve) {
    
            bluetoothle.initialize(resolve, { request: true, statusReceiver: false });
    
        }).then(initializeSuccess, handleError);
    
    });

If your call succeeds, use result.status property to find out if Bluetooth is enabled on their device.

function initializeSuccess(result) {
    
        if (result.status === "enabled") {
    
            log("Bluetooth is enabled.");
            log(result);
        }
    
        else {
    
            document.getElementById("start-scan").disabled = true;
    
            log("Bluetooth is not enabled:", "status");
            log(result, "status");
        }
    }

If your call fails, you can find out why by using the error object. This code shows one way to do that. We'll re-use this function throughout this example.

function handleError(error) {
    
        var msg;
    
        if (error.error && error.message) {
    
            var errorItems = [];
    
            if (error.service) {
    
                errorItems.push("service: " + (uuids[error.service] || error.service));
            }
    
            if (error.characteristic) {
    
                errorItems.push("characteristic: " + (uuids[error.characteristic] || error.characteristic));
            }
    
            msg = "Error on " + error.error + ": " + error.message + (errorItems.length && (" (" + errorItems.join(", ") + ")"));
        }
    
        else {
    
            msg = error;
        }
    
        log(msg, "error");
    
        if (error.error === "read" && error.service && error.characteristic) {
    
            reportValue(error.service, error.characteristic, "Error: " + error.message);
        }
    }

The block of code above calls a function named log. It's just a helper function that shows one of many ways to show output to the users.

function log(msg, level) {
    
        level = level || "log";
    
        if (typeof msg === "object") {
    
            msg = JSON.stringify(msg, null, "  ");
        }
    
        console.log(msg);
    
        if (level === "status" || level === "error") {
    
            var msgDiv = document.createElement("div");
            msgDiv.textContent = msg;
    
            if (level === "error") {
    
                msgDiv.style.color = "red";
            }
    
            msgDiv.style.padding = "5px 0";
            msgDiv.style.borderBottom = "rgb(192,192,192) solid 1px";
            document.getElementById("output").appendChild(msgDiv);
        }
    }
Scan for devices

Call the startScan function to find Bluetooth LE devices that are around you.

var foundDevices = [];
    
    function startScan() {
    
        log("Starting scan for devices...", "status");
    
        foundDevices = [];
    
        document.getElementById("devices").innerHTML = "";
        document.getElementById("services").innerHTML = "";
        document.getElementById("output").innerHTML = "";
    
        bluetoothle.startScan(startScanSuccess, handleError, { services: [] });
    }

Every time that a Bluetooth LE device is detected, the startScanSuccess callback function is called. In that function, use the result object to get information about the device.

In this example, we'll add each result object to an array. We use this array to detect duplicates. We'll compare the MAC address of the current result to all result objects in the array before we add it.

After we've determined that the detected device is unique, we'll call a helper function named addDevice to show that device as a button on the screen. We'll take a look at that function shortly.

function startScanSuccess(result) {
    
        log("startScanSuccess(" + result.status + ")");
    
        if (result.status === "scanStarted") {
    
            log("Scanning for devices (will continue to scan until you select a device)...", "status");
        }
        else if (result.status === "scanResult") {
    
            if (!foundDevices.some(function (device) {
    
                return device.address === result.address;
    
            })) {
    
                log('FOUND DEVICE:');
                log(result);
                foundDevices.push(result);
                addDevice(result.name, result.address);
            }
        }
    }

If the function succeeds, we get an array of result objects.

In this example, we iterate through that array and then call a helper function named addDevice to show that device as a button on the screen.

function retrieveConnectedSuccess(result) {
    
        log("retrieveConnectedSuccess()");
        log(result);
    
        result.forEach(function (device) {
    
            addDevice(device.name, device.address);
    
        });
    }

This helper function adds a button for each available device. The click event of each button calls a helper function named connect. We'll define that function in the next section.

function addDevice(name, address) {
    
        var button = document.createElement("button");
        button.style.width = "100%";
        button.style.padding = "10px";
        button.style.fontSize = "16px";
        button.textContent = name + ": " + address;
    
        button.addEventListener("click", function () {
    
            document.getElementById("services").innerHTML = "";
            connect(address);
        });
    
        document.getElementById("devices").appendChild(button);
    }
Connect to a device

If the user clicks a button for any of the devices, the connect helper function is called. In that function, we'll call the connect function of the Bluetooth LE API.

function connect(address) {
    
        log('Connecting to device: ' + address + "...", "status");
    
        new Promise(function (resolve, reject) {
    
            bluetoothle.connect(resolve, reject, { address: address });
    
        }).then(connectSuccess, handleError);
    }
    
    function stopScan() {
    
        new Promise(function (resolve, reject) {
    
            bluetoothle.stopScan(resolve, reject);
    
        }).then(stopScanSuccess, handleError);
    }
    
    function stopScanSuccess() {
    
        if (!foundDevices.length) {
    
            log("NO DEVICES FOUND");
        }
        else {
    
            log("Found " + foundDevices.length + " devices.", "status");
        }
    }

If the call to the connect function succeeds, use the result.status property to find out if you've managed to connect.

In this example, if we're connected to the Bluethooth LE device, we'll call a helper function named getDeviceServices to get information about that device's services.

function connectSuccess(result) {
    
        log("- " + result.status);
    
        if (result.status === "connected") {
    
            getDeviceServices(result.address);
        }
        else if (result.status === "disconnected") {
    
            log("Disconnected from device: " + result.address, "status");
        }
    }
Get device services

Now we'll take a look at that helper function named getDeviceServices that we referred to above.

Call the discover function to find the services that are available on the Bluetooth LE device.

In this example, we'll call a helper function named addService for each service in that array.

That function will show all of the characteristics of the service. We'll look at that function a bit later.

function discoverSuccess(result) {
    
        log("Discover returned with status: " + result.status);
    
        if (result.status === "discovered") {
    
        // Create a chain of read promises so we don't try to read a property until we've finished
            // reading the previous property.
    
        var readSequence = result.services.reduce(function (sequence, service) {
    
            return sequence.then(function () {
    
                return addService(result.address, service.uuid, service.characteristics);
            });
    
        }, Promise.resolve());
    
        // Once we're done reading all the values, disconnect
        readSequence.then(function () {
    
            new Promise(function (resolve, reject) {
    
                bluetoothle.disconnect(resolve, reject,
                    { address: result.address });
    
            }).then(connectSuccess, handleError);
    
        });
    
        }
    }
Show services and characteristics in an app page

The addService helper method shows the details of each service and their characteristics. To show each characteristic, this function calls the read function.

The array of uuid values that is used in this example comes from a helper js file that contains the unique identifiers of all known characteristics. That file does not appear in this example, but the values in it come from the Bluetooth web site.

function addService(address, serviceUuid, characteristics) {
    
        log('Adding service ' + serviceUuid + '; characteristics:');
        log(characteristics);
    
        var readSequence = Promise.resolve();
    
        var wrapperDiv = document.createElement("div");
        wrapperDiv.className = "service-wrapper";
    
        var serviceDiv = document.createElement("div");
        serviceDiv.className = "service";
        serviceDiv.textContent = uuids[serviceUuid] || serviceUuid;
        wrapperDiv.appendChild(serviceDiv);
    
        characteristics.forEach(function (characteristic) {
    
            var characteristicDiv = document.createElement("div");
            characteristicDiv.className = "characteristic";
    
            var characteristicNameSpan = document.createElement("span");
            characteristicNameSpan.textContent = (uuids[characteristic.uuid] || characteristic.uuid) + ":";
            characteristicDiv.appendChild(characteristicNameSpan);
    
            characteristicDiv.appendChild(document.createElement("br"));
    
            var characteristicValueSpan = document.createElement("span");
            characteristicValueSpan.id = serviceUuid + "." + characteristic.uuid;
            characteristicValueSpan.style.color = "blue";
            characteristicDiv.appendChild(characteristicValueSpan);
    
            wrapperDiv.appendChild(characteristicDiv);
    
            readSequence = readSequence.then(function () {
    
                return new Promise(function (resolve, reject) {
    
                    bluetoothle.read(resolve, reject,
                        { address: address, service: serviceUuid, characteristic: characteristic.uuid });
    
                }).then(readSuccess, handleError);
    
            });
        });
    
        document.getElementById("services").appendChild(wrapperDiv);
    
        return readSequence;
    }

If the call to the read function succeeds, we'll write the value of that characteristic to the app page.

function readSuccess(result) {
    
        log("readSuccess():");
        log(result);
    
        if (result.status === "read") {
    
            reportValue(result.service, result.characteristic, window.atob(result.value));
        }
    }
    
    function reportValue(serviceUuid, characteristicUuid, value) {
    
        document.getElementById(serviceUuid + "." + characteristicUuid).textContent = value;
    }

Interfaces

InitializeOptions
InitializeOptions {
    // Should user be prompted to enable Bluetooth
    "request" ? : boolean,
    // Should change in Bluetooth status notifications be sent
    "statusReceiver": boolean,
    // A unique string to identify your app. Bluetooth Central background mode is required to use this, but background mode doesn't seem to require specifying the restoreKey
    "restoreKey" : "bluetoothleplugin"
}
StartScanOptions
StartScanOptions {
    // An array of service IDs to filter the retrieval by. If no service IDs are specified, no devices will be returned
    "services": [
        "180D",
        "180F"
    ],
    // Defaults to Low Power
    "scanMode": bluetoothle.SCAN_MODE_LOW_LATENCY,
    // Defaults to Aggressive
    "matchMode": bluetoothle.MATCH_MODE_AGGRESSIVE,
    // Defaults to One Advertisement
    "matchNum": bluetoothle.MATCH_NUM_MAX_ADVERTISEMENT,
    // Defaults to All Matches
    "callbackType": bluetoothle.CALLBACK_TYPE_ALL_MATCHES,
}
RetrieveConnectedOptions
RetrieveConnectedOptions {
    // An array of service IDs to filter the retrieval by. If no service IDs are specified, no devices will be returned
    "services": [
        "180D",
        "180F"
    ]
}
Identifier
Identifier {
    // The address/identifier provided by the scan's return object
    "address": string
}
MTUOptions
MTUOptions {
    // The address/identifier provided by the scan's return object
    "address": string,
    // Integer value mtu should be set to
    "mtu": int
}
RequestConnectionPriorityOptions
RequestConnectionPriorityOptions {
    // The address/identifier provided by the scan's return object
    "address": string,
    // Integer value mtu should be set to
    "connectionPriority": connectionPriority
}
ConnectOptions
ConnectOptions {
    // The address/identifier provided by the scan's return object
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63",
    // Automatically connect as soon as the remote device becomes available
    "autoConnect": boolean,
    // Mode of transport
    "transport": transportMode
}
DiscoverOptions
DiscoverOptions {
    // The address/identifier provided by the scan's return object
    "address": string,
    // Force the device to re-discover services, instead of relying on cache from previous discovery
    "clearCache": boolean
}
ServiceCharacteristicOptions
ServiceCharacteristicOptions {
    // The address/identifier provided by the scan's return object
    "address": string,
    // The service's UUID
    "service": string,
    // The characteristic's UUID
    "characteristic": string
}
WriteOptions
WriteOptions {
    // The address/identifier provided by the scan's return object
    "address": string,
    // The service's UUID
    "service": string,
    // Base64 encoded string
    "value": string,
    // Set to "noResponse" to enable write without response, all other values will write normally
    "type": string
}
ReadDescriptorOptions
ReadDescriptorOptions {
    // The address/identifier provided by the scan's return object
    "address": string,
    // The service's UUID
    "service": string,
    // The characteristic's ID
    "characteristic": string,
    // The descriptor's ID
    "descriptor": string
}
WriteDescriptorOptions
WriteDescriptorOptions {
    // The address/identifier provided by the scan's return object
    "address": string,
    // The service's UUID
    "service": string,
    // The characteristic's UUID
    "characteristic": string,
    // The descriptor's ID
    "descriptor": string,
    // Base64 encoded string
    "value": string,
    // Set to "noResponse" to enable write without response, all other values will write normally
    "type": string
}
ResultInitialize
ResultInitialize {
    // status => enabled = Bluetooth is enabled
    // status => disabled = Bluetooth is disabled
    "status": "enabled"
}
ResultGetAdapterInfo
ResultGetAdapterInfo {
    // the adapters's display name
    "name": string
    // the adapter's address
    "address": string
    // true if the adapter was initialized, otherwise false
    "isInitialized": boolean
    // true if the adapter was enabled, otherwise false
    "isEnabled": boolean
    // true if the adapter is currently scanning, otherwise false
    "isScanning": boolean
    // true if the adapter is in discoverable mode, otherwise false (currently largely false)
    "isDiscoverable": boolean
}
ResultStartScan
ResultStartScan {
    "status": "scanStarted"
}
// OR
ResultStartScan{
    "status": "scanResult",
    "advertisement": "awArG05L",
    "rssi": -58,
    "name": "Polar H7 3B321015",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63"
}
ResultStopScan
ResultStopScan {
    "status": "scanStopped"
}
resultRetrieveConnected
{
    "services": [
        "180D",
        "180F"
    ]
}
ResultObject
ResultObject {
    "name": "Hello World",
    "address": "5A:94:4B:38:B3:FD",
    "status": "statusConnection"
}
ResultDiscover
ResultDiscover {
"address": "00:22:D0:3B:32:10",
"status": "discovered",
"services": [{
    "characteristics": [{
        "descriptors": [

        ],
        "uuid": "2a00", // [Device Name](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.device_name.xml)
        "properties": {
            "write": true,
            "writeWithoutResponse": true,
            "read": true
        }
    },
    {
        "descriptors": [

        ],
        "uuid": "2a01", // [Appearance](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml)
        "properties": {
            "read": true
        }
    },
    {
        "descriptors": [

        ],
        "uuid": "2a02", // [Peripheral Privacy Flag](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.peripheral_privacy_flag.xml)
        "properties": {
            "read": true
        }
    },
    {
        "descriptors": [

        ],
        "uuid": "2a03", // [Reconnection Address](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.reconnection_address.xml)
        "properties": {
            "write": true
        }
    },
    {
        "descriptors": [

        ],
        "uuid": "2a04", // [Pheripheral Preferred Connection Parameters](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters.xml)
        "properties": {
            "read": true
        }
    }],
    "uuid": "1800" // [Generic Access](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.generic_access.xml)
},
{
    "characteristics": [{
        "descriptors": [
            {
            "uuid": "2902"
            }
        ],
        "uuid": "2a05", // [Service Changed](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gatt.service_changed.xml)
        "properties": {
            "indicate": true
        }
    }],
    "uuid": "1801" // [Generic Attribute](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.generic_attribute.xml)
},
    {
    "characteristics": [{
        "descriptors": [
            {
            "uuid": "2902"
            }
        ],
        "uuid": "2a37", // [Heart Rate Measurement](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml)
        "properties": {
            "notify": true
        }
    },
    {
        "descriptors": [

        ],
        "uuid": "2a38", // [Body Sensor Location](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.body_sensor_location.xml)
        "properties": {
            "read": true
        }
        }
    ],
    "uuid": "180d" // [Heart Rate](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.heart_rate.xml)
    },
    {
    "characteristics": [
        {
        "descriptors": [

        ],
        "uuid": "2a23", // [System ID](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.system_id.xml)
        "properties": {
            "read": true
        }
        },
        {
        "descriptors": [

        ],
        "uuid": "2a24", // [Model Number String](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.model_number_string.xml)
        "properties": {
            "read": true
        }
        },
        {
        "descriptors": [

        ],
        "uuid": "2a25", // [Serial Number String](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.serial_number_string.xml)
        "properties": {
            "read": true
        }
        },
        {
        "descriptors": [

        ],
        "uuid": "2a26", // [Firmware Revision String](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.firmware_revision_string.xml)
        "properties": {
            "read": true
        }
        },
        {
        "descriptors": [

        ],
        "uuid": "2a27", // [hardware Revision String](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.hardware_revision_string.xml)
        "properties": {
            "read": true
        }
        },
        {
        "descriptors": [

        ],
        "uuid": "2a28", // [Software Revision String](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.software_revision_string.xml)
        "properties": {
            "read": true
        }
        },
        {
        "descriptors": [

        ],
        "uuid": "2a29", // [Manufacturer Name String](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.manufacturer_name_string.xml)
        "properties": {
            "read": true
        }
        }
    ],
    "uuid": "180a" // [Device Information](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.device_information.xml)
    },
    {
    "characteristics": [
        {
        "descriptors": [

        ],
        "uuid": "2a19", // [Battery Level](https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.battery_level.xml)
        "properties": {
            "read": true
        }
        }
    ],
    "uuid": "180f" // [Battery Service](https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.battery_service.xml)
    },
    {
    "characteristics": [
        {
        "descriptors": [

        ],
        "uuid": "6217ff4c-c8ec-b1fb-1380-3ad986708e2d",
        "properties": {
            "read": true
        }
        },
        {
        "descriptors": [
            {
            "uuid": "2902"
            }
        ],
        "uuid": "6217ff4d-91bb-91d0-7e2a-7cd3bda8a1f3",
        "properties": {
            "write": true,
            "indicate": true
        }
        }
    ],
    "uuid": "6217ff4b-fb31-1140-ad5a-a45545d7ecf3"
    }
],
"name": "Polar H7 3B321015"
}
ResultRead
ResultRead {
    "status": "read",
    "value": "UmVhZCBIZWxsbyBXb3JsZA==", //Read Hello World
    "characteristic": "2a38",
    "name": "Polar H7 3B321015",
    "service": "180d",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63"
}
ResultSubscribe
ResultSubscribe {
    "status": "subscribed",
    "characteristic": "2a37",
    "name": "Polar H7 3B321015",
    "service": "180d",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63"
}
// OR
ResultSubscribe {
    "status": "subscribedResult",
    "value": "U3Vic2NyaWJlIEhlbGxvIFdvcmxk", //Subscribe Hello World
    "characteristic": "2a37",
    "name": "Polar H7 3B321015",
    "service": "180d",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63"
}
ResultWrite
ResultWrite {
    "status": "subscribed",
    "service": string,
    "characteristic": "2a37",
    "value": "Polar H7 3B321015",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63"
}
ResultUnsubscribe
ResultUnsubscribe {
    "status": "unsubscribed",
    "characteristic": "2a37",
    "name": "Polar H7 3B321015",
    "service": "180d",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63"
}
ResultReadDescriptor
ResultReadDescriptor {
    "status": "readDescriptor",
    "service": "180d",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63",
    "characteristic": "2a37",
    "value": "AQAAAAAAAAA=",
    "name": "Polar H7 3B321015",
    "descriptor": "2902"
}
ResultWriteDescriptor
ResultWriteDescriptor {
    "status": "readDescriptor",
    "service": "180d",
    "characteristic": "2a37",
    "descriptor": "2902",
    "value": "AQAAAAAAAAA=",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63"
}
ResultRSSI
ResultRSSI {
    "status": "rssi",
    "rssi": -50,
    "name": "Polar H7 3B321015",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63"
}
ResultMTU
resultMTU {
    "status": "mtu",
    "mtu": 50,
    "name": "Polar H7 3B321015",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63"
}
ResultRequestConnectionPriority
ResultRequestConnectionPriority {
    "name": "Polar H7 3B321015",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63",
    "status" : "statusConnection"
}
ResultIsInitialized
ResultIsInitialized {
    "isInitialized": true
}
ResultIsEnabled
ResultIsEnabled {
    "isEnabled": true
}
ResultIsScanning
ResultIsScanning {
    "isScanning": false
}
ResultIsBonded
ResultIsBonded {
    "name": "Polar H7 3B321015",
    "address": "5A:94:4B:38:B3:FD",
    "isBonded": false
}
ResultwasConnected
ResultwasConnected {
    "name": "Polar H7 3B321015",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63",
    "wasConnected": false
}
ResultIsConnected
ResultIsConnected {
    "name": "Polar H7 3B321015",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63",
    "isConnected": false
}
ResultisDiscovered
ResultisDiscovered {
    "name": "Polar H7 3B321015",
    "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63",
    "isDiscovered": false
}
ResultHasPermission
ResultHasPermission {
    "hasPermission": true
}
ResultRequestPermission
ResultRequestPermission {
    "requestPermission": true
}
ResultIsLocationEnabled
ResultIsLocationEnabled {
    "isLocationEnabled": true
}
ResultRequestLocation
ResultRequestLocation {
    "requestLocation": true
}
InitializePeripheralOptions
InitializePeripheralOptions {
    // Should user be prompted to enable Bluetooth
    "request": boolean,
    // A unique string to identify your app. Bluetooth Peripheral background mode is required to use this, but background mode doesn't seem to require specifying the restoreKey
    "restoreKey": string
}
ResultInitializePeripheral
ResultInitializePeripheral {
    // status => enabled = Bluetooth is enabled
    // status => disabled = Bluetooth is disabled
    // status => readRequested = Respond to a read request with respond(). Characteristic or Descriptor
    // status => writeRequested = Respond to a write request with respond(). Characteristic or Descriptor
    // status => subscribed = Subscription started request, use notify() to send new data
    // status => unsubscribed = Subscription ended request, stop sending data
    // status => notificationSent = Notification has been sent
    // status => connected = A device has connected
    // status => disconnected = A device has disconnected
    // status => mtuChanged = MTU has changed for device
    "status": // See the possible results above for the status property
}
Enable/Disable
{
    // Bluetooth is enabled/disabled
    "status": string
}
ReadRequested
ReadRequested {
    // Respond to a read request with respond()
    "status": string,
    "address": string,
    "service": string,
    "characteristic": string,
    "requestId": int,
    "offset": int
}
WriteRequested
WriteRequested {
    // Respond to a write request with respond()
    "status": string,
    "address": string,
    "service": string,
    "characteristic": string,
    "requestId": int,
    "value": string,
    "offset": int
}
Subscribed/Unsubscribed
{
        // Subscription started/ended request
    "status": string,
    "address": string,
    "service": string,
    "characteristic": string
}
Connected/Disconnected
{
    // A device has connected/disconnected
    "status": string,
    "address": string
}
MTUChanged
MTUChanged {
    // MTU has changed for device
    "status": string,
    "address": string,
    "mtu": int
}
NotificationSent
NotificationSent {
    // Notification has been sent
    "status": string
}
AddServiceOptions
AddServiceOptions {
    // A service UUID
    "service": string,
    // An object of characteristics data as shown below
    characteristics: [{
        uuid: string,
        permissions: {
            read: boolean,
            write: boolean,
            //readEncryptionRequired: boolean,
            //writeEncryptionRequired: boolean,
        },
        properties : {
            read: boolean,
            writeWithoutResponse: boolean,
            write: boolean,
            notify: boolean,
            indicate: boolean,
            //authenticatedSignedWrites: boolean,
            //notifyEncryptionRequired: boolean,
            //indicateEncryptionRequired: boolean
        }
    }]
}
ResultAddService
ResultAddService {
    "service": string,
    "status": string
}
RemoveServiceOptions
{
    // A service UUID
    "service": string
}
ResultRemoveService
ResultRemoveService {
    "service": string,
    "status": string
}
ResultRemoveAllServices
ResultRemoveAllServices {
    "status": string
}
StartAdvertisingOptions
StartAdvertisingOptions {
    "service": string,
    "name": string,
}
ResultStartAdvertising
ResultStartAdvertising {
    "status": string
}
ResultStoptAdvertising
ResultStoptAdvertising {
    "status": string
}
ResultisAdvertising
ResultisAdvertising {
    "isAdvertising": boolean
}
RespondOptions
RespondOptions {
    "requestId": requestID
    "value": string
}
ResultRespond
ResultRespond {
    "status": string
}
NotifyOptions
NotifyOptions {
    "service": string,
    "characteristic": string,
    "value": string
}
ResultNotify
ResultNotify {
    "status": string
    "sent": boolean
}

Enumerations

StartScanStatus

  • "scanStarted"
  • "scanResult"

TransportMode

  • "Auto": 0
  • "Prefer BR/EDR": 1
  • "Prefer LE": 2

StatusConnection

ConnectionPriority

  • "low"
  • "balanced"
  • "high"

Constraints

  • SCAN_MODE_OPPORTUNISTIC: -1
  • SCAN_MODE_LOW_POWER: 0
  • SCAN_MODE_BALANCED: 1
  • SCAN_MODE_LOW_LATENCY: 2
  • MATCH_NUM_ONE_ADVERTISEMENT: 1
  • MATCH_NUM_FEW_ADVERTISEMENT: 2
  • MATCH_NUM_MAX_ADVERTISEMENT: 3
  • MATCH_MODE_AGGRESSIVE: 1
  • MATCH_MODE_STICKY: 2
  • CALLBACK_TYPE_ALL_MATCHES: 1
  • CALLBACK_TYPE_FIRST_MATCH: 2
  • CALLBACK_TYPE_MATCH_LOST: 4

RequestID

  • 0: for read
  • 1: for write