JavaScript 経由で Bluetooth デバイスと通信する

Web Bluetooth API を使用すると、ウェブサイトと Bluetooth デバイスとの通信が可能になります。

François Beaufort
François Beaufort

ウェブサイトが近くの Bluetooth デバイスと通信できるとしたらどうしますか? セキュリティを確保できるでしょうか。このようにして、心拍数をモニターし、 電球や、カメもウェブサイトと直接やり取りできます。

これまでは、Bluetooth デバイスを操作することが可能でした。 プラットフォーム固有のアプリに対してのみ 使用できますWeb Bluetooth API は、この点を変え、 ウェブブラウザにも導入されます。

始める前に

このドキュメントは、Bluetooth Low 機能に関する基本的な知識があることを前提としています。 Energy(BLE)と Generic Attribute Profile は機能します。

Web Bluetooth API の仕様はまだ確定していませんが、 作成者は、この API を試してくれる熱心なデベロッパーを積極的に求めています。 仕様に関するフィードバック実装に関するフィードバックをお寄せください。

Web Bluetooth API のサブセットを ChromeOS と Chrome for Android で利用可能 6.0、Mac(Chrome 56)、Windows 10(Chrome 70)に対応しています。つまり 付近の Bluetooth Low Energy デバイスをリクエストして接続する Bluetooth 特性の読み取り/書き込みGATT 通知の受信、情報 Bluetooth デバイスの接続が解除され、さらに Bluetooth デバイスの Bluetooth 記述子。詳しくは MDN のブラウザの互換性の表をご覧ください 情報です。

Linux やそれ以前のバージョンの Windows の場合は、 about://flags#experimental-web-platform-features フラグ。

オリジン トライアルで利用可能

ウェブを使用しているデベロッパーからできるだけ多くのフィードバックを Bluetooth API のフィールドで、この機能が Chrome にすでに追加されています。 53 を ChromeOS、Android、Mac のオリジン トライアルとして利用できます。

このトライアルは、2017 年 1 月に終了いたしました。

セキュリティ要件

セキュリティのトレードオフを理解するには、Web Bluetooth Security Chrome チームのソフトウェア エンジニアである Jeffrey Yasskin によるモデルの投稿 ウェブ Bluetooth API の仕様に取り組んでいます。

HTTPS のみ

この試験運用版の API はウェブに追加されたパワフルな新機能であるため、 安全なコンテキストでのみ利用可能。つまり、Python、C、C++ の TLS に留意してください。

ユーザー操作が必要です

セキュリティ機能として、Bluetooth デバイス、 navigator.bluetooth.requestDevice は、次のようなユーザー操作によってトリガーする必要があります。 タップでもマウスクリックでも操作できます。つまり pointerupclicktouchend イベント。

button.addEventListener('pointerup', function(event) {
  // Call navigator.bluetooth.requestDevice
});

コードを開始する

Web Bluetooth API は、JavaScript の Promise に大きく依存しています。Google Workspace の こちらの Promise のチュートリアルをご覧ください。最後にもう一つ、 () => {} は、ECMAScript 2015 のアロー関数です。

Bluetooth デバイスをリクエストする

このバージョンの Web Bluetooth API 仕様では、ウェブサイトを BLE 接続でリモート GATT サーバーに接続するための Central ロールが必要です。これは、 は Bluetooth 4.0 以降を実装したデバイス間の通信に対応しています。

ウェブサイトから付近のデバイスへのアクセスが navigator.bluetooth.requestDevice: ブラウザがユーザーにデバイスのプロンプトを表示します。 1 台のデバイスを選択したり、リクエストをキャンセルしたりできます。

をご覧ください。
Bluetooth デバイスのユーザー プロンプト

navigator.bluetooth.requestDevice() 関数は、次のような必須のオブジェクトを受け取ります。 フィルタを定義します。これらのフィルタは、一部に一致するデバイスのみを取得するために使用されます。 アドバタイズされた Bluetooth GATT サービスやデバイス名がアドバタイズされます。

サービス フィルタ

たとえば、Bluetooth GATT をアドバタイズする Bluetooth デバイスをリクエストします。 バッテリー サービス:

navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => { /* … */ })
.catch(error => { console.error(error); });

Bluetooth GATT サービスが標準の Bluetooth GATT サービスでは、完全な Bluetooth UUID または短い UUID を指定できます。 16 ビット形式または 32 ビット形式。

navigator.bluetooth.requestDevice({
  filters: [{
    services: [0x1234, 0x12345678, '99999999-0000-1000-8000-00805f9b34fb']
  }]
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

名前フィルタ

アドバタイズするデバイス名に基づいて Bluetooth デバイスをリクエストすることもできます name フィルタキー、またはこの名前の接頭辞 namePrefix と一緒に使用します。 あります。この場合は、サービス アカウントを optionalServices 鍵で、プロジェクトに含まれていないサービスにも サービス フィルタ。そうしないと、後でアクセスしようとするとエラーが発生します できます。

navigator.bluetooth.requestDevice({
  filters: [{
    name: 'Francois robot'
  }],
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

メーカーのデータフィルタ

Bluetooth デバイスをメーカーにリクエストすることもできます。 manufacturerData フィルタキーでアドバタイズされる特定のデータ。このキー 必須の Bluetooth 企業識別子キーを持つオブジェクトの配列です。 companyIdentifier。データ接頭辞を指定して、 Bluetooth デバイスのメーカー データを取得します。なお、 任意のサービスにアクセスできるように、optionalServices キーを定義する必要もあります。 含まれません。そうしないと、後でエラーが発生するのに 見ていきましょう。

// Filter Bluetooth devices from Google company with manufacturer data bytes
// that start with [0x01, 0x02].
navigator.bluetooth.requestDevice({
  filters: [{
    manufacturerData: [{
      companyIdentifier: 0x00e0,
      dataPrefix: new Uint8Array([0x01, 0x02])
    }]
  }],
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

データ接頭辞とともにマスクを使用すると、 ダウンロードします。詳しくは、Bluetooth データフィルタの説明をご覧ください。 できます。

除外フィルタ

navigator.bluetooth.requestDevice()exclusionFilters オプションを使用すると、 ブラウザ選択ツールから一部のデバイスを除外した。特定のキャンペーンを除外したり より広範なフィルタに一致するがサポートされていないデバイスです。

// Request access to a bluetooth device whose name starts with "Created by".
// The device named "Created by Francois" has been reported as unsupported.
navigator.bluetooth.requestDevice({
  filters: [{
    namePrefix: "Created by"
  }],
  exclusionFilters: [{
    name: "Created by Francois"
  }],
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

フィルタを使わない

最後に、filters の代わりに acceptAllDevices キーを使用して、すべてを表示できます。 付近の Bluetooth デバイスに接続できます。optionalServices を定義する必要もあります。 鍵が必要です。そうしないと、後でエラーが発生します 制限されることがあります。

navigator.bluetooth.requestDevice({
  acceptAllDevices: true,
  optionalServices: ['battery_service'] // Required to access service later.
})
.then(device => { /* … */ })
.catch(error => { console.error(error); });

Bluetooth デバイスに接続する

では、BluetoothDevice を用意したら、どうすればよいでしょうか。Cloud Shell に サービスと特性を保持する Bluetooth リモート GATT サーバー あります。

navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => {
  // Human-readable name of the device.
  console.log(device.name);

  // Attempts to connect to remote GATT Server.
  return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });

Bluetooth の特性を読み取る

ここで、リモート Bluetooth デバイスの GATT サーバーに接続します。これで、 プライマリ GATT サービスを取得して、 できます。たとえば、Google Nest Mini の現在の充電レベルを できます。

上記の例では、battery_level標準化されたバッテリー残量です。 特性

navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device => device.gatt.connect())
.then(server => {
  // Getting Battery Service…
  return server.getPrimaryService('battery_service');
})
.then(service => {
  // Getting Battery Level Characteristic…
  return service.getCharacteristic('battery_level');
})
.then(characteristic => {
  // Reading Battery Level…
  return characteristic.readValue();
})
.then(value => {
  console.log(`Battery percentage is ${value.getUint8(0)}`);
})
.catch(error => { console.error(error); });

カスタムの Bluetooth GATT 特性を使用する場合は、 完全な Bluetooth UUID、または短い 16 ビットまたは 32 ビット形式の service.getCharacteristic

なお、characteristicvaluechanged イベント リスナーを 値の読み取りを処理できます。Read 特性の 値変更サンプルで、今後の GATT をオプションとして処理する方法を確認してください。 通知を受け取ることができます。

…
.then(characteristic => {
  // Set up event listener for when characteristic value changes.
  characteristic.addEventListener('characteristicvaluechanged',
                                  handleBatteryLevelChanged);
  // Reading Battery Level…
  return characteristic.readValue();
})
.catch(error => { console.error(error); });

function handleBatteryLevelChanged(event) {
  const batteryLevel = event.target.value.getUint8(0);
  console.log('Battery percentage is ' + batteryLevel);
}

Bluetooth 特性への書き込み

Bluetooth GATT 特性への書き込みは、読み取るのと同じくらい簡単です。今回は [HR コントロール ポイント] を使用して、[消費エネルギー] の値を 心拍数モニターデバイスではフィールドを 0 に設定します。

魔法はないと約束する。これについては心拍数コントロールの [Point Characteristic] ページ

navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_control_point'))
.then(characteristic => {
  // Writing 1 is the signal to reset energy expended.
  const resetEnergyExpended = Uint8Array.of(1);
  return characteristic.writeValue(resetEnergyExpended);
})
.then(_ => {
  console.log('Energy expended has been reset.');
})
.catch(error => { console.error(error); });

GATT 通知を受け取る

次に、心拍数測定がいつ通知されるかを見てみましょう。 特性の変化に迅速に対応できます。

navigator.bluetooth.requestDevice({ filters: [{ services: ['heart_rate'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('heart_rate'))
.then(service => service.getCharacteristic('heart_rate_measurement'))
.then(characteristic => characteristic.startNotifications())
.then(characteristic => {
  characteristic.addEventListener('characteristicvaluechanged',
                                  handleCharacteristicValueChanged);
  console.log('Notifications have been started.');
})
.catch(error => { console.error(error); });

function handleCharacteristicValueChanged(event) {
  const value = event.target.value;
  console.log('Received ' + value);
  // TODO: Parse Heart Rate Measurement value.
  // See https://github.com/WebBluetoothCG/demos/blob/gh-pages/heart-rate-sensor/heartRateSensor.js
}

Notifications サンプルでは、次の方法を使用して通知を停止する方法を説明しています。 stopNotifications() を実行し、追加された characteristicvaluechanged を適切に削除します イベント リスナー。

Bluetooth デバイスの接続を解除する

ユーザー エクスペリエンスを向上させるために、接続解除イベントをリッスンできます。 ユーザーに再接続するよう招待します。

navigator.bluetooth.requestDevice({ filters: [{ name: 'Francois robot' }] })
.then(device => {
  // Set up event listener for when device gets disconnected.
  device.addEventListener('gattserverdisconnected', onDisconnected);

  // Attempts to connect to remote GATT Server.
  return device.gatt.connect();
})
.then(server => { /* … */ })
.catch(error => { console.error(error); });

function onDisconnected(event) {
  const device = event.target;
  console.log(`Device ${device.name} is disconnected.`);
}

また、device.gatt.disconnect() を呼び出してウェブアプリと Bluetooth デバイス。既存の gattserverdisconnected イベントがトリガーされます。 使用します。ただし、別の Bluetooth デバイスが Bluetooth デバイスと通信しても、 アプリはすでに Bluetooth デバイスと通信しています。詳細については、 切断のサンプル自動再接続のサンプルで詳細を確認してください。

Bluetooth 記述子の読み取りと書き込み

Bluetooth GATT 記述子は、特性値を記述する属性です。 Bluetooth GATT と同様の方法で読み書きできます。 説明します。

それでは、測定に関するユーザーの説明を読み取る方法を見てみましょう。 デバイスのヘルス温度計の間隔です。

以下の例で、health_thermometer健康温度計サービスです。 measurement_interval 測定間隔の特性 gatt.characteristic_user_description - 特徴ユーザーの説明 記述子を使用します。

navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => descriptor.readValue())
.then(value => {
  const decoder = new TextDecoder('utf-8');
  console.log(`User Description: ${decoder.decode(value)}`);
})
.catch(error => { console.error(error); });

ここまで、BigQuery の それを更新してカスタム温度を あります。

navigator.bluetooth.requestDevice({ filters: [{ services: ['health_thermometer'] }] })
.then(device => device.gatt.connect())
.then(server => server.getPrimaryService('health_thermometer'))
.then(service => service.getCharacteristic('measurement_interval'))
.then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
.then(descriptor => {
  const encoder = new TextEncoder('utf-8');
  const userDescription = encoder.encode('Defines the time between measurements.');
  return descriptor.writeValue(userDescription);
})
.catch(error => { console.error(error); });

サンプル、デモ、Codelab

以下のウェブ Bluetooth のサンプルはすべてテスト済みです。お楽しみください 使用するには、[BLE Peripheral Simulator] を Android アプリ] を使用して、バッテリー サービスで BLE 周辺機器をシミュレートします。 サービス、またはヘルス温度計サービス。

初級

  • Device Info - BLE デバイスから基本的なデバイス情報を取得します。
  • Battery Level - バッテリー情報をアドバタイズする BLE デバイスからバッテリー情報を取得します。
  • Reset Energy - 心拍数をアドバタイズする BLE デバイスから消費されたエネルギーをリセットします。
  • Characteristic Properties - BLE デバイスの特定の特性に関するすべてのプロパティを表示します。
  • Notifications - BLE デバイスからの特性通知を開始および停止します。
  • Device Disconnect(デバイスの切断) - BLE デバイスの接続後に接続が切断されると、切断され、通知が届きます。
  • 特性の取得 - BLE デバイスからアドバタイズされたサービスのすべての特性を取得します。
  • 記述子を取得 - すべての特性を取得します。BLE デバイスからアドバタイズされたサービスの記述子です。
  • メーカーデータフィルタ - メーカーのデータと一致する BLE デバイスから基本的なデバイス情報を取得します。
  • Exclusion Filters(除外フィルタ) - 基本的な除外フィルタを備えた BLE デバイスから基本的なデバイス情報を取得します。

複数のオペレーションの組み合わせ

  • GAP Characteristics(GAP 特性)- BLE デバイスのすべての GAP 特性を取得します。
  • Device Information Characteristics(デバイス情報の特性)- BLE デバイスのすべてのデバイス情報特性を取得します。
  • Link Loss - BLE デバイスのアラートレベル特性を設定します(readValue と writeValue)。
  • サービスとアプリの特性 - BLE デバイスからアクセス可能なすべての主要サービスとその特性。
  • Automatic Reconnect - 指数バックオフ アルゴリズムを使用して、接続解除された BLE デバイスに再接続します。
  • 特性値の読み取り - バッテリー残量を読み取って、BLE デバイスからの変更に関する通知を受け取ります。
  • 記述子の読み取り - サービスのすべての特性の記述子を BLE デバイスから読み取ります。
  • Write Descriptor - 「Characteristic User Description」という記述子に書き込みます。測定します。

おすすめのウェブ Bluetooth デモウェブ Bluetooth 公式 Codelab もご覧ください。

ライブラリ

  • web-bluetooth-utils は、いくつかの便利な関数を追加する npm モジュールです。 できます。
  • ウェブ Bluetooth API shim は、最も一般的な Node.js BLE である noble で利用できます。 モジュールへようこそ。これにより、コードを一切書かずに Noble をウェブパック/ブラウザ化 WebSocket サーバーやその他のプラグインの トラフィックを暗号化します
  • angular-web-bluetoothAngular のモジュールであり、 Web Bluetooth API の設定に必要なボイラープレート。

ツール

  • ウェブ Bluetooth スタートガイドは、すべての Bluetooth 接続や Bluetooth 接続、 Bluetooth デバイスの操作を開始するための JavaScript ボイラープレート コードです。 デバイス名、サービス、特性を入力し、そのプロパティを定義します。 これで完了です。
  • すでに Bluetooth デベロッパーの方は、Web Bluetooth Developer Studio Plugin は、お使いのモバイル デバイスのウェブ Bluetooth JavaScript コードも生成します。 Bluetooth デバイス。

ヒント

Bluetooth の仕組みに関するページは Chrome の次の場所にあります。 about://bluetooth-internals にすることで、付近の情報をすべて検査できます。 Bluetooth デバイス: ステータス、サービス、特性、記述子。

Chrome で Bluetooth をデバッグするための内部ページのスクリーンショット Bluetooth デバイスをデバッグするための Chrome の内部ページ

また、公式のウェブ Bluetooth のバグを報告する方法を確認することもおすすめします。 をご覧ください。Bluetooth のデバッグは難しい場合があるためです。

次のステップ

まず、ブラウザとプラットフォームの実装ステータスを確認して、 の Web Bluetooth API が実装されています。

ワークショップの内容はまだ完了していませんが、今後のイベントの内容を一足先にご紹介します。 将来:

  • 付近の BLE アドバタイズのスキャン navigator.bluetooth.requestLEScan() で発生します。
  • 新しい serviceadded イベントにより、新しく検出された Bluetooth GATT サービスを追跡します。 一方、serviceremoved イベントは削除されたイベントをトラッキングします。新しい servicechanged イベントは、特性や記述子が追加されたり、 Bluetooth GATT サービスから削除されます。

API のサポートを表示する

Web Bluetooth API を使用する予定はありますか?皆様の公開サポートは、Chrome チームが 他のブラウザ ベンダーがそれらの機能をサポートすることの重要性を説明します。

ハッシュタグを使用して @ChromiumDev にツイートしてください #WebBluetooth を、どこで、どのように使用しているかをお知らせください。

リソース

謝辞

この記事の執筆にご協力いただいた Kayce Basques に感謝します。 ヒーロー画像提供: 米国ボルダーの SparkFun Electronics