Bluetooth

このドキュメントでは、BluetoothBluetooth SocketBluetooth Low Energy の各 API を使用して、Bluetooth および Bluetooth Low Energy デバイスと通信する方法について説明します。

Bluetooth の背景情報については、公式の Bluetooth の仕様をご覧ください。

マニフェストの要件

Bluetooth を使用する Chrome アプリの場合は、マニフェストに bluetooth エントリを追加し、必要に応じて、実装するプロファイル、プロトコル、サービスの UUID と、ソケットや Low Energy API で実装するかどうかを指定してください。

たとえば、ソケット実装の場合は次のようになります。

"bluetooth": {
  "uuids": [ "1105", "1106" ],
  "socket": true
}

Low Energy の実装:

"bluetooth": {
  "uuids": [ "180D", "1809", "180F" ],
  "low_energy": true
}

アダプターの状態へのアクセス、付近のデバイスの検出、デバイスの基本情報の取得のみを行うには、エントリ自体のみが必要になります。

"bluetooth": {}

アダプタ情報

アダプタの状態を取得する

Bluetooth アダプターの状態を取得するには、bluetooth.getAdapterState メソッドを使用します。

chrome.bluetooth.getAdapterState(function(adapter) {
  console.log("Adapter " + adapter.address + ": " + adapter.name);
});

アダプターの通知

アダプタの状態が変わるたびに、bluetooth.onAdapterStateChanged イベントが送信されます。これにより、たとえば、アダプター無線の電源がオンかオフかを判断できます。

var powered = false;
chrome.bluetooth.getAdapterState(function(adapter) {
  powered = adapter.powered;
});

chrome.bluetooth.onAdapterStateChanged.addListener(
  function(adapter) {
    if (adapter.powered != powered) {
      powered = adapter.powered;
      if (powered) {
        console.log("Adapter radio is on");
      } else {
        console.log("Adapter radio is off");
      }
    }
  });

デバイス情報

既知のデバイスの一覧表示

Bluetooth アダプターで認識されているデバイスのリストを取得するには、bluetooth.getDevices メソッドを使用します。

chrome.bluetooth.getDevices(function(devices) {
  for (var i = 0; i < devices.length; i++) {
    console.log(devices[i].address);
  }
});

ペア設定したデバイスや最近検出されたデバイスを含め、すべてのデバイスが返却されます。新しいデバイスの検出は開始されません(付近のデバイスの検出をご覧ください)。

デバイスの通知を受信しています

bluetooth.getDevices を繰り返し呼び出す代わりに、bluetooth.onDeviceAddedbluetooth.onDeviceChangedbluetooth.onDeviceRemoved の各イベントを使用して通知を受け取ることができます。

デバイスがアダプターによって検出されるか、アダプターに接続されるたびに、bluetooth.onDeviceAdded イベントが送信されます。

chrome.bluetooth.onDeviceAdded.addListener(function(device) {
  console.log(device.address);
});

このイベントのリスナーを追加しても、デバイスの検出は開始されません(付近のデバイスの検出をご覧ください)。

デバイスの変更(以前に検出されてペア設定されたデバイスなど)は、bluetooth.onDeviceChanged イベントによって通知されます。

chrome.bluetooth.onDeviceChanged.addListener(function(device) {
  console.log(device.address);
});

最後に、ペア設定されたデバイスがシステムから削除された場合、または検出されたデバイスが最近検出されていない場合に、bluetooth.onDeviceRemoved イベントが送信されます。

chrome.bluetooth.onDeviceRemoved.addListener(function(device) {
  console.log(device.address);
});

付近のデバイスを検出しています

付近のデバイスの検出を開始するには、bluetooth.startDiscovery メソッドを使用します。検出ではリソースを大量に消費する可能性があるため、実行が完了したら bluetooth.stopDiscovery を呼び出してください。

アプリで付近のデバイスを検出する必要があるときは、常に bluetooth.startDiscovery を呼び出す必要があります。bluetooth.AdapterStatediscovering プロパティで呼び出しを条件にしないでください。この呼び出しは、別のアプリが付近のデバイスを検出している場合でも成功し、他のアプリが停止した後もアダプターは検出の実行を継続します。

新たに検出された各デバイスに関する情報は、bluetooth.onDeviceAdded イベントを使用して受信されます。すでに最近検出されたデバイス、または以前にペア設定または接続されたデバイスの場合、イベントは送信されません。代わりに、bluetooth.getDevices を呼び出して現在の情報を取得し、bluetooth.onDeviceChanged イベントを使用して、検出の結果としてその情報が変更された場合に通知を受ける必要があります。

例:

var device_names = {};
var updateDeviceName = function(device) {
  device_names[device.address] = device.name;
};
var removeDeviceName = function(device) {
  delete device_names[device.address];
}

// Add listeners to receive newly found devices and updates
// to the previously known devices.
chrome.bluetooth.onDeviceAdded.addListener(updateDeviceName);
chrome.bluetooth.onDeviceChanged.addListener(updateDeviceName);
chrome.bluetooth.onDeviceRemoved.addListener(removeDeviceName);

// With the listeners in place, get the list of devices found in
// previous discovery sessions, or any currently active ones,
// along with paired devices.
chrome.bluetooth.getDevices(function(devices) {
  for (var i = 0; i < devices.length; i++) {
    updateDeviceName(devices[i]);
  }
});

// Now begin the discovery process.
chrome.bluetooth.startDiscovery(function() {
  // Stop discovery after 30 seconds.
  setTimeout(function() {
    chrome.bluetooth.stopDiscovery(function() {});
  }, 30000);
});

ユーザーが Bluetooth 無線をオフにすると、すべての検出セッションが終了し、無線がオンになっても自動的に再開されることはありません。アプリでこのことが重要な場合は、bluetooth.onAdapterStateChanged イベントを監視してください。discovering プロパティが false に変更された場合、アプリを再開するには、bluetooth.startDiscovery を再度呼び出す必要があります。検出の際にリソースを大量に消費する性質に注意してください。

デバイスの識別

bluetooth.getDevices および関連するイベントから返されるデバイスを識別するために、さまざまなオプションが用意されています。

デバイスが Bluetooth のデバイス ID 仕様をサポートしている場合、その仕様で定義されたフィールドを含むデバイス オブジェクトに複数のプロパティが追加されます。例:

chrome.bluetooth.getDevices(function(devices) {
  for (var i = 0; i < devices.length; i++) {
    if (devices[0].vendorIdSource != undefined) {
      console.log(devices[0].address + ' = ' +
                  devices[0].vendorIdSource + ':' +
                  devices[0].vendorId.toString(16) + ':' +
                  devices[0].productId.toString(16) + ':' +
                  devices[0].deviceId.toString(16));
    }
  }
});

通常、ベンダーのデバイスの特定のモデルやリビジョンを特定するには、デバイス ID の仕様で十分です。この URL が存在しない場合は、代わりにデバイスのクラスまたはタイプに関する情報を利用する必要があります。必要に応じて、address 内でメーカーの接頭辞と組み合わせて使用することもできます。

ほとんどの Bluetooth デバイスは、ベースバンド割り当て数値のドキュメントに従って解釈されたビット フィールドとしてデバイスのクラス情報を提供します。このビット フィールドは deviceClass プロパティで使用できます。

chrome.bluetooth.getDevices(function(devices) {
  for (var i = 0; i < devices.length; i++) {
    if (devices[0].vendorIdSource != undefined) {
      console.log(devices[0].address + ' = ' +
                  devices[0].deviceClass.toString(16));
    }
  }
});

フィールドの解析は複雑な場合があるため、一般的なデバイスタイプでは Chrome が処理を行い、type フィールドを設定します。使用できない場合やニーズを満たせない場合は、自分で deviceClass を解析する必要があります。

chrome.bluetooth.getDevices(function(devices) {
  for (var i = 0; i < devices.length; i++) {
    if (devices[0].vendorIdSource != undefined) {
      console.log(devices[0].address + ' = ' + devices[0].type);
    }
  }
});

RFCOMM と L2CAP の使用

Chrome アプリは、RFCOMM または L2CAP サービスをサポートするデバイスに接続できます。これには、市販されている従来の Bluetooth デバイスの大多数が含まれます。

ソケットへの接続

デバイスに接続するには、3 つのものが必要です。bluetoothSocket.create を使用して作成された、接続に使用するソケット、接続するデバイスのアドレス、サービス自体の UUID。

接続する前に、bluetooth.getDevice または Device Discovery API を使用して、アダプタがデバイスを認識していることを確認してください。

RFCOMM プロトコルと L2CAP プロトコルのどちらを使用するか、どのチャネルまたは PSM を使用するかなど、基盤となる接続を確立するために必要な情報は、デバイスの SDP ディスカバリを使用して取得されます。

例:

var uuid = '1105';
var onConnectedCallback = function() {
  if (chrome.runtime.lastError) {
    console.log("Connection failed: " + chrome.runtime.lastError.message);
  } else {
    // Profile implementation here.
  }
};

chrome.bluetoothSocket.create(function(createInfo) {
  chrome.bluetoothSocket.connect(createInfo.socketId,
    device.address, uuid, onConnectedCallback);
});

後でこのソケットにデータ(bluetoothSocket.send)を送信できるように、socketId へのハンドルを保持します。

ソケットの受信と送信

ソケットとの間でデータの受信と送信には、ArrayBuffer オブジェクトを使用します。ArrayBuffers については、概要、JavaScript 型配列、チュートリアルの ArrayBuffer と文字列を変換する方法をご覧ください。

arrayBuffer にあるデータを送信するには、bluetoothSocket.send を使用します。

chrome.bluetoothSocket.send(socketId, arrayBuffer, function(bytes_sent) {
  if (chrome.runtime.lastError) {
    console.log("Send failed: " + chrome.runtime.lastError.message);
  } else {
    console.log("Sent " + bytes_sent + " bytes")
  }
})

データを送信するメソッドとは対照的に、データはイベント(bluetoothSocket.onReceive)で受信します。ソケットは一時停止されずに作成されます(bluetoothSocket.setPaused を参照)。そのため、このイベントのリスナーは通常、bluetoothSocket.createbluetoothSocket.connect の間に追加されます。

chrome.bluetoothSocket.onRecieve.addListener(function(receiveInfo) {
  if (receiveInfo.socketId != socketId)
    return;
  // receiveInfo.data is an ArrayBuffer.
});

ソケットのエラーと切断

切断などのソケットエラーの通知を受けるには、bluetoothSocket.onReceiveError イベントにリスナーを追加します。

chrome.bluetoothSocket.onReceiveError.addListener(function(errorInfo) {
  // Cause is in errorInfo.error.
  console.log(errorInfo.errorMessage);
});

ソケットからの切断

接続を切断してソケットを切断するには、bluetoothSocket.disconnect を使用します。

chrome.bluetoothSocket.disconnect(socketId);

公開サービス

Chrome アプリは、デバイスへのアウトバウンド接続だけでなく、RFCOMM または L2CAP をサポートするすべてのデバイスで使用できるサービスを公開することもできます。

ソケットでのリッスン

2 種類の公開サービスがサポートされています。RFCOMM は最も一般的に使用され、次のようにデバイスとプロファイルの大部分をカバーしています。

var uuid = '1105';
chrome.bluetoothSocket.create(function(createInfo) {
  chrome.bluetoothSocket.listenUsingRfcomm(createInfo.socketId,
    uuid, onListenCallback);
});

L2CAP はもう 1 つで、他のデバイスタイプや、ファームウェアのアップロードなど、ベンダー固有の用途に対応しています。

var uuid = '0b87367c-f188-47cd-bc20-a5f4f70973c6';
chrome.bluetoothSocket.create(function(createInfo) {
  chrome.bluetoothSocket.listenUsingL2cap(createInfo.socketId,
    uuid, onListenCallback);
});

いずれの場合も、オプションの bluetoothSocket.ListenOptions を渡して、特定のチャネルまたは PSM を割り当てることができます。このコールバックは、chrome.runtime.lastError でエラーを示し、それ以外の場合は成功を示します。socketId へのハンドルを保持して、後でこのソケットからの接続(bluetoothSocket.onAccept)を受け入れるようにします。

クライアント接続を受け入れる

クライアント接続は受け入れられ、bluetoothSocket.onAccept イベントを介してアプリに渡されます。

chrome.bluetoothSocket.onAccept.addListener(function(acceptInfo) {
  if (info.socketId != serverSocketId)
    return;

  // Say hello...
  chrome.bluetoothSocket.send(acceptInfo.clientSocketId,
    data, onSendCallback);

  // Accepted sockets are initially paused,
  // set the onReceive listener first.
  chrome.bluetoothSocket.onReceive.addListener(onReceive);
  chrome.bluetoothSocket.setPaused(false);
});

クライアント接続の受け入れを停止する

クライアント接続の受け入れを停止してサービスを非公開にするには、bluetoothSocket.disconnect を使用します。

chrome.bluetoothSocket.disconnect(serverSocketId);

Low Energy デバイスの操作

Bluetooth Low Energy(Bluetooth Smart)は、消費電力の削減を目的としたワイヤレス技術です。Bluetooth Low Energy API を使用すると、アプリは周辺機器への LE 接続の中心的な役割を実装できます。以下のセクションでは、Bluetooth Low Energy の周辺機器の検出、接続、操作方法について説明します。

周辺機器の検出と接続

従来の Bluetooth デバイスと同様に、LE 周辺機器は付近のデバイスを検出するで説明されている方法で検出できます。LE デバイスは「アドバタイジング データ」と呼ばれるデータパケットを送信することで自身を検出可能にします。デバイスはアドバタイジング モードであると言えます。広告データには、デバイスで利用可能なサービスの UUID が含まれる場合があります。UUID が存在する場合は、対応する bluetooth.Device オブジェクトの uuids プロパティを使用してアクセスできます。

検出された LE デバイスは、bluetoothLowEnergy.connect を呼び出して接続し、アプリがそのサービスとやり取りできるようにします。

chrome.bluetooth.onDeviceAdded.addListener(function(device) {
  var uuid = '0000180d-0000-1000-8000-00805f9b34fb';
  if (!device.uuids || device.uuids.indexOf(uuid) < 0)
    return;

  // The device has a service with the desired UUID.
  chrome.bluetoothLowEnergy.connect(device.address, function () {
    if (chrome.runtime.lastError) {
      console.log('Failed to connect: ' + chrome.runtime.lastError.message);
      return;
    }

    // Connected! Do stuff...
    ...
  });
});

接続されると、対応する bluetooth.Device オブジェクトの connected プロパティの値は true になります。bluetoothLowEnergy.connect を呼び出すと、デバイスへの物理接続に対するアプリによる要求が確立されます。別のアプリケーションなどが原因で、bluetoothLowEnergy.connect を呼び出さなくてもデバイスへの物理的な接続が確立できます。この場合、アプリは引き続きデバイスのサービスとやり取りできますが、必ず bluetoothLowEnergy.connect を呼び出して、別のアプリが物理リンクを切断しないようにする必要があります。

アプリの接続が不要になったら、bluetoothLowEnergy.disconnect を呼び出して、接続に対する要求を削除できます。

chrome.bluetoothLowEnergy.disconnect(deviceAddress);

なお、デバイスへのアクティブな接続を持つ他のアプリが存在する可能性があるため、これによってデバイスへの物理リンクが必ずしも破棄されるわけではありません。アプリの制御範囲外の理由でデバイスが接続解除されることがあります(オペレーティング システムのユーティリティを介してデバイスが表示されなくなった、またはユーザーが明示的に接続を解除した場合など)。アプリは bluetooth.onDeviceChanged イベントを監視して、接続の変更に関する通知を受け取り、必要に応じて再接続する必要があります。

接続されると、Chrome を実行しているデバイスはいわゆる中央の役割になり、リモート デバイスは周辺機器の役割になります。この時点で、アプリは次のセクションで説明するメソッドを使用して、デバイス上のサービスとやり取りできます。注: API は現在、LE 周辺機器としての動作をサポートしていません。アプリは中心的な役割のみを実装できます。

サービス、特性、記述子

Bluetooth Low Energy は、属性プロトコル(ATT)と呼ばれるシンプルなリクエスト / レスポンス プロトコルに基づいています。ATT を使用すると、中央のデバイスは Generic Attribute Profile(GATT)と呼ばれる特別な Bluetooth プロファイルに準拠することで、周辺機器デバイスのいわゆる属性とやり取りします。GATT では、次の大まかなコンセプトが定義されています。

  • サービス: GATT サービスは、デバイスの特定の機能を実現するためのデータの集まりとそれに関連する動作を表します。たとえば、通常、心拍数モニターには少なくとも 1 つの「心拍数サービス」があります。GATT サービスに関する情報は、bluetoothLowEnergy.Service オブジェクトに格納されます。
  • 特性: GATT 特性は、GATT サービスの構築に使用される基本的なデータ要素で、値とその値へのアクセス方法を定義するプロパティを含んでいます。たとえば、「Heart Rate Service」には「Heart Rate Measurement」という特性があり、これを使用してユーザーの心拍数の値を取得できます。GATT 特性に関する情報は、bluetoothLowEnergy.Characteristic オブジェクトに格納されます。
  • 記述子: GATT 特性記述子には、特性に関する追加情報が含まれます。GATT 特性記述子に関する情報は、bluetoothLowEnergy.Descriptor オブジェクトに格納されます。

Bluetooth Low Energy API を使用すると、アプリは bluetoothLowEnergy.getServicesbluetoothLowEnergy.getCharacteristicsbluetoothLowEnergy.getDescriptors の呼び出しにより、デバイスのサービス、特性、記述子に関する情報を見つけることができます。アプリは、uuid フィールドを目的の GATT UUID と比較することで、サービス、特性、記述子をフィルタリングできます。

chrome.bluetoothLowEnergy.getServices(deviceAddress, function(services) {
  ...
  for (var i = 0; i < services.length; i++) {
    if (services[i].uuid == HEART_RATE_SERVICE_UUID) {
      heartRateService = services[i];
      break;
    }
  }
  ...
});

API を通じてアクセスできる各サービス、特性、記述子には、一意のインスタンス識別子が割り当てられます。この識別子は、instanceId フィールドを使用して取得できます。このインスタンス ID を使用して、GATT オブジェクトを識別し、そのオブジェクトに対して特定のオペレーションを実行できます。

chrome.bluetoothLowEnergy.getCharacteristics(heartRateService.instanceId,
                                             function(chracteristics) {
  ...
  for (var i = 0; i < characteristics.length; i++) {
    if (characteristics[i].uuid == HEART_RATE_MEASUREMENT_UUID) {
      measurementChar = characteristics[i];
      break;
    }
  }
  ...
  chrome.bluetoothLowEnergy.getDescriptors(measurementChar.instanceId,
                                           function(descriptors) {
    ...
  });
});

サービス イベント

デバイスが接続されると、Chrome はそのサービスを検出します。各サービスが検出されて削除されると、アプリは bluetoothLowEnergy.onServiceAdded イベントと bluetoothLowEnergy.onServiceRemoved イベントを受け取ります。

  var initializeService = function(service) {
    if (!service) {
      console.log('No service selected!');
      // Reset UI, etc.
      ...
      return;
    }

    myService = service;

    // Get all the characteristics and descriptors and bootstrap the app.
    ...
  };

  chrome.bluetoothLowEnergy.onServiceAdded.addListener(function(service) {
    if (service.uuid == MY_SERVICE_UUID)
      initializeService(service);
  });

  chrome.bluetoothLowEnergy.onServiceRemoved.addListener(function(service) {
    if (service.instanceId == myService.instanceId)
      initializeService(null);
  });

Chrome はサービスのすべての特性と記述子を非同期で検出し、検出が完了すると bluetoothLowEnergy.onServiceAdded イベントを送信します。周辺機器への接続が終了すると、Chrome は関連するすべてのサービスを削除し、bluetoothLowEnergy.onServiceRemoved イベントを送信します。

周辺機器によってはサービスが変更されることがあります。たとえば、サービスの特性が変更されたり、サービスが追加または削除されたりすることがあります。Chrome は、bluetoothLowEnergy.onServiceChangedbluetoothLowEnergy.onServiceAddedbluetoothLowEnergy.onServiceRemoved イベントを使用して、これらの変更をアプリに通知します。

  chrome.bluetoothLowEnergy.onServiceChanged.addListener(function(service) {
    if (service.instanceId != myService.instanceId)
      return;

    updateMyService(service);
  });

特性値の読み取りと書き込み

GATT 特性は、そのサービスの 1 つの側面をエンコードします。中央のアプリは、特性の値を操作することにより、周辺機器のサービスの状態の読み取りと操作、変更を行います。特性値はバイトのシーケンスであり、その意味は特定の特性を定義するハイレベル仕様によって定義されます。たとえば、[Heart Rate Measurement] 特性の値は、ユーザーの心拍数と消費カロリーの総量がエンコードされ、[Body Sensor Location] 特性は、心拍数センサーを装着すべき体内の位置をエンコードします。

Chrome には、特性の値を読み取る bluetoothLowEnergy.readCharacteristicValue メソッドが用意されています。

chrome.bluetoothLowEnergy.readCharacteristicValue(chrc.instanceId,
                                                  function(result) {
  if (chrome.runtime.lastError) {
    console.log('Failed to read value: ' + chrome.runtime.lastError.message);
    return;
  }

  var bytes = new Uint8Array(result.value);

  // Do stuff with the bytes.
  ...
});

いくつかの特性は書き込み可能です。特に「コントロール ポイント」として動作する特性で、値を書き込むと副作用が発生します。たとえば、Heart Rate Control Point 特性は、総消費カロリー数をリセットするように心拍数センサーに伝えるために使用され、書き込みのみをサポートします。これを実現するために、Chrome には bluetoothLowEnergy.writeCharacteristicValue メソッドが用意されています。

var myBytes = new Uint8Array([ ... ]);
chrome.bluetoothLowEnergy.writeCharacteristicValue(chrc.instanceId,
                                                   myBytes.buffer,
                                                   function() {
  if (chrome.runtime.lastError) {
    console.log('Failed to write value: ' +
                chrome.runtime.lastError.message);
    return;
  }

  // Value is written now.
});

特性記述子も同様に動作し、読み書きが可能です。Chrome には、記述子の値を読み書きするための bluetoothLowEnergy.readDescriptorValue メソッドと bluetoothLowEnergy.writeDescriptorValue メソッドが用意されています。

特性が読み取りまたは書き込みをサポートしているかどうかを確認するには、アプリで bluetoothLowEnergy.Characteristic オブジェクトの properties フィールドを確認します。このフィールドには、値にアクセスするためのセキュリティ要件に関する情報は含まれませんが、特性が一般的にどの値のオペレーションをサポートするかは説明されます。

価値通知の処理

特性によっては、通知やインジケーションを使用して値を公開します。たとえば、心拍数測定の特性は読み取りも書き込みもできませんが、現在の値の更新を定期的に送信します。アプリは、bluetoothLowEnergy.onCharacteristicValueChanged イベントを使用して、これらの通知をリッスンできます。

  chrome.bluetoothLowEnergy.onCharacteristicValueChanged.addListener(
      function(chrc) {
    if (chrc.instanceId != myCharId)
      return;

    var bytes = new Uint8Array(chrc.value);

    // Do stuff with the bytes.
    ...
  });

特性が通知や表示をサポートしていても、デフォルトでは有効になっていません。アプリは bluetoothLowEnergy.startCharacteristicNotifications メソッドと bluetoothLowEnergy.stopCharacteristicNotifications メソッドを呼び出して、bluetoothLowEnergy.onCharacteristicValueChanged イベントの受信を開始または停止する必要があります。

  // Start receiving characteristic value notifications.
  var notifying = false;
  chrome.bluetoothLowEnergy.startCharacteristicNotifications(chrc.instanceId,
                                                             function() {
    if (chrome.runtime.lastError) {
      console.log('Failed to enable notifications: ' +
                  chrome.runtime.lastError.message);
      return;
    }

    notifying = true;
  });

  ...

  // No longer interested in notifications from this characteristic.
  if (notifying) {
    chrome.bluetoothLowEnergy.stopCharacteristicNotifications(
        chrc.instanceId);
  }

通知が開始されると、アプリは特性から通知または表示を受け取るたびに bluetoothLowEnergy.onCharacteristicValueChanged を受け取ります。特性が読み取りをサポートしている場合は、bluetoothLowEnergy.readCharacteristicValue の呼び出しが成功した後もこのイベントが送信されます。これにより、アプリは読み取りリクエストと通知によってトリガーされる値の更新の制御フローを統合できます。

  chrome.bluetoothLowEnergy.onCharacteristicValueChanged.addListener(
      function(chrc) {
    // Process the value.
    ...
  });

  chrome.bluetoothLowEnergy.startCharacteristicNotifications(chrc.instanceId,
                                                             function() {
    // Notifications started. Read the initial value.
    chrome.bluetoothLowEnergy.readCharacteristicValue(chrc.instanceId,
                                                      function(result) {
      ...
      // No need to do anything here since onCharacteristicValueChanged
      // will handle it.
    });
  });

特性が通知をサポートする場合、properties フィールドに "notify" または "indicate" のいずれかのプロパティが含まれます。

注: 特性が通知 / 表示をサポートしている場合、通知を有効または無効にする「クライアント特性構成」記述子があります。Chrome は、アプリがこの記述子への書き込みを許可しません。代わりに bluetoothLowEnergy.startCharacteristicNotifications メソッドと bluetoothLowEnergy.stopCharacteristicNotifications メソッドを使用して、通知の動作を制御します。