This API allows you to interact with Bluetooth LE devices.
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>
enable(): Promise<any>
Enable Bluetooth on the device
disable(): Promise<any>
Disable Bluetooth on the device.
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>
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>
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>
Retrieved paired Bluetooth LE devices.
retrieveConnected(options: RetrieveConnectedOptions): Promise<ResultRetrieveConnected>
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>
Unbond with a device. The device doesn't need to be connected to initiate bonding.
unbond(option: Identifier): Promise<ResultObject>
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>
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>
Disconnect from a Bluetooth LE device. It's simpler to just call close().
disconnect(option: Identifier): Promise<ResultObject>
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>
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>
Read a particular service's characteristic once.
read(options: ServiceCharacteristicOptions): Promise<ResultRead>
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>
Unsubscribe to a particular service's characteristic.
unsubscribe(options: ServiceCharacteristicOptions): Promise<ResultSubscribe>
Write a particular service's characteristic.
write(options: WriteOptions): Promise<ResultWrite>
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
writeQ(options: WriteqOptions): Promise<ResultWrite>
Read a particular characterist's descriptor
read(options: ReadDescriptorOptions): Promise<ResultReadDescriptor>
Write a particular characteristic's descriptor. Use subscribe/unsubscribe, which will automatically enable/disable notification.
writeDescriptor(options: WriteDescriptorOptions): Promise<ResultWriteDescriptor>
Read RSSI of a connected device. RSSI is also returned with scanning.
rssi(options: Identifier): Promise<ResultRSSI>
Set MTU of a connected device.
mtu(options: MTUOptions): Promise<ResultMTU>
Request a change in the connection priority to improve throughput when transfer large amounts of data via BLE.
requestConnectionPriority(options: RequestConnectionPriorityOptions): Promise<ResultRequestConnectionPriority>
Determine whether the adapter is initialized.
isInitialized(): Promise<ResultIsInitialized>
Determine whether the adapter is enabled.
isEnabled(): Promise<ResultIsEnabled>
Determine whether the adapter is initialized.
isScanning(): Promise<ResultIsScanning>
Determine whether the device is bonded or not, or error if not initialized.
isBonded(option: Identifier): Promise<ResultIsScanning>
Determine whether the device was connected, or error if not initialized.
wasConnected(option: Identifier): Promise<ResultWasConnected>
Determine whether the device is connected, or error if not initialized or never connected to device.
isConnected(option: Identifier): Promise<ResultIsConnected>
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>
Determine whether coarse location privileges are granted since scanning for unpaired devices requies it.
hasPermission(): Promise<ResultHasPermission>
Request coarse location privileges since scanning for unpaired devices requires it.
RequestPermission();
Determine if location services are enabled or not. Location Services are required to find devices.
isLocationEnabled(): Promise<ResultIsLocationEnabled>
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>
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>
Add a service with characteristics and descriptors. If more than one service is added, add them sequentially.
addService(options: AddServiceOptions): Promise<ResultAddService>
Remove a service.
removeService(options: RemoveServiceOptions): Promise<ResultRemoveService>
Remove all services.
removeAllService(): Promise<ResultRemoveAllServices>
Start advertising as a BLE device.
startAdvertising(options: StartAdvertisingOptions): Promise<ResultstartAdvertising>
Stop advertising.
stopAdvertising(): Promise<ResultStopAdvertising>
Stop advertising.
isAdvertising(): Promise<ResultisAdvertising>
Respond to a read or write request.
respond(options: RespondOptions): Promise<Resultrespond>
Update a value for a subscription.
notify(options: NotifyOptions): Promise<ResultNotify>
Helper function to convert a base64 encoded string from a characteristic or descriptor value into a uint8Array object.
encodedStringToBytes(option: string): Promise<any>
Helper function to convert a unit8Array to a base64 encoded string for a characteric or descriptor write.
bytesToEncodedString(option: string): Promise<any>
Helper function to convert a string to bytes.
stringToBytes(option: string): Promise<any>
Helper function to convert bytes to a string.
bytesToString(option: string): Promise<any>
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;
}
}
}
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:
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.
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);
}
}
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);
}
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");
}
}
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);
});
}
}
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;
}
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 { // 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 {
// 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 {
// The address/identifier provided by the scan's return object
"address": string
}
MTUOptions { // The address/identifier provided by the scan's return object "address": string, // Integer value mtu should be set to "mtu": int }
RequestConnectionPriorityOptions { // The address/identifier provided by the scan's return object "address": string, // Integer value mtu should be set to "connectionPriority": connectionPriority }
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 { // 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 { // 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 { // 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 { // 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 { // 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 { // status => enabled = Bluetooth is enabled // status => disabled = Bluetooth is disabled "status": "enabled" }
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 { "status": "scanStarted" } // OR ResultStartScan{ "status": "scanResult", "advertisement": "awArG05L", "rssi": -58, "name": "Polar H7 3B321015", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63" }
ResultStopScan { "status": "scanStopped" }
{ "services": [ "180D", "180F" ] }
ResultObject { "name": "Hello World", "address": "5A:94:4B:38:B3:FD", "status": "statusConnection" }
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 { "status": "read", "value": "UmVhZCBIZWxsbyBXb3JsZA==", //Read Hello World "characteristic": "2a38", "name": "Polar H7 3B321015", "service": "180d", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63" }
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 { "status": "subscribed", "service": string, "characteristic": "2a37", "value": "Polar H7 3B321015", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63" }
ResultUnsubscribe { "status": "unsubscribed", "characteristic": "2a37", "name": "Polar H7 3B321015", "service": "180d", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63" }
ResultReadDescriptor { "status": "readDescriptor", "service": "180d", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63", "characteristic": "2a37", "value": "AQAAAAAAAAA=", "name": "Polar H7 3B321015", "descriptor": "2902" }
ResultWriteDescriptor { "status": "readDescriptor", "service": "180d", "characteristic": "2a37", "descriptor": "2902", "value": "AQAAAAAAAAA=", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63" }
ResultRSSI { "status": "rssi", "rssi": -50, "name": "Polar H7 3B321015", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63" }
resultMTU { "status": "mtu", "mtu": 50, "name": "Polar H7 3B321015", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63" }
ResultRequestConnectionPriority { "name": "Polar H7 3B321015", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63", "status" : "statusConnection" }
ResultIsInitialized { "isInitialized": true }
ResultIsEnabled { "isEnabled": true }
ResultIsScanning { "isScanning": false }
ResultIsBonded { "name": "Polar H7 3B321015", "address": "5A:94:4B:38:B3:FD", "isBonded": false }
ResultwasConnected { "name": "Polar H7 3B321015", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63", "wasConnected": false }
ResultIsConnected { "name": "Polar H7 3B321015", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63", "isConnected": false }
ResultisDiscovered { "name": "Polar H7 3B321015", "address": "ECC037FD-72AE-AFC5-9213-CA785B3B5C63", "isDiscovered": false }
ResultHasPermission { "hasPermission": true }
ResultRequestPermission { "requestPermission": true }
ResultIsLocationEnabled { "isLocationEnabled": true }
ResultRequestLocation { "requestLocation": true }
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 { // 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 }
{
// Bluetooth is enabled/disabled
"status": string
}
ReadRequested {
// Respond to a read request with respond()
"status": string,
"address": string,
"service": string,
"characteristic": string,
"requestId": int,
"offset": int
}
WriteRequested {
// Respond to a write request with respond()
"status": string,
"address": string,
"service": string,
"characteristic": string,
"requestId": int,
"value": string,
"offset": int
}
{
// Subscription started/ended request
"status": string,
"address": string,
"service": string,
"characteristic": string
}
{
// A device has connected/disconnected
"status": string,
"address": string
}
MTUChanged {
// MTU has changed for device
"status": string,
"address": string,
"mtu": int
}
NotificationSent {
// Notification has been sent
"status": string
}
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 { "service": string, "status": string }
{
// A service UUID
"service": string
}
ResultRemoveService { "service": string, "status": string }
ResultRemoveAllServices { "status": string }
StartAdvertisingOptions { "service": string, "name": string, }
ResultStartAdvertising { "status": string }
ResultStoptAdvertising { "status": string }
ResultisAdvertising { "isAdvertising": boolean }
RespondOptions { "requestId": requestID "value": string }
ResultRespond { "status": string }
NotifyOptions { "service": string, "characteristic": string, "value": string }
ResultNotify { "status": string "sent": boolean }