BLE GATT

The BLE GATT API allows you to use webOS TV's BLE GATT client function. For devices that adopt webOS TV 24 or higher, you can use the BLE GATT API.

To use the BLE GATT API, your app should acquire user permission. If the app calls the API without the permission, a pop up to get user permission will appear, and only after the user choose to give the permission, the app can use the BLE GATT API. Once acquired, the permission of the app remains valid until the user deletes it and no pop up for getting permission will appear till then. If the user explicitly deletes the permission, the app cannot use the BLE GATT API, and only after the user gives the permission again, it can use the API again.

The operations of the API, introduced in this document, are verified with an Android mobile phone working as a GATT server, and the Android app for functioning as a GATT server is BLE Tool available on Google Play.

See BLE GATT API Reference for how to use each method of the BLE GATT API.

Note

This API is available on webOS TV 24 or higher.

Overview

This guide describes an example on how a TV device can work as a GATT client. If any methods explained here on this document are called on a webOS TV platform that does not support the API, `returnValue` will be returned as false with `errorText` as `Unknown method`.

// When called BLE APIs from a webOS version that is not supported

var isEnabledHandle = webOS.service.request(
  "luna://com.webos.service.blegatt",
  {
    method: "isEnabled",
    parameters: {
      subscribe: true,
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
    },
    onFailure: function (inError) {
      // "errorCode": -1,
      // "errorText": "Unknown method "isEnabled" for category "/""
      console.log("[" + inError.errorCode + "]: " + inError.errorText); // To-Do something
      return;
    },
  }
);

While there is a problem in connecting the Bluetooth hardware or the Bluetooth hardware is not found, if any methods explained here on this document are called, `returnValue` will be returned as false with `errorText` saying `Bluetooth adapter is not available`.

// If there is a problem with the connection of the Bluetooth hardware or the
// hardware is missing
var isEnabledHandle = webOS.service.request(
  "luna://com.webos.service.blegatt",
  {
    method: "isEnabled",
    parameters: {
      subscribe: true,
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
    },
    onFailure: function (inError) {
      // "errorCode": 100,
      // "errorText": " Bluetooth adapter is not available"
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
      return;
    },
  }
);

Also, maintaining the BLE connection and all other BLE-related operations, such as read, write, and notify, can be performed while the app is in the foreground. If the app goes into the background or gets terminated, all the BLE connections will be lost. If the app goes back into the foreground or is newly launched, the following procedure in this section should be performed again.

Check Bluetooth adapter

Call the isEnabled method to check if Bluetooth is enabled. If the `isEabled` return of this method is false, it means the Bluetooth function of the TV device is currently unavailable. The `isEnabled` method supports subscription, and whenever there is a change to the availability of the Bluetooth function, the updated information is returned.

var isEnabledHandle = webOS.service.request(
  "luna://com.webos.service.blegatt",
  {
    method: "isEnabled",
    parameters: {
      subscribe: true,
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      // check isEnabled
      if (inResponse.isEnabled === true) {
        isEnabledHandle.cancel(); // cancel subscribe
        // To-Do something
      }
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
      return;
    },
  }
);

Find BLE devices

To find BLE devices, use the `startScan` method. If you want to search for a certain type of peripheral devices, include the `uuid` parameter when calling the method. This `uuid` parameter should include values that indicates GATT services. Here are some points that you need to keep in mind about the `startScan` method.

  • If you do not stop scanning by calling the `stopScan` method after calling this method, the scanning will automatically stop after 60 seconds.

  • You can check whether scanning is currently underway from the return value of the `getState` method.

  • If the `startScan` method is called again while scanning is already underway, the `returnValue` will be false with `errorCode:1003` and `errorText: Scan is already in progress`.

stopScan = function () {
  var request = webOS.service.request("luna://com.webos.service.blegatt", {
    method: "stopScan",
    parameters: {},
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      // To-Do something
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};

startScan = function () {
  var scanHandle = webOS.service.request("luna://com.webos.service.blegatt", {
    method: "startScan",
    parameters: {
      subscribe: true,
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      if (inResponse.devices) {
        for (let i = 0; i < inResponse.devices.length; i++) {
          if (inResponse.devices[i].address === targetAddress) {
            // find target device
            scanHandle.cancel(); // cancel subscribe
            stopScan(); // stop scanning
            // To-Do something
            break;
          }
        }
      }
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};

The following is an example of checking if scanning is currently underway using the `getState` method.

getState = function () {
  var request = webOS.service.request("luna://com.webos.service.blegatt", {
    method: "getState",
    parameters: {
      subscribe: true,
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      if (inResponse.isScan === true) {
        // scanning in progress
        // To-Do something
      } else {
        // timeout or stopScan is called somewhere else
        // Scan request available status
        // To-Do something
      }
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};

Connect to a GATT server

The first step of interaction with a BLE device is connecting to the device, or more specifically, connecting to the GATT server of the device. To connect to the GATT server of the BLE device, use the `client/connect` method. This method receives the mac address of the GATT server as a parameter.

connect = function () {
  var request = webOS.service.request("luna://com.webos.service.blegatt", {
    method: "client/connect",
    parameters: {
      subscribe: true,
      address: "f7:0e:a1:0b:e7:84", // your taeget device address
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      // To-Do something
      handleEvent(inResponse);
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};

The call in the previous example makes connection to the GATT server hosted by the BLE device, and webOS TV can work as a GATT client. From the subscription return, you can check the connection state and additional operation result of the GATT client.

handleEvent = function (inResponse) {
  console.log("Result: " + JSON.stringify(inResponse));
  var event = inResponse.event;
  var values = inResponse.vales;

  // check connection state
  if (event === "onConnectionStateChange") {
    if (values) {
      if (values.address === targetAddress && values.connected === true) {
        // device is connected
        // To-Do something
      } else {
        // device is disconnected
        // To-Do something
      }
    }
  }
  // new services discovered
  else if (event === "onServicesDiscovered") {
    // To-Do something
  }
  // Characteristic notification
  else if (event === "onCharacteristicChanged") {
    // To-Do something
  }
  // Result of a characteristic read operation
  else if (event === "onCharacteristicRead") {
    // To-Do something
  }
  // Result of a characteristic write operation
  else if (event === "onCharacteristicWrite") {
    // To-Do something
  }
  // Result of a descriptor read operation
  else if (event === "onDescriptorRead") {
    // To-Do something
  }
  // Result of a descriptor write operation
  else if (event === "onDescriptorWrite") {
    // To-Do something
  }
};

Through the event delivered as the subscription return of the `client/connect` method, the operation of the GATT client is delivered, and depending on the event received, you can add appropriate follow-up operations.

Discover/Get GATT server services

To read or write data into the characteristic of the GATT server, searching for the supported services of the server should be performed first. It can be done by calling the `client/discoverServices` method, and when the searching is complete, an `onServicesDiscovered` event is delivered as the subscription return of the the `client/connect` method.

discoverServices = function () {
  var request = webOS.service.request("luna://com.webos.service.blegatt", {
    method: " client/discoverServices",
    parameters: {
      address: "f7:0e:a1:0b:e7:84",
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      // To-Do something
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};
handleEvent = function (inResponse) {
  var event = inResponse.event;
  // Result of discover services operation
  if (event === "onServicesDiscovered") {
    // To-Do something
  }
};

The information about the discovered server services can be checked by calling the `client/getServices` method, and the information is delivered as the subscription return of the `client/connect` method together with the `onServicesDiscovered` event.

getServices = function () {
  var request = webOS.service.request("luna://com.webos.service.blegatt", {
    method: " client/getServices",
    parameters: {
      address: "f7:0e:a1:0b:e7:84",
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      // To-Do something
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};
handleEvent = function (inResponse) {
  var event = inResponse.event;
  var values = inResponse.vales;
  // Result of a characteristic read operation
  if (event === "onServicesDiscovered") {
    // To-Do something
    console.log("values: " + JSON.stringify(values));
  }
};

Read/Write BLE characteristic

After webOS TV is connected to the GATT service and discovers a service, it can read and write characteristic (if supported). It is possible to read characteristic using the `client/readCharacteristic` method, and the read information is delivered as the subscription return of the `client/connect` method with the `onCharacteristicRead` event.

readCharacteristic = function () {
  var request = webOS.service.request("luna://com.webos.service.blegatt", {
    method: " client/readCharacteristic",
    parameters: {
      address: "f7:0e:a1:0b:e7:84",
      characteristic: "0000fff4-0000-1000-8000-00805f9b34fb",
      service: "0000fff0-0000-1000-8000-00805f9b34fb",
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      // To-Do something
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};
handleEvent = function (inResponse) {
  var event = inResponse.event;
  var values = inResponse.vales;
  // Result of a characteristic read operation
  if (event === "onCharacteristicRead") {
    // To-Do something
    console.log("values: " + JSON.stringify(values));
  }
};

Using the `client/writeCharacteristic` method, you can write a value to the characteristic, and the result of writing is delivered as the subscription return of the `client/connect` method with the `onCharacteristicWrite` event. However, if it is necessary to write data into a certain characteristic continuously, call the `client/writeCharacteristic` method first. Then, after receiving an `onCharacteristicWrite` event as the subscription return of the `client/connect` method, write the data using the `client/writeCharacteristic` method.

writeCharacteristic = function () {
  var request = webOS.service.request("luna://com.webos.service.blegatt", {
    method: " client/writeCharacteristic",
    parameters: {
      address: "f7:0e:a1:0b:e7:84",
      characteristic: "0000fff4-0000-1000-8000-00805f9b34fb",
      service: "0000fff0-0000-1000-8000-00805f9b34fb",
      value: { bytes: [92, 91, 93] },
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      // To-Do something
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};
var availableWriteCharacteristic = true;
var pollingCount = 0;
var timerId = 0;

handleEvent = function (inResponse) {
  var event = inResponse.event;
  var values = inResponse.vales;
  // Result of a characteristic write operation
  if (event === "onCharacteristicWrite") {
    console.log("values: " + JSON.stringify(values));
    availableWriteCharacteristic = ture;
  }
};

checkWriteCharacteristic = function () {
  // check to available writeCharacteristic
  if (availableWriteCharacteristic === true) {
    // clear timer
    clearTimeout(timerId);
    timerId = 0;
    pollingCount = 0;
    // write characteristic
    availableWriteCharacteristic = false;
    writeCharacteristic();
  } else {
    // need to polling to check write characteristic
    // This is an example implemented in the case of repetition three times.
    if (pollingCount < 3) {
      pollingCount++;
      timerId = setTimeout(function () {
        checkWriteCharacteristic();
      }, 100); // period is 100ms
    } else {
      clearTimeout(timerId);
      timerId = 0;
      pollingCount = 0;
    }
  }
};

Receive GATT notification

You can turn on notification about changes to a certain characteristic. Use the `setCharacteristicNotification` method to turn on notification about a certain characteristic. If there is a change to a characteristic on a remote device while notification about the characteristic is enabled, an `onCharacteristicChanged` event and the changed information are delivered as the subscription return of the `client/connect` method.

setCharacteristicNotification = function () {
  var request = webOS.service.request("luna://com.webos.service.blegatt", {
    method: " client/setCharacteristicNotification",
    parameters: {
      address: "f7:0e:a1:0b:e7:84",
      characteristic: "0000fff4-0000-1000-8000-00805f9b34fb",
      service: "0000fff0-0000-1000-8000-00805f9b34fb",
      enable: true,
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      // To-Do something
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};
handleEvent = function (inResponse) {
  var event = inResponse.event;
  var values = inResponse.vales;
  // Result of a characteristic read operation
  if (event === " onCharacteristicChanged") {
    // To-Do something
    console.log("values: " + JSON.stringify(values.changed));
  }
};

If necessary, to receive notifications, you need to change the configuration of Client Characteristic Configuration Descriptor (CCCD) to enable notification. It can be done using the `notification` parameter of the `client/writeDescriptor` method.

setCharacteristicNotification = function () {
  var request = webOS.service.request("luna://com.webos.service.blegatt", {
    method: "writeDescriptor",
    parameters: {
      address: "4f:6b:40:db:5b:b2",
      descriptor: "00002902-0000-1000-8000-00805f9b34fb", // CCCD
      characteristic: "0000fff4-0000-1000-8000-00805f9b34fb",
      service: "0000fff0-0000-1000-8000-00805f9b34fb",
      notification: "ENABLE_NOTIFICATION_VALUE",
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      // To-Do something
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};

Close GATT connection

When the use of the BLE device is complete in an app, the connection with the device should be terminated by calling the `client/disconnect` method.

disconnect = function () {
  var request = webOS.service.request("luna://com.webos.service.blegatt", {
    method: " client/disconnect",
    parameters: {
      address: "f7:0e:a1:0b:e7:84",
    },
    onSuccess: function (inResponse) {
      console.log("Result: " + JSON.stringify(inResponse));
      // To-Do something
    },
    onFailure: function (inError) {
      console.log("[" + inError.errorCode + "]: " + inError.errorText);
      // To-Do something
    },
  });
};

No Headings