Web Bluetooth(ウェブブルートゥース)

コミュニティグループ草案レポート

このドキュメントの詳細
このバージョン:
https://webbluetoothcg.github.io/web-bluetooth/
課題の追跡:
GitHub
仕様書内インライン
編集者:
(Google LLC)
(Google LLC)
GitHubでのコントリビューターを見る
翻訳 (参考情報):
日本語
参加する:
W3C コミュニティグループに参加
GitHubで本文を修正
public-web-bluetooth@w3.org (アーカイブ)
IRC: W3Cの #web-bluetooth チャンネル

概要

本書は、Bluetooth 4無線規格におけるGeneric Attribute Profile(GATT)を用いてデバイスの発見および通信を行うためのAPIについて記述しています。

この文書のステータス

この仕様はWeb Bluetooth コミュニティグループによって公開されました。 これはW3C標準ではなく、W3C標準化トラック上にもありません。 W3C Community Contributor License Agreement (CLA)の下では限定的なオプトアウトその他の条件が適用されることにご注意ください。 W3Cコミュニティおよびビジネスグループについて詳しくは、こちらをご覧ください。

この文書への変更は、https://github.com/WebBluetoothCG/web-bluetooth/commits/gh-pages で追跡できます。

この文書に関するコメントは、 public-web-bluetooth@w3.org購読アーカイブ)にお送りください。

1. はじめに

この節は規範的ではありません。

Bluetoothは、デバイス間の短距離無線通信のための標準です。Bluetooth「クラシック」(BR/EDR) は一連のバイナリプロトコルを定義しており、最大約24Mbpsまでの速度をサポートします。 Bluetooth 4.0では「Low Energy」モードが導入され、「Bluetooth Smart」や BLE、あるいは単に LEとも呼ばれます。 このモードは最大約1Mbpsに制限されていますが、デバイスがほとんどの時間送信機をオフにできるようにします。BLEは、 Generic Attribute Profile (GATT) によって提供されるキー/バリューのペアを通じて多くの機能を提供します。

BLEはデバイスが担うことのできる複数の役割を定義しています。 ブロードキャスターオブザーバー 役割はそれぞれ送信専用・受信専用の用途向けです。 ペリフェラル 役割のデバイスは接続を受け入れることができ、 セントラル 役割のデバイスは ペリフェラルデバイスへ接続できます。

ペリフェラル または セントラル役割で動作するデバイスは、 GATTサーバー をホストでき、 そこでは サービス, キャラクタリスティック, ディスクリプタ の階層を公開します。詳しくは §6.1 GATT情報モデル をご覧ください。この階層はBLEトランスポートを前提に設計されていますが、 GATTプロトコルはBR/EDRトランスポートでも動作可能です。

この仕様の最初のバージョンでは、UA上で セントラル役割で動作するウェブページが、 BR/EDRまたはLE接続経由で GATTサーバー に接続できるようにします。 この仕様は[BLUETOOTH42]仕様を参照していますが、 Bluetooth 4.0または4.1のみを実装した機器間の通信もサポートする意図です。

1.1.

標準的な心拍センサを検出しデータを取得するには、 ウェブサイトは以下のようなコードを利用します:
(省略:ソースコード部分は翻訳不要)

parseHeartRate() は、 heart_rate_measurementのドキュメント を参照し、DataView に格納された BluetoothRemoteGATTCharacteristicvalue フィールドから読み取る形で定義できます。

(省略:ソースコード部分は翻訳不要)

onHeartRateChanged()は以下のようなオブジェクトをログ出力するかもしれません

(省略:ソースコード部分は翻訳不要)

心拍センサがenergyExpended フィールドを報告している場合、 ウェブアプリケーションは heart_rate_control_point キャラクタリスティックに書き込みを行うことで、その値を0にリセットできます。

(省略:ソースコード部分は翻訳不要)

2. セキュリティに関する考慮事項

§3 プライバシーに関する考慮事項の節を参照してください。 [Issue #575]

3. プライバシーに関する考慮事項

3.1. デバイスアクセスは強力です

ウェブサイトが requestDevice() を使用してデバイスへのアクセスを要求すると、 呼び出しで指定したすべてのGATTサービスへのアクセス権を得ます。UAはどのような機能がウェブサイトに与えられるか、 デバイスの選択をユーザーに促す前にユーザーへ説明しなければなりません(MUST)。 指定されたサービスの中にUAが認識しないものがあれば、サイトがデバイスの完全制御を取得するリスクがあるものとして このことをユーザーに告知しなければなりません(MUST)。 また、ユーザーがどのサイトがどのデバイスへアクセス権を持っているかを確認し、 そのペアリングを取り消しできるようにもする必要があります。

UAはウェブサイトに対してデバイスクラス全体のペアリングを許可してはなりません(MUST NOT)。 各デバイスが同じBluetoothレベルの識別情報を送信するようなデバイスクラスを構築することが理論上は可能です。 UAはこの種の偽装を検出することを必ずしも求められず(MAY)、こうした擬似デバイスをウェブサイトとペアリングさせることもできます。

利用者が承認した主体のみが実際にアクセス権を持つことを確保するために、 この仕様ではセキュアコンテキストのみがBluetoothデバイスへアクセスできるよう制限されています。

3.2. 信頼できるサーバでも悪意あるコードを配信する可能性があります

この節は規範的ではありません。

ユーザーがオリジンを信頼していたとしても、そのオリジンのサーバや開発者が侵害されることや、 サイトがXSS攻撃の脆弱性を抱えていることがあります。どちらの場合でも、ユーザーが 悪意あるコードに価値あるデバイスへのアクセス権を与えてしまう可能性があります。オリジンは コンテンツセキュリティポリシー([CSP3])を定義してXSS攻撃リスクを低減すべきですが、 サーバや開発者自体が侵害されている場合にはこれは効果がありません。

§4.1 Permission APIとの連携 で説明されている通り、 ページのリロード後にも許可したデバイスを取得できる機能はこのリスクをさらに増大させます。 サイト侵害中に利用者からアクセス許可を取得する必要がなくなり、利用者が ただ訪れた場合でも過去に許可されたデバイスへのアクセスを攻撃者が得られるためです。 逆に、ページリロード間でもデバイスへのアクセスを維持できるとパーミッションのプロンプト表示回数が減るため、 利用者は表示されたプロンプトによく注意を払う可能性も高まります。

3.3. デバイスへの攻撃

この節は規範的ではありません。

ウェブサイトから送信される通信は、一部デバイスのセキュリティモデルを破る可能性があります。これらのデバイスは、信頼できる リモート機器のOSからのみ通信を受け取る前提で設計されている場合があります。ヒューマンインターフェースデバイス(HID)は顕著な例で、 ウェブサイトとの通信を許可するとそのサイトがキーストロークを記録できるようになります。この仕様には、 ウェブサイトの悪用を防ぐために、そうした脆弱なサービス・キャラクタリスティック・ディスクリプタの GATTブロックリスト が定義されています。

多くのデバイスは無線通信で予期しないデータを受け取ると脆弱になると考えられます。これまでは個々のデバイスごとに 攻撃が必要でしたが、このAPIにより大規模な攻撃が現実味を帯びてきます。この仕様ではこうした攻撃を困難にするために以下の対策を取っています:

UAはさらにユーザー保護のため、追加の対応を取ることが可能です:

3.4. Bluetoothデバイス識別子

この節は規範的ではありません。

各Bluetooth BR/EDRデバイスは BD_ADDR と呼ばれる固有の48ビットMACアドレスを持ちます。 Bluetooth LEデバイスは少なくとも パブリックデバイスアドレススタティックデバイスアドレス のいずれかを持ちます。 パブリックデバイスアドレス はMACアドレスです。 スタティックデバイスアドレスは再起動ごとに再生成される場合があります。 BR/EDR/LEデバイスはBD_ADDRパブリックデバイスアドレスRead BD_ADDR Commandで指定)に同じ値を使います。

LEデバイスはさらに一意な128ビットの Identity Resolving Key を持つ場合があり、 ボンディング時に信頼済みデバイスへ送信されます。恒久的な識別子の漏洩を避けるため、LEデバイスはスタティックまたは パブリックアドレスの代わりにランダムなリゾルバブル/ノンリゾルバブル プライベートアドレスでスキャンやアドバタイズを行う場合があります。 これらは定期的(約15分ごと)に再生成されますが、ペア済みデバイスは保存している IRK が与えられたリゾルバブルプライベートアドレスに一致するかを Resolvable Private Address Resolution Procedureで 判別できます。

各Bluetoothデバイスは人間が読める Bluetoothデバイス名 も持ちます。 これは一意である保証はありませんが、デバイス種類によっては一意となることもあります。

3.4.1. リモートBluetoothデバイスの識別子

この節は規範的ではありません。

ウェブサイトがいずれかの恒久的なデバイスIDを取得できる場合、それらを活用し周囲のデバイスを大規模にカタログ化することで 利用者の位置を割り出すことができます。また、同じBluetoothデバイスを2つの異なるウェブサイトで ペアリングした場合、そのユーザーが同一人物であることも特定可能です。 一方、多くのGATTサービスが指紋採取に利用できるため、デバイス側が意図的にカスタムGATTサービスを用いた 匿名化を簡単に行うこともできます。

この仕様は 注記 で、 スクリプトが同じデバイスかどうかを判定できることを利用者が意図していない場合は UAが一つのデバイスに対して異なるデバイスIDを用いることを推奨しており、 サイトによるデバイスアドレス乱用を困難にします。とはいえ、デバイスメーカーが 利用者追跡を補助するような設計を行うことは可能ですが、その分手間がかかります。

3.4.2. UAのBluetoothアドレス

この節は規範的ではありません。

BR/EDRモード、またはLEモード中で プライバシー機能 を用いずにアクティブスキャンしている場合、UAは自身の恒久的IDを周囲のBluetooth無線へ ブロードキャストします。これにより悪意のあるデバイスをエリア中にばらまいて UAの追跡が容易になります。2014-08時点でこの プライバシー機能 を実装していることを 文書化しているプラットフォームは少なく、 本仕様で推奨していても多くのUAでは採用されていない現実があります。 本仕様では ユーザー操作の要求 として UAがウェブサイトによるスキャンをトリガーするにはユーザーの操作が必要と義務付けており スキャンの頻度をある程度抑制していますが、 より多くのプラットフォームで プライバシー機能 をサポートすることが望ましいです。

3.5. Bluetooth利用可能性の暴露

この節は規範的ではありません。

navigator.bluetooth.getAvailability() はBluetooth無線がユーザーのシステムで利用可能かどうかを(電源の有無にかかわらず)公開します。 また、ユーザーがUAでWeb Bluetoothをブロックした場合も利用可能性に影響します。 一部のユーザーはこれをプライベートだと考えるかもしれませんが、 この情報暴露による実害は想像しづらいです。また、この情報はUAの フィンガープリント表面をわずかに拡大します。 この関数はPromise を返すため、UAが返す値についてユーザーに選択を促すことも理論上できますが、 リスク増加幅が十分に小さいため、ほとんどのUAはプロンプト表示しないと予想されます。

4. デバイス検出

dictionary BluetoothDataFilterInit {
  BufferSource dataPrefix;
  BufferSource mask;
};

dictionary BluetoothManufacturerDataFilterInit : BluetoothDataFilterInit {
  required [EnforceRange] unsigned short companyIdentifier;
};

dictionary BluetoothServiceDataFilterInit : BluetoothDataFilterInit {
  required BluetoothServiceUUID service;
};

dictionary BluetoothLEScanFilterInit {
  sequence<BluetoothServiceUUID> services;
  DOMString name;
  DOMString namePrefix;
  sequence<BluetoothManufacturerDataFilterInit> manufacturerData;
  sequence<BluetoothServiceDataFilterInit> serviceData;
};

dictionary RequestDeviceOptions {
  sequence<BluetoothLEScanFilterInit> filters;
  sequence<BluetoothLEScanFilterInit> exclusionFilters;
  sequence<BluetoothServiceUUID> optionalServices = [];
  sequence<unsigned short> optionalManufacturerData = [];
  boolean acceptAllDevices = false;
};

[Exposed=Window, SecureContext]
interface Bluetooth : EventTarget {
  Promise<boolean> getAvailability();
  attribute EventHandler onavailabilitychanged;
  [SameObject]
  readonly attribute BluetoothDevice? referringDevice;
  Promise<sequence<BluetoothDevice>> getDevices();
  Promise<BluetoothDevice> requestDevice(optional RequestDeviceOptions options = {});
};

Bluetooth includes BluetoothDeviceEventHandlers;
Bluetooth includes CharacteristicEventHandlers;
Bluetooth includes ServiceEventHandlers;

この仕様で定義されるメソッドは通常非同期に完了し、Bluetooth タスクソースに作業をキューイングします。

注記: Bluetooth メンバー
注記: getAvailability() はページに対して、Bluetooth が 利用可能かどうかを通知します。ソフトウェアによって無効化されたアダプターも 利用可能と見なされるべきです。利用可能性の変化(たとえばユーザーが物理的に アダプターを接続/取り外ししたとき)は availabilitychanged イベントで通知されます。

referringDevice は、ユーザーがこのページを開いた元のデバイス(存在する場合) へのアクセスを提供します。たとえば Eddystone ビーコンが URL をアドバタイズし、UA がその URL を開くことをユーザーに許可するケースです。 ビーコンを表す BluetoothDevicenavigator.bluetooth.referringDevice を通して利用できます。

getDevices() は、ユーザーがアクセスを許可した Bluetooth デバイスをページが取得できるようにします。

requestDevice(options) は、このオリジンに対し、いずれかのフィルターに一致するが options.filters 内の いずれのフィルターにも一致しない デバイスへのアクセスをユーザーに求めます(除外フィルターは options.exclusionFilters)。 フィルターに一致するために、 デバイスは以下を満たす必要があります:

Manufacturer Specific DataService Data はいずれもキーから バイト配列へのマッピングです。BluetoothDataFilterInit はこれらの配列をフィルタします。配列は、prefix が存在し、 prefix & mask が 次と等しい場合に一致します: dataPrefix & mask

デバイスが接続時に挙動を大きく変える場合(例: 識別用のメーカー固有データの広告を止め、 クライアント側で識別可能な GATT サービスを発見させるなど)、ウェブサイトは 両方の挙動に対応するフィルターを含める必要があるかもしれません。

まれに、サイトが不要なデバイスをフィルタリングするのに十分な識別情報をデバイスが 広告しない場合があります。その場合、サイトは acceptAllDevicestrue に設定し、 filtersexclusionFilters をすべて省略できます。これにより適切なデバイスの選択責任は完全に サイトのユーザーに委ねられます。acceptAllDevices を使用する場合、 optionalServices に列挙されたサービスのみが利用可能になります。

ユーザーがこのオリジンとペアにするデバイスを選択した後、オリジンは services リストに含まれる UUID のいずれかを options.filters のいずれかの要素、または options.optionalServices に列挙しているサービスにアクセスできます。 また、デバイスの広告データ中の options.optionalManufacturerData に定義されたメーカーコードのメーカー固有データにもアクセスできます。

これは、開発者が名前だけでフィルタリングする場合、任意のサービスにアクセスするには optionalServices を使用しなければならないことを意味します。

UA が以下のデバイスの近くにあるとします:
デバイス 広告されているサービス
D1 A, B, C, D
D2 A, B, E
D3 C, D
D4 E
D5 <none>

ウェブサイトが次を呼び出した場合

navigator.bluetooth.requestDevice({
  filters: [ {services: [A, B]} ]
});

ユーザーには D1 と D2 を含むダイアログが表示されます。ユーザーが D1 を選ぶと、 ウェブサイトはサービス C と D にアクセスできません。ユーザーが D2 を選ぶと、 ウェブサイトはサービス E にアクセスできません。

一方、ウェブサイトが次を呼び出した場合

navigator.bluetooth.requestDevice({
  filters: [
    {services: [A, B]},
    {services: [C, D]}
  ]
});

ダイアログには D1、D2、D3 が含まれ、ユーザーが D1 を選べば、 ウェブサイトは A、B、C、D のサービスにアクセスできます。

その後ウェブサイトが次を呼び出した場合

navigator.bluetooth.getDevices();

結果の Promise は D1 を含む配列に解決され、 ウェブサイトは A、B、C、D のサービスにアクセスできます。

optionalServices リストは、ユーザーに表示されるダイアログに デバイスを追加することはありませんが、ユーザーが選択したデバイスから ウェブサイトが利用できるサービスには影響します。

navigator.bluetooth.requestDevice({
  filters: [ {services: [A, B]} ],
  optionalServices: [E]
});

D4 は必須サービスを含まないため、D1 と D2 を含むダイアログが表示されます。 ユーザーが D2 を選んだ場合、最初の例と異なり、ウェブサイトは A、B、E の サービスにアクセスできます。

ウェブサイトが再び

navigator.bluetooth.getDevices();

を呼び出すと、結果の Promise は D1 と D2 を含む配列に解決されます。D1 では A、B、C、D のサービスが、 D2 では A、B、E のサービスが利用可能です。

許可されたサービスは、ユーザーがアクセスを許可した後にデバイスが変化した場合にも 適用されます。たとえば、前の requestDevice() 呼び出しでユーザーが D1 を 選択し、その後 D1 が新しい E サービスを追加した場合、 serviceadded イベントが発火し、ウェブページはサービス E にアクセスできるようになります。

前の例のデバイスが、次のような名前も アドバタイズしているとします:
デバイス 広告されているデバイス名
D1 First De…
D2 <none>
D3 Device Third
D4 Device Fourth
D5 Unique Name

次の表は、navigator.bluetooth.requestDevice({filters: filters}) に 渡される filters の値ごとに、ユーザーがどのデバイスを選べるかを示します。

filters デバイス 注記
[{name: "Unique Name"}]
D5
[{namePrefix: "Device"}]
D3, D4
[{name: "First De"},
  {name: "First Device"}]
<none> D1 は名前の接頭辞のみを広告しているため、完全な名前を一致させようとしても 失敗します。
[{namePrefix: "First"},
  {name: "Unique Name"}]
D1, D5
[{services: [C],
  namePrefix: "Device"},
  {name: "Unique Name"}]
D3, D5

次の表は、navigator.bluetooth.requestDevice({filters: filters, exclusionFilters: exclusionFilters}) に渡される filters および exclusionFilters の値ごとに、 ユーザーがどのデバイスを選べるかを示します。

filters exclusionFilters デバイス
[{namePrefix: "Device"}]  // D3, D4
[{name: "Device Third"}]   // D3
D4
[{namePrefix: "Device"}]  // D3, D4
[{namePrefix: "Device F"}] // D4
D3
[{services: [C]},         // D1, D3
  {namePrefix: "Device"}] // D3, D4
[{services: [A]},          // D1
  {name: "Device Fourth"}] // D4
D3
前の例のデバイスが、次のような メーカー/サービスデータも広告しているとします:
デバイス メーカー固有データ サービスデータ
D1 17: 01 02 03
D2 A: 01 02 03

次の表は、navigator.bluetooth.requestDevice({filters: filters}) に 渡される filters の値ごとに、ユーザーがどのデバイスを選べるかを示します。

filters デバイス
[{ manufacturerData: [{ companyIdentifier: 17 }] }]
D1
[{ serviceData: [{ service: "A" }] }]
D2
[
  { manufacturerData: [{ companyIdentifier: 17 }] },
  { serviceData: [{ service: "A" }] },
]
D1, D2
[
  {
    manufacturerData: [{ companyIdentifier: 17 }],
    serviceData: [{ service: "A" }],
  },
]
<none>
[
  {
    manufacturerData: [
      {
        companyIdentifier: 17,
        dataPrefix: new Uint8Array([1, 2, 3])
      },
    ],
  },
]
D1
[
  {
    manufacturerData: [
      {
        companyIdentifier: 17,
        dataPrefix: new Uint8Array([1, 2, 3, 4])
      },
    ],
  },
]
<none>
[
  {
    manufacturerData: [
      {
        companyIdentifier: 17,
        dataPrefix: new Uint8Array([1])
      },
    ],
  },
]
D1
[
  {
    manufacturerData: [
      {
        companyIdentifier: 17,
        dataPrefix: new Uint8Array([0x91, 0xAA]),
        mask: new Uint8Array([0x0f, 0x57]),
      },
    ],
  },
]
D1
[
  {
    manufacturerData: [
      { companyIdentifier: 17 },
      { companyIdentifier: 18 },
    ]
  }
]
<none>
すべてのデバイスを受け入れる、または拒否するフィルターは TypeError を引き起こします。 すべてのデバイスを受け入れるには、代わりに acceptAllDevices を使用してください。
呼び出し 注記
requestDevice({})
無効: フィルターのリストが欠如していると、どのデバイスも受け入れません。
requestDevice({filters:[]})
無効: 空のフィルターリストは、どのデバイスも受け入れません。
requestDevice({filters:[{}]})
無効: 空のフィルターはすべてのデバイスを受け入れてしまうため、これも許可されません。
requestDevice({
  acceptAllDevices:true
})
有効: acceptAllDevices で明示的にすべてのデバイスを受け入れます。
requestDevice({
  filters: [...],
  acceptAllDevices:true
})
無効: acceptAllDevices は任意の filters を上書きしてしまいます。
requestDevice({
  exclusionFilters: [...],
  acceptAllDevices:true
})
無効: acceptAllDevices は任意の exclusionFilters を上書きしてしまいます。
requestDevice({
  exclusionFilters: [...]
})
無効: exclusionFilters には filters が必要です。
requestDevice({
  filters: [...],
  exclusionFilters: []
})
無効: デバイスを除外するには、exclusionFilters は空であってはなりません。
requestDevice({
  filters: [{namePrefix: ""}]
})
無効: namePrefix は、存在する場合、デバイスをフィルタするために空であってはなりません。
requestDevice({
  filters: [{manufacturerData: []}]
})
無効: manufacturerData は、存在する場合、デバイスをフィルタするために空であってはなりません。
requestDevice({
  filters: [{serviceData: []}]
})
無効: serviceData は、存在する場合、デバイスをフィルタするために空であってはなりません。

Bluetooth のインスタンスは、 次の表に示す 内部スロットを持って作成されます:

内部スロット 初期値 説明(非規範)
[[deviceInstanceMap]] Bluetooth デバイスから BluetoothDevice インスタンスへの空のマップ。 単一のグローバルオブジェクト内で、各 Bluetooth デバイスを一つの BluetoothDevice インスタンスのみが表現することを保証します。
[[attributeInstanceMap]] Bluetooth キャッシュのエントリから Promise への空のマップ。 これらの Promise は、BluetoothRemoteGATTServiceBluetoothRemoteGATTCharacteristic、 あるいは BluetoothRemoteGATTDescriptor インスタンスのいずれかに解決されます。
[[referringDevice]] null Document がデバイスから開かれた場合、Document オブジェクトの初期化中に BluetoothDevice に設定されます。
navigator.bluetooth.referringDevice の 取得は [[referringDevice]] を返さなければなりません。
一部の UA は、ユーザーが 閲覧コンテキストを、移動させるようにする場合があります(Bluetooth デバイスへの反応として)。
注記: たとえば、Eddystone ビーコンが URL を広告する場合、UA はユーザーがその URL に遷移することを 許可するかもしれません。

これが起こった場合、Document オブジェクトの初期化の一環として、 UA は次の手順を実行しなければなりません(MUST):

  1. ナビゲーションを引き起こしたデバイスを referringDevice とします。

  2. BluetoothDevice を取得し、 navigator.bluetooth 内で referringDevice を表す オブジェクトを referringDeviceObj とします。

  3. 前の手順が例外を投げた場合、これらの手順を中止します。

    注記: これは、UA がユーザーが現在の realmreferringDevice への アクセスを付与する意図を推論しなかったことを意味します。たとえば、ユーザーが GATT へのアクセスを全体的に拒否している場合などです。
  4. navigator.bluetooth.[[referringDevice]]referringDeviceObj に設定します。

Bluetooth デバイス device は、以下の手順が match を返すとき、 filter一致する とみなされます:
  1. filter.name が存在し、かつ deviceBluetooth デバイス名 が 完全一致で filter.name と等しくない場合、 mismatch を返します。

  2. filter.namePrefix が存在し、deviceBluetooth デバイス名 が存在しない、 あるいは filter.namePrefix で始まらない場合、 mismatch を返します。

  3. filter.services 内の各 uuid について、UA が当該デバイスが UUID uuid の プライマリ(含有ではない)サービスをサポートしていることを示す 広告データ、拡張問い合わせ応答、 あるいはサービスディスカバリ応答を受信していない場合、 mismatch を返します。

  4. filter["manufacturerData"] 内の各 manufacturerData について、 deviceメーカー固有データを、 manufacturerData["companyIdentifier"] と等しい会社識別子コードかつ 一致するデータで広告していない場合、 mismatch を返します。

  5. filter["serviceData"] 内の各 serviceData について、 device が次の条件で サービスデータを広告していない場合、 mismatch を返します。すなわち、UUID の 128-bit 形式が serviceData["service"] であり、かつデータが 一致 すること。

  6. match を返します。

バイト配列 data が、 BluetoothDataFilterInit filter一致 するのは、 以下の手順が match を返す場合です。
注記: このアルゴリズムは、filter がすでに 正規化されていると仮定します。
  1. expectedPrefix を、保持しているバイト列のコピーとした filter.dataPrefix とします。

  2. mask を、保持しているバイト列のコピーとした filter.mask とします。

  3. data のバイト数が expectedPrefix より少ない場合、 mismatch を返します。

  4. mask の各 1 ビットについて、data の対応ビットが expectedPrefix の対応ビットと等しくない場合、 mismatch を返します。

  5. match を返します。

BluetoothDataFilterInit filter1 が、BluetoothDataFilterInit filter2真部分集合であるのは、 以下の手順が true を返す場合です:
  1. filter1 の長さが filter2 の長さより短い場合、 false を返します。

  2. byteIndex0 にします。

  3. byteIndexfilter2 の長さ未満の間、次の副手順を実行します:

    1. filter1.mask[byteIndex] & filter2.mask[byteIndex]filter2.mask[byteIndex] と等しくない場合、false を返します。

    2. filter1.dataPrefix[byteIndex] & filter2.mask[byteIndex]filter2.dataPrefix[byteIndex] & filter2.mask[byteIndex] と等しくない場合、false を返します。

    3. byteIndexbyteIndex + 1 に設定します。

  4. true を返します。

デバイスが広告するサービス UUID の一覧には、当該デバイスがサポートする すべての UUID が含まれない場合があります。広告データは、この一覧が完全かどうかを 指定します。ウェブサイトが、近傍のデバイスがサポートしているものの広告していない UUID を 用いてフィルタリングする場合、そのデバイスはユーザーに提示される一覧に 含まれないかもしれません。UA は、サポートされるサービスの完全な一覧を発見するために デバイスへ接続する必要がありますが、これは無線のパフォーマンスを低下させ、 遅延を引き起こす可能性があるため、本仕様はそれを要求しません。
getDevices() メソッドは、 BluetoothPermissionStorage storage が与えられて呼び出されたとき、次の手順を 実行しなければなりません(MUST):
  1. global を、this関連付けられたグローバルオブジェクトとします。

  2. global関連する Document が "bluetooth" という ポリシー制御機能使用可能でない場合、 拒否された PromiseSecurityError で返します。

  3. promise新しい Promise とします。

  4. 次の手順を並行して実行します:

    1. devices を新しい空の Array とします。

    2. storage.allowedDevices 内の各 allowedDevice について、 allowedDevice@[[device]] を表す BluetoothDevice オブジェクトを devices に追加します。

    3. グローバルタスクをキューし、 Bluetooth タスクソース上で global に与え、resolve により promisedevices で解決します。

    注記: devices 内の BluetoothDevice は、Bluetooth 無線の範囲内にない場合があります。devices 内のある device については、watchAdvertisements() を用いて、device が範囲内にあり広告パケットを 送信しているタイミングを観測できます。device 上で advertisementreceived イベント event が発火したとき、 event.device.gatt.connect() を呼び出すことで接続が確立できる程度に近いことを示す可能性があります。
  5. promise を返します。

requestDevice(options) メソッドは、呼び出されたとき、次の手順を実行しなければなりません(MUST):
  1. options.exclusionFilters が存在し、 options.filters が存在しない場合、 拒否された PromiseTypeError で返します。

  2. options.filters が存在し、 options.acceptAllDevicestrue の場合、あるいは options.filters が存在せず、 options.acceptAllDevicesfalse の場合、 拒否された PromiseTypeError で返します。

    注記: これは、filtersacceptAllDevices:true のいずれか一方のみが存在することを強制します。
  3. promise新しい Promise とします。

  4. 次の手順を並行して実行します:

    1. Bluetooth デバイスを要求し、 options.filters を、 options.acceptAllDevicesfalse の場合に渡し、そうでなければ null を渡します。 options.exclusionFilters が存在する場合はそれを、なければ null を渡し、 options.optionalServicesoptions.optionalManufacturerData を渡します。結果を devices とします。

    2. グローバルタスクをキューし、 Bluetooth タスクソース上で、 this関連付けられたグローバルオブジェクトに与えて、 次の手順を実行します:

      1. 前の手順が例外を投げた場合、reject により promise をその例外で拒否し、これらの手順を中止します。

      2. devices が空のシーケンスである場合、reject により promiseNotFoundError で拒否し、これらの手順を中止します。

      3. Resolve により promisedevices[0] で解決します。

  5. promise を返します。

Bluetooth デバイスを要求するには、 次が与えられたとき、UA は次の手順を実行しなければなりません(MUST): BluetoothPermissionStorage storageBluetoothLEScanFilterInit のシーケンス filtersnull の場合はすべてのデバイスが一致可能であることを表す)、 BluetoothLEScanFilterInit のシーケンス exclusionFilters(除外フィルターが設定されていない場合は null)、 BluetoothServiceUUID のシーケンス optionalServices、および unsigned short のシーケンス optionalManufacturerData
注記: これらの手順はブロックする可能性があるため、このアルゴリズムの呼び出しは 並行して行う必要があります。
注記: このアルゴリズムの呼び出しは、最終的には複数のデバイスを要求できるようになりますが、 現状では常に 1 つのみを返します。
  1. global を、storage関連付けられたグローバルオブジェクトとします。

  2. document を、global関連する Document とします。

  3. document が "bluetooth" という ポリシー制御機能使用可能でない場合、 SecurityError を投げ、これらの手順を中止します。

  4. このアルゴリズムが、 関連付けられたグローバルオブジェクト一時的なアクティベーションがある間に トリガーされていることを確認し、そうでなければ SecurityError を投げ、これらの手順を中止します。

  5. サービス名やエイリアスを UUID に 変換するため、次の副手順を実行します:

    1. filters !== null && filters.length === 0 の場合、 TypeError を投げ、これらの手順を中止します。

    2. exclusionFilters !== null && exclusionFilters.length === 0 の場合、 TypeError を投げ、これらの手順を中止します。

    3. uuidFilters を新しい ArrayuuidExclusionFilters を新しい ArrayrequiredServiceUUIDs を新しい Set とします。

    4. filtersnull の場合、 requiredServiceUUIDs をすべての UUID の集合に設定します。

    5. filtersnull でない場合、filters 内の各 filter について次を実行します:

      1. canonicalFilter を、 filter正規化した結果とします。

      2. canonicalFilteruuidFilters に追加します。

      3. canonicalFilter.services の中身を requiredServiceUUIDs に追加します。

    6. exclusionFiltersnull でない場合、 exclusionFilters 内の各 exclusionFilter について 次を実行します:

      1. canonicalExclusionFilter を、 exclusionFilter正規化した結果とします。

      2. canonicalExclusionFilteruuidExclusionFilters に追加します。

    7. optionalServiceUUIDsArray.prototype.map.call(optionalServices, BluetoothUUID.getService) とします。

    8. BluetoothUUID.getService() の呼び出しのいずれかが例外を投げた場合、その例外を投げ、手順を中止します。

    9. optionalServiceUUIDs から、 ブロックリストにある UUID を すべて取り除きます。

  6. descriptor を次のようにします:

    {
      name: "bluetooth",
      filters: uuidFilters
      optionalServices: optionalServiceUUIDs,
      optionalManufacturerData: optionalManufacturerData
      acceptAllDevices: filters !== null,
    }
    
  7. state を、descriptorpermission state とします。

    注記: 非セキュアコンテキストでは、強力な機能は 非セキュアコンテキストで使用できないため、 state は "denied" になります。
  8. state が "denied" の場合、 [] を返し、これらの手順を中止します。

  9. UA が次の手順でデバイスを見つけられないことを証明できる場合(例: スキャンに使用できる Bluetooth アダプターが存在しない、またはフィルターがいかなる広告パケットにも一致しえない場合)、UA は [] を返してこれらの手順を中止しても構いません(MAY)。

  10. scanResult を、デバイスをスキャンglobal および requiredServiceUUIDs とともに呼び出した結果とします。

  11. filtersnull でない場合、次の副手順を実行します:

    1. uuidFilters 内の フィルターに一致しないデバイスを scanResult から削除します。

    2. exclusionFiltersnull でない場合、 uuidExclusionFilters 内の フィルターに一致するデバイスを scanResult から削除します。

  12. navigable を、documentnavigable とします。

  13. promptId を、新しい一意の不透明な文字列とします。

実際には、プロンプトが開いている間に デバイスリストは動的に更新されます。仕様テキストは現在それを反映していませんが、 同じ promptId と最新のデバイスリストでこのイベントが複数回送出される可能性があります。 参照: https://github.com/WebBluetoothCG/web-bluetooth/issues/621.

  1. プロンプト更新イベントをトリガーし、 navigablepromptIdscanResult を渡します。

  2. scanResult が空であっても、 ユーザーに選択を促すことで scanResult 内のいずれかのデバイスを、descriptor と関連付けて選ばせ、 その結果を device とします。

    UA は、uuidFilters に一致しない近傍のデバイスを 選択できるようにしても構いません(MAY)。

    注記: UA は各デバイスの人間可読な名前をユーザーに表示するべきです。 この名前が利用できない場合(たとえば、UA の Bluetooth システムが プライバシー有効のスキャンをサポートしていないなど)、UA はユーザーが 関心を示せるようにし、その後プライバシー無効のスキャンを行って 名前を取得できるようにすべきです。
  3. 削除します: navigable からデバイスプロンプトへのマップ[navigablenavigable id]。

  4. UA は devicestorage に追加 しても構いません(MAY)。

    注記: device を選択することは、おそらくユーザーが当該デバイスを "bluetooth"追加の許可データallowedDevices リスト(少なくとも 現在の設定オブジェクト)に 表示する意図を持つことを意味します。また、その mayUseGATT フィールドを true にし、 requiredServiceUUIDsoptionalServiceUUIDs の和集合内のすべてのサービスを、 すでに存在しているサービスに加えてその allowedServices リストに含め、さらに optionalManufacturerData のメーカーコードをその allowedManufacturerData リストに含めることを意味します。
  5. device が "denied" の場合、 [] を返し、これらの手順を中止します。

  6. UA は、device 内のすべてのサービスで Bluetooth キャッシュを構築 しても構いません(MAY)。この手順でのエラーは無視します。

  7. BluetoothDevice を取得し、 例外を伝播させつつ this の内部で device を表す deviceObj を結果とします。

  8. [deviceObj] を返します。

正規化の結果として、 BluetoothLEScanFilterInit filter から返されるのは、次の手順で得られる BluetoothLEScanFilterInit です:
  1. filter のメンバーが一つも存在しない場合、TypeError を投げて、これらの手順を中止します。

  2. canonicalizedFilter{} とします。

  3. filter.services が 存在する場合、次の副手順を実行します:

    1. filter.services.length === 0 の場合、TypeError を投げて、これらの手順を中止します。

    2. servicesArray.prototype.map.call(filter.services, BluetoothUUID.getService) とします。

    3. BluetoothUUID.getService() の呼び出しのいずれかが例外を投げた場合、その例外を投げてこれらの手順を中止します。

    4. services 内のいずれかのサービスが ブロックリストにある場合、SecurityError を投げて、これらの手順を中止します。

    5. canonicalizedFilter.servicesservices に設定します。

  4. filter.name が 存在する場合、次の副手順を実行します。

    1. UTF-8 エンコードした filter.name が 248 バイトを超える場合、TypeError を投げて、これらの手順を中止します。

      注記: 248 は、Bluetooth デバイス名における UTF-8 のコード単位の最大数です。
    2. canonicalizedFilter.namefilter.name に設定します。

  5. filter.namePrefix が 存在する場合、次の副手順を実行します。

    1. filter.namePrefix.length === 0 の場合、または UTF-8 エンコードした filter.namePrefix が 248 バイトを超える場合、 TypeError を投げて、これらの手順を中止します。

      注記: 248 は、Bluetooth デバイス名における UTF-8 のコード単位の最大数です。
    2. canonicalizedFilter.namePrefixfilter.namePrefix に設定します。

  6. canonicalizedFilter["manufacturerData"][] に設定します。

  7. filter["manufacturerData"] が 存在し、かつ filter["manufacturerData"].length === 0 の場合、 TypeError を投げて、これらの手順を中止します。

  8. filter["manufacturerData"] 内の各 manufacturerData について、次の副手順を実行します:

    1. manufacturerDataブロックリストにあるメーカー固有データフィルター の場合、SecurityError を投げて、これらの手順を中止します。

    2. canonicalizedFilter["manufacturerData"] 内に existing["companyIdentifier"] === manufacturerData["companyIdentifier"] を満たすオブジェクト existing が存在する場合、TypeError を投げて、これらの手順を中止します。

    3. canonicalizedManufacturerDataFilter を、 正規化した manufacturerDataECMAScript 値に変換した結果とします。 これが例外を投げた場合、その例外を伝播させてこれらの手順を中止します。

    4. canonicalizedManufacturerDataFilter["companyIdentifier"]manufacturerData["companyIdentifier"] に設定します。

    5. canonicalizedManufacturerDataFiltercanonicalizedFilter["manufacturerData"] に追加します。

  9. canonicalizedFilter.serviceData[] に設定します。

  10. filter["serviceData"] が 存在し、かつ filter["serviceData"].length === 0 の場合、TypeError を投げて、これらの手順を中止します。

  11. filter["serviceData"] 内の各 serviceData について、次の副手順を実行します:

    1. serviceBluetoothUUID.getService(serviceData["service"]) とします。これが例外を投げた場合、その例外を伝播させてこれらの手順を中止します。

    2. serviceブロックリストにある場合、SecurityError を投げて、これらの手順を中止します。

    3. canonicalizedServiceDataFilter を、 正規化した serviceDataECMAScript 値に変換した結果とします。 これが例外を投げた場合、その例外を伝播させてこれらの手順を中止します。

    4. canonicalizedServiceDataFilter["service"]service に設定します。

    5. canonicalizedServiceDataFiltercanonicalizedFilter["serviceData"] に追加します。

  12. canonicalizedFilter を返します。

正規化の結果として、 BluetoothDataFilterInit filter から返されるのは、次の手順で得られる BluetoothDataFilterInit です:
  1. filter.dataPrefix が 存在しない場合、dataPrefix を空のバイト列とします。そうでない場合、 次の副手順を実行します:

    1. dataPrefix を、保持しているバイト列のコピーである filter.dataPrefix とします。

    2. dataPrefix の長さが 0 の場合、TypeError を投げて、これらの手順を中止します。

  2. filter.mask が存在する場合、 mask保持しているバイト列のコピーである filter.mask とします。 そうでない場合、maskdataPrefix と同じ長さの 0xFF バイトの列とします。

  3. mask の長さが dataPrefix と同じでない場合、TypeError を投げて、 これらの手順を中止します。

  4. {dataPrefix: new Uint8Array(|dataPrefix|), mask: new Uint8Array(|mask|)} を返します。

デバイスをスキャン するには、パラメーター global と任意の Service UUID の集合(省略時はすべての UUID の集合)を受け取り、 UA は次の手順を実行します:
  1. UA が直近に、今回のスキャンで用いる UUID の集合を包含する UUID の集合でスキャンを行っている場合、 その結果を返して、これらの手順を中止してもよいです(MAY)。

    TODO: 期間を確定する。

  2. nearbyDevicesBluetooth デバイスの集合とし、初期値は UA に 接続されている(ATT Bearer を持つ)デバイスの集合とします。

  3. topLevelTraversable を、globalnavigabletop-level traversable とします。

  4. simulatedBluetoothDevices を空の list とします。

  5. topLevelTraversableシミュレートされた Bluetooth アダプター を持つ場合、 値を取得して得られる シミュレートされた Bluetooth デバイス対応表 の値を simulatedBluetoothDevices とします。

    非同期のデバイス検出をサポートする。

  6. UA が LE トランスポートをサポートしている場合、General Discovery Procedure を実行します。ただし、UA は Discoverable Mode フラグが設定されていないデバイスも含めてもよく、検出した Bluetooth デバイスnearbyDevices に追加します。UA は Privacy Feature を有効にすべきです(SHOULD)。

    受動スキャンPrivacy Feature の双方は、 一意で不変なデバイス ID の漏洩を回避します。UA にいずれかの使用を要求すべきですが、 どの OS API もこれらを提供していないようです。さらに Bluetooth では、 Central デバイスに Observation Procedure のサポートが要求されないため、 受動スキャン の利用が難しいです。

  7. UA が BR/EDR トランスポートをサポートしている場合、Device Discovery Procedure を実行し、検出した Bluetooth デバイスnearbyDevices に追加します。

    すべての形態の BR/EDR の問い合わせ/検出は、一意で不変のデバイスアドレスを漏らすように見えます。

  8. result を空の Bluetooth デバイスの集合とします。

  9. nearbyDevices および simulatedBluetoothDevices 内の各 Bluetooth デバイス device について、 次の副手順を実行します:

    1. deviceサポートされる物理トランスポートに LE が含まれ、 かつその Bluetooth デバイス名 が不完全または存在しない場合、 UA は完全な名前を取得するため Name Discovery Procedure を実行すべきです(SHOULD)。

    2. device が広告している Service UUIDs と、 Service UUID の集合 の共通部分が空でない場合、 deviceresult に追加し、これらの副手順を中断します。

      注記: BR/EDR デバイスでは、 Extended Inquiry Response において GATT と非 GATT のサービスを区別する方法がありません。サイトが非 GATT サービスの UUID で フィルターした場合、ユーザーは requestDevice の結果として選択できるものの、 この API では相互作用手段のないデバイスを選んでしまう可能性があります。
    3. UA は device に接続し、Bluetooth キャッシュを構築して、 UUID が Service UUID の集合 に含まれるすべてのサービスを格納してもよいです(MAY)。deviceサポートされる物理トランスポートに BR/EDR が含まれる場合、 標準的な GATT 手順に加えて、キャッシュの構築時に Service Discovery Protocol(Searching for Services)を使用してもよいです(MAY)。

      注記: 近傍のすべてのデバイスに接続してサービスを発見することは電力を消費し、 Bluetooth 無線の他の利用を遅くする可能性があります。UA は、そのデバイスが有用であると期待できる理由がある場合にのみ、 追加のサービス発見を行うべきです。

      また UA は、開発者がこの追加発見の挙動に依存しないよう支援すべきです。例えば、 開発者が以前にそのデバイスへ接続しており、UA がそのデバイスの完全なサポートサービス集合を把握しているとします。 この開発者が広告されていない UUID でフィルタした場合、ユーザーの環境ではフィルタにより 除外されるであろうデバイスであっても、ダイアログに含まれることがあります。UA は、 この状況を警告する開発者向けオプションを提供したり、一致判定で広告済みサービスのみに限定する オプションを提供したりできます。

    4. Bluetooth キャッシュに、 device 内の既知の存在するサービスのうち、 Service UUID の集合 に 含まれる UUID を持つものが含まれている場合、UA は deviceresult に追加してもよいです(MAY)。

  10. スキャンの結果として result を返します。

興味深いデバイスが到達範囲内に入ったときに、 サイトがイベントを受け取れるよう登録する手段が必要です。

許可された Bluetooth デバイスを追加するために、 requiredServiceUUIDs の集合と optionalServiceUUIDs の集合が与えられた BluetoothPermissionStorage storagedevice を追加する際、UA は次の手順を実行します:
  1. grantedServiceUUIDs を新しい Set とします。

  2. requiredServiceUUIDs の内容を grantedServiceUUIDs に追加します。

  3. optionalServiceUUIDs の内容を grantedServiceUUIDs に追加します。

  4. storage.allowedDevices 内で、 deviceallowedDevice@[[device]] と等しい要素 allowedDevice を検索します。見つかった場合は次の副手順を実行します:

    1. allowedDevice.allowedServices の内容を grantedServiceUUIDs に追加します。

    見つからなかった場合は次の副手順を実行します:

    1. allowedDevice.deviceId を、UA が 2 つの Bluetooth 接続が同一デバイスであると判定できる範囲、 かつ ユーザーがその事実をスクリプトに公開したいと望む範囲で 一意の ID とします。

  5. allowedDevice.allowedServicesgrantedServiceUUIDs に設定します。

  6. allowedDevice.mayUseGATTtrue に設定します。

許可された Bluetooth デバイスを削除するには、BluetoothPermissionStorage storagedevice が与えられた場合、UA は次の手順を実行します:

  1. storage.allowedDevices 内で、 deviceallowedDevice@[[device]] と等しい要素 allowedDevice を検索します。そのような要素が存在しない場合、これらの手順を中止します。

  2. allowedDevicestorage.allowedDevices から削除します。

4.1. Permission API との統合

[permissions] API は、 ウェブサイトが自身に付与されている権限を照会するための統一的な方法を提供します。

いったんサイトにデバイス集合へのアクセスが許可されると、navigator.permissions.query({name: "bluetooth", ...}) を用いて、 リロード後にそれらのデバイスを取得できます。
navigator.permissions.query({
  name: "bluetooth",
  deviceId: sessionStorage.lastDevice,
}).then(result => {
  if (result.devices.length == 1) {
    return result.devices[0];
  } else {
    throw new DOMException("Lost permission", "NotFoundError");
  }
}).then(...);

Web Bluetooth API は 強力な機能であり、 name "bluetooth" によって識別されます。 その権限に関するアルゴリズムおよび型は次のとおり定義されます。

許可ディスクリプタ型
dictionary BluetoothPermissionDescriptor : PermissionDescriptor {
  DOMString deviceId;
  // これらは RequestDeviceOptions に一致します。
  sequence<BluetoothLEScanFilterInit> filters;
  sequence<BluetoothServiceUUID> optionalServices = [];
  sequence<unsigned short> optionalManufacturerData = [];
  boolean acceptAllDevices = false;
};
追加の許可データ型
BluetoothPermissionStorage は次のように定義されます。
dictionary AllowedBluetoothDevice {
  required DOMString deviceId;
  required boolean mayUseGATT;
  // allowedServices が "all" の場合、すべてのサービスが許可されることを意味します。
  required (DOMString or sequence<UUID>) allowedServices;
  required sequence<unsigned short> allowedManufacturerData;
};
dictionary BluetoothPermissionStorage {
  required sequence<AllowedBluetoothDevice> allowedDevices;
};

AllowedBluetoothDevice インスタンスは、内部スロット [[device]] を持ち、 そこに Bluetooth device を保持します。

追加の許可データの制約
allowedDevices の要素はそれぞれ、 異なる [[device]] と 異なる deviceId を持たなければなりません。

mayUseGATTfalse の場合、 allowedServicesallowedManufacturerData はどちらも [] でなければなりません。

注記: deviceId により、サイトはある時点で観測した BluetoothDevice インスタンスが、別の時点(場合によっては異なる realm)で観測した別の BluetoothDevice インスタンスと同一のデバイスであることを追跡できます。UA は、 "bluetooth"追加の許可データ を返す際に、 ユーザーがその追跡を望むか否かを考慮すべきです。

例えば、一般にユーザーは、異なる 2 つのオリジンが同一のデバイスとやり取りしていると 知ることを望まず、また通常はオリジンのクッキーを削除した後に一意識別子が 持続することも望みません。

許可結果型
[Exposed=Window]
interface BluetoothPermissionResult : PermissionStatus {
  attribute FrozenArray<BluetoothDevice> devices;
};
許可照会アルゴリズム
"bluetooth" の許可を照会するにあたり、 BluetoothPermissionDescriptor descBluetoothPermissionResult status が与えられた場合、UA は以下を実行しなければなりません(MUST):
  1. status関連付けられたグローバルオブジェクトglobal とします。

  2. status.statedescpermission state に設定します。

  3. status.state が "denied" の場合、 status.devices を空の FrozenArray に設定し、これらの手順を中止します。

  4. matchingDevices を新しい Array とします。

  5. storageBluetoothPermissionStorage) を、"bluetooth"追加の許可データ現在の設定オブジェクトに対するもの)とします。

  6. storage.allowedDevices 内の各 allowedDevice について、 次の副手順を実行します。

    1. desc.deviceId が設定されており、 allowedDevice.deviceId != desc.deviceId の場合は、 次の allowedDevice に進みます。

    2. desc.filters が設定されている場合、次の副手順を実行します。

      1. desc.filters 内の各フィルターを、 それを正規化した結果に置き換えます。 これらの正規化のいずれかがエラーを投げた場合、そのエラーを返し、これらの手順を中止します。

      2. allowedDevice.[[device]]desc.filters 内の いずれかのフィルターに一致 しない場合、次の allowedDevice に進みます。

    3. BluetoothDevice を取得して global.navigator.bluetooth 内で allowedDevice.[[device]] を表すものを得て、その結果を matchingDevices に追加します。

    注記: desc.optionalServices および desc.optionalManufacturerData フィールドは結果に影響しません。
  7. status.devices を新しい FrozenArray とし、 その内容を matchingDevices に設定します。

許可取り消しアルゴリズム
ユーザーが公開する意図のなくなったデバイスへのアクセスを 取り消すために、 UA は以下の手順を実行しなければなりません(MUST):
  1. storageBluetoothPermissionStorage) を、"bluetooth"追加の許可データ現在の設定オブジェクトに対するもの)とします。

  2. 現在の realm 内の各 BluetoothDevice インスタンス deviceObj について、次の副手順を実行します。

    1. storage.allowedDevices 内に、次を満たす AllowedBluetoothDevice allowedDevice が存在する場合:

      この場合、 deviceObj.[[allowedServices]]allowedDevice.allowedServices に更新し、次の deviceObj に進みます。

    2. それ以外の場合、残りの手順を実行して、deviceObj をそのデバイスから切り離します。

    3. deviceObj.gatt.disconnect() を呼び出します。

      注記: これは deviceObj に対して gattserverdisconnected イベントを発火します。
    4. deviceObj.[[representedDevice]]null に設定します。

4.2. Bluetooth の全体的な利用可否

UA は Bluetooth 無線を搭載していないコンピューター上で動作している場合があります。 requestDevice() はデバイスを一切発見できないことでこれを扱い、 その結果 NotFoundError になりますが、ウェブサイト側でもより丁寧に対処できる場合があります。

Bluetooth アダプターを持つユーザーにのみ Bluetooth の UI を表示するには:
const bluetoothUI = document.querySelector('#bluetoothUI');
navigator.bluetooth.getAvailability().then(isAvailable => {
  bluetoothUI.hidden = !isAvailable;
});
navigator.bluetooth.addEventListener('availabilitychanged', e => {
  bluetoothUI.hidden = !e.value;
});
getAvailability() メソッドは、 呼び出されたら 新しい promise promise を返し、 次の手順を並行して実行しなければなりません(MUST):
  1. global を、this関連付けられたグローバルオブジェクトとします。

  2. global関連する Document が、 "bluetooth" という ポリシー制御機能使用を許可されていない場合、グローバルタスクをキューして、 Bluetooth タスクソース上で globalresolve により promisefalse で解決し、 これらの手順を中止します。

  3. ユーザーが当該オリジンに対して本関数の返答を特定の値にするよう UA を構成している場合、その構成済みの値で タスクをキューして resolve により promise を解決し、 これらの手順を中止します。

    注記: ユーザーによって Web Bluetooth の許可がブロックされている場合、 UA は resolve により promisefalse で解決しても構いません。
  4. simulatedBluetoothAdapter を、 thisnavigabletop-level traversable が持つ シミュレートされた Bluetooth アダプター とします。

  5. simulatedBluetoothAdapter が空でない場合、

    1. simulatedBluetoothAdapteradapter state が "absent" であるなら、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 resolve により promisefalse で解決します。

    2. simulatedBluetoothAdapterLE supported statefalse の場合、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 resolve により promisefalse で解決します。

    3. それ以外の場合は、グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 resolve により promisetrue で解決します。

    4. これらの手順を中止します。

  6. UA が Bluetooth 無線を備えたシステム上で動作している場合、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 Bluetooth 無線の電源状態に関わらず resolve により promisetrue で解決します。

  7. それ以外の場合は、グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 resolve により promisefalse で解決します。

    注記: UA が Bluetooth の可用性を判定するために他のシステムへ問い合わせできるよう、 この promise は並行して解決されます。
ユーザーが権限をブロックしており、UA が getAvailability の promise を false で解決する場合、次の方法で Bluetooth が再び利用可能になったことを検出して Bluetooth UI を表示できます:
function checkAvailability() {
  const bluetoothUI = document.querySelector('#bluetoothUI');
  navigator.bluetooth.getAvailability().then(isAvailable => {
    bluetoothUI.hidden = !isAvailable;
  });
}

navigator.permissions.query({name: "bluetooth"}).then(status => {
  if (status.state !== 'denied') checkAvailability();

  // Bluetooth がブロックされています。PermissionStatus の変化を監視します。
  status.onchange = () => {
    if (this.state !== 'denied') checkAvailability();
  };
});
UA が Bluetooth を使用可能または不可能になる場合(例: 無線が物理的に接続・切断された、 あるいは 構成 により getAvailability() が返す答えが変更されたなど)、 UA は各 グローバルオブジェクト global に対して、 グローバルタスクをキューし、 Bluetooth タスクソース上で 次の手順を実行しなければなりません(MUST):
  1. 変更前に getAvailability() が返していた値を oldAvailability とします。

  2. 変更後に getAvailability() が返す値を newAvailability とします。

  3. oldAvailabilitynewAvailability と同一でない場合、

    1. navigator を、global関連付けられた Navigator とします。

    2. bluetooth を、navigator関連付けられた Bluetooth とします。

    3. イベントを発火させます。イベント名は availabilitychanged、 インターフェイスは ValueEvent、 対象は bluetooth で、 その value 属性を newAvailability に初期化します。

[
  Exposed=Window,
  SecureContext
]
interface ValueEvent : Event {
  constructor(DOMString type, optional ValueEventInit initDict = {});
  readonly attribute any value;
};

dictionary ValueEventInit : EventInit {
  any value = null;
};

ValueEvent インスタンスは、 DOM § 2.5 Constructing events に従って構築されます。

value 属性は、初期化時に設定された値を返さなければなりません。

このような汎用的なイベント型は、 ここではなく [HTML] または [DOM] に属するべきです。

5. デバイスの表現

UA は Bluetooth デバイスのプロパティを複数のレベル(グローバル、オリジンごと、そして グローバルオブジェクトごと)で追跡する必要があります。

5.1. グローバルな Bluetooth デバイスのプロパティ

物理的な Bluetooth デバイスには、UA が受信していない可能性のあるプロパティが保証されている場合があります。これらのプロパティはここでは任意と記述します。

Bluetooth device は次のプロパティを持ちます。任意のプロパティは存在せず、列(sequence)やマップのプロパティは、別途記述がない限り空です。その他のプロパティは既定値が指定されているか、デバイスが導入されるときに指定されます。

UA は、2 つの Bluetooth device が、同一の Bluetooth デバイス(同一デバイス)であると判断すべきです(SHOULD)。それは、それらが同じ Public Bluetooth AddressStatic AddressPrivate Address、または Identity Resolving Key を持つ場合、あるいは一方のデバイスの IRK と他方の Private Address(Resolvable)を用いて Resolvable Private Address Resolution Procedure が成功する場合に限ります。ただし、プラットフォーム API はデバイス同一性の判定方法を文書化していないため、UA は別の手順を用いてもかまいません(MAY)。

5.2. BluetoothDevice

BluetoothDevice インスタンスは、特定の Bluetooth device を、特定の グローバルオブジェクト(同等に、特定の Realm または Bluetooth インスタンス)に対して表現します。

[Exposed=Window, SecureContext]
interface BluetoothDevice : EventTarget {
  readonly attribute DOMString id;
  readonly attribute DOMString? name;
  readonly attribute BluetoothRemoteGATTServer? gatt;

  Promise<undefined> forget();
  Promise<undefined> watchAdvertisements(
      optional WatchAdvertisementsOptions options = {});
  readonly attribute boolean watchingAdvertisements;
};
BluetoothDevice includes BluetoothDeviceEventHandlers;
BluetoothDevice includes CharacteristicEventHandlers;
BluetoothDevice includes ServiceEventHandlers;

dictionary WatchAdvertisementsOptions {
  AbortSignal signal;
};
NOTE: BluetoothDevice 属性
id は、UA が 2 つの Bluetooth 接続が同一のデバイスであると判断できる範囲、かつユーザーが その事実をスクリプトに公開することを望む範囲で、デバイスを一意に識別します。

name は当該デバイスの人間可読な名称です。

gatt は、サイトにその権限がある場合、このデバイスの GATT サーバーと対話する手段を提供します。

forget() は、ユーザーが付与した当該デバイスへのアクセスを、ページが取り消すことを可能にします。

watchingAdvertisements は、UA が現在このデバイスからの広告をスキャンし、そのためのイベントを発火している場合に true です。

BluetoothDevice のインスタンスは、以下の表で説明される 内部スロットとともに作成されます。

Internal Slot Initial Value Description (non-normative)
[[context]] <always set in prose> この Bluetooth オブジェクトが返した BluetoothDevice
[[representedDevice]] <always set in prose> このオブジェクトが表す Bluetooth device。 アクセスが 取り消された場合は null
[[gatt]] 新しい BluetoothRemoteGATTServer インスタンスで、 その device 属性は this に初期化され、 connected 属性は false に初期化されます。 変更されません。
[[allowedServices]] <always set in prose> このオリジンに対する本デバイスの allowedServices リスト。すべてのサービスが許可されている場合は "all"。たとえば、UA があるオリジンで URL を広告した referringDevice 上のすべてのサービスへのアクセスをオリジンに許可することがあります。
[[allowedManufacturerData]] <always set in prose> このオリジンに対する本デバイスの allowedManufacturerData リスト。
[[watchAdvertisementsState]] 'not-watching' 現在の watchAdvertisements() 操作の状態を表す文字列列挙。取り得る列挙値は次のとおりです:
  • 'not-watching'

  • 'pending-watch'

  • 'watching'

BluetoothDevice を取得して表現する ために、Bluetooth device deviceBluetooth インスタンス context 内で表現するには、UA は次の手順を実行しなければなりません(MUST):
  1. storage を、 BluetoothPermissionStorage とし、"bluetooth"追加の許可データ現在の設定オブジェクトについてのもの)とします。

  2. storage.allowedDevices の中から、allowedDevice.[[device]]同一のデバイスである allowedDevice を見つけます。そのようなオブジェクトがなければ、 SecurityError を投げて、これらの手順を中止します。

  3. context.[[deviceInstanceMap]]device同一のデバイスであるキーが存在しない場合、次の副手順を実行します:

    1. result を、新しい BluetoothDevice のインスタンスとします。

    2. result の任意フィールドをすべて null に初期化します。

    3. result.[[context]]context に初期化します。

    4. result.[[representedDevice]]device に初期化します。

    5. result.idallowedDevice.deviceId に初期化し、 result.[[allowedServices]]allowedDevice.allowedServices に初期化します。

    6. device に部分的または完全な Bluetooth デバイス名がある場合、 result.name をその文字列に設定します。

    7. result.watchingAdvertisementsfalse に初期化します。

    8. context.[[deviceInstanceMap]] に、device から result への対応を追加します。

  4. context.[[deviceInstanceMap]] のうち、キーが 同一のデバイスである device に対応する値を返します。

gatt 属性の取得は、次の手順を実行しなければなりません(MUST):
  1. "bluetooth"追加の許可データthis関連する設定オブジェクトに対するもの)に、 次を満たす AllowedBluetoothDevice allowedDeviceallowedDevices リスト内にあり、 その allowedDevice.[[device]]同一のデバイスthis.[[representedDevice]] に対して)であり、 かつ allowedDevice.mayUseGATTtrue に等しい場合、 this.[[gatt]] を返します。

  2. それ以外の場合、null を返します。

forget() メソッドは、 呼び出されたとき、新しい promise promise を返し、次の手順を実行しなければなりません(MUST):
  1. device を対象の BluetoothDevice オブジェクトとします。

  2. storage を、現在のスクリプト実行環境における BluetoothPermissionStorage オブジェクトとします。

  3. Remove device from storagestorage に対して実行します。

  4. Resolve により promise を解決します。

ユーザーエージェントは関連付けられた watch advertisements manager を持ちます。これは 新しい並列キューの開始の結果です。

watchAdvertisements(options) メソッドは、呼び出されたとき、新しい promise promise を返し、 次の手順を実行しなければなりません(MUST):
  1. global を、this の関連付けられたグローバルオブジェクトとします。 これは this のものです。

  2. options.signal が存在する場合、次の副手順を実行します:

    1. options.signal中止されている場合、 abort watchAdvertisementsthis で実行し、これらの手順を中止します。

    2. 以下の中止手順を追加します: options.signal に対して。

      1. Abort watchAdvertisementsthis で実行します。

      2. Reject により promiseAbortError で拒否します。

  3. this.[[watchAdvertisementsState]] が次のいずれかの場合:

    'not-watching'
    1. this.[[watchAdvertisementsState]]'pending-watch' に設定します。

    2. 以下の手順をエンキューして watch advertisements manager に追加します。ただし、 this.[[watchAdvertisementsState]]not-watching になった場合は中止します:

      1. UA がこのデバイスの広告をスキャンしていることを保証します。UA は、同一デバイスの「重複した」広告をフィルタすべきではありません(SHOULD NOT)。

      2. UA がスキャンの有効化に失敗した場合、グローバルタスクをキューして Bluetooth タスクソース上で global に与え、次の手順を実行し、これらの手順を中止します:

        1. this.[[watchAdvertisementsState]]'not-watching' に設定します。

        2. Reject により promise を以下のいずれかのエラーで拒否します:

          UA が広告のスキャンをサポートしていない

          NotSupportedError

          Bluetooth がオフである

          InvalidStateError

          その他の理由

          UnknownError

      3. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、以下の手順を実行します。ただし、 次の場合中止します: this.[[watchAdvertisementsState]]not-watching になった場合。

        1. this.[[watchAdvertisementsState]]watching に設定します。

        2. this.watchingAdvertisementstrue に設定します。

        3. Resolve により promiseundefined で解決します。

    'pending-watch'
    1. Reject により promiseInvalidStateError で拒否します。

    'watching'
    1. Resolve により promiseundefined で解決します。

  4. 中止された場合は、 reject により promiseAbortError で拒否します。

Note: スキャンは電力を消費するため、ウェブサイトは不要に広告の監視を行わないようにし、可能な限り早く電力消費を停止できるよう AbortController を使用すべきです(SHOULD)。

watchAdvertisements を中止する ために、 BluetoothDevice device に対して、次の手順を実行します:
  1. this.[[watchAdvertisementsState]]'not-watching' に設定します。

  2. device.watchingAdvertisementsfalse に設定します。

  3. 以下の手順をエンキューして watch advertisements manager に追加します:

    1. UA 全体で BluetoothDevice のうち watchingAdvertisementstrue に設定されているものがなくなった場合、UA は広告のスキャンを停止すべきです(SHOULD)。それ以外の場合で、this と同一のデバイスを表す BluetoothDevice のうち watchingAdvertisementstrue に設定されているものがなくなった場合、UA はこのデバイスのレポートを受信しないようスキャンを再設定すべきです(SHOULD)。

すべてのアクティブな watchAdvertisements を中止する ために、Bluetooth bluetooth が与えられたとき、次の手順を実行します:
  1. device について、 bluetooth.[[deviceInstanceMap]] 内を走査し、次の手順を実行します:

    1. もし device.[[watchAdvertisementsState]]pending-watch または watching であれば、 abort watchAdvertisementsdevice で実行します。

5.2.1. 可視状態の変更への対応

Bluetooth デバイスのスキャンを開始する操作は、可視な document においてのみ実行できます。visibility state"visible" でなくなったとき、その document に対する スキャン操作は中止される必要があります。

本仕様は、visibilityStatedocument が与えられた場合に実行する、以下の ページ可視性変更手順を定義します:
  1. globaldocument関連付けられたグローバルオブジェクトとします。

  2. グローバルタスクをキューし、global を与えて Bluetooth タスクソース上で 次を実行します:

    1. navigatorglobal関連付けられた Navigator とします。

    2. bluetoothnavigator関連付けられた Bluetooth とします。

    3. visibilityState"visible" でない場合、 すべてのアクティブな watchAdvertisements を中止 する操作を bluetooth 上で実行します。

5.2.2. ドキュメントの完全なアクティビティ喪失への対応

Bluetooth デバイスのスキャンを開始する操作は、完全にアクティブdocument においてのみ実行できます。 完全なアクティビティを喪失した場合、その document に対するスキャン操作は中止される必要があります。

ユーザーエージェントが、Document が もはや 完全にアクティブではないと判断したとき、次の手順を実行しなければなりません(MUST):
  1. document を、もはや 完全にアクティブではない Document とします。

  2. globaldocument関連付けられたグローバルオブジェクトとします。

  3. グローバルタスクをキューし、global を与えて Bluetooth タスクソース上で 次を実行します:

    1. navigatorglobal関連付けられた Navigator とします。

    2. bluetoothnavigator関連付けられた Bluetooth とします。

    3. すべてのアクティブな watchAdvertisements を中止 する操作を bluetooth 上で実行します。

5.2.3. 広告イベントへの応答

watchingAdvertisements が設定された BluetoothDeviceadvertising event が到着したとき、 UA は "advertisementreceived" イベントを配信します。

[Exposed=Window, SecureContext]
interface BluetoothManufacturerDataMap {
  readonly maplike<unsigned short, DataView>;
};
[Exposed=Window, SecureContext]
interface BluetoothServiceDataMap {
  readonly maplike<UUID, DataView>;
};
[
  Exposed=Window
  ,
  SecureContext
]
interface BluetoothAdvertisingEvent : Event {
  constructor(DOMString type, BluetoothAdvertisingEventInit init);
  [SameObject]
  readonly attribute BluetoothDevice device;
  readonly attribute FrozenArray<UUID> uuids;
  readonly attribute DOMString? name;
  readonly attribute unsigned short? appearance;
  readonly attribute byte? txPower;
  readonly attribute byte? rssi;
  [SameObject]
  readonly attribute BluetoothManufacturerDataMap manufacturerData;
  [SameObject]
  readonly attribute BluetoothServiceDataMap serviceData;
};
dictionary BluetoothAdvertisingEventInit : EventInit {
  required BluetoothDevice device;
  sequence<(DOMString or unsigned long)> uuids;
  DOMString name;
  unsigned short appearance;
  byte txPower;
  byte rssi;
  BluetoothManufacturerDataMap manufacturerData;
  BluetoothServiceDataMap serviceData;
};
device は、この広告を送信した BluetoothDevice です。

uuids は、この広告が示す device の GATT サーバーがサポートする Service UUID を列挙します。

namedevice のローカル名、またはその接頭辞です。

appearanceAppearance であり、 gap.appearance 特性で定義される値の一つです。

txPower はデバイスが送信している 送信電力(dBm)です。これは this.txPower - this.rssi としてパスロスを計算するために使用されます。

rssi は、広告が受信されたときの 受信電力(dBm)です。これは this.txPower - this.rssi としてパスロスを計算するために使用されます。

manufacturerData は、 unsigned short の Company Identifier Code を DataView に写像します。

serviceDataUUIDDataView に写像します。

デバイスを取得してその iBeacon データを読み出すために、開発者は次のコードを使用できます。現在のところこの API は特定の manufacturer data を持つデバイスを要求する方法を提供していないため、ユーザーが requestDevice ダイアログでこのデバイスを選択できるよう、iBeacon は既知のサービスを含むように 広告をローテーションする必要があります。
var known_service = "A service in the iBeacon’s GATT server";
return navigator.bluetooth.requestDevice({
  filters: [{services: [known_service]}]
}).then(device => {
  device.watchAdvertisements();
  device.addEventListener('advertisementreceived', interpretIBeacon);
});

function interpretIBeacon(event) {
  var rssi = event.rssi;
  var appleData = event.manufacturerData.get(0x004C);
  if (appleData.byteLength != 23 ||
    appleData.getUint16(0, false) !== 0x0215) {
    console.log({isBeacon: false});
  }
  var uuidArray = new Uint8Array(appleData.buffer, 2, 16);
  var major = appleData.getUint16(18, false);
  var minor = appleData.getUint16(20, false);
  var txPowerAt1m = -appleData.getInt8(22);
  console.log({
      isBeacon: true,
      uuidArray,
      major,
      minor,
      pathLossVs1m: txPowerAt1m - rssi});
});

iBeacon 広告のフォーマットは、Adam Warski による How do iBeacons work? を基にしています。

UA が(広告パケットと任意のスキャン応答から成る)advertising event を受信したとき、次の手順を実行しなければなりません(MUST):
  1. device を、その広告イベントを送信した Bluetooth device とします。

  2. UA 内の各 BluetoothDevice deviceObj について、devicedeviceObj.[[representedDevice]]同一のデバイスである場合、 タスクをキューし、deviceObj関連する設定オブジェクト責任イベントループ上で次の副手順を実行します:

    1. deviceObj.watchingAdvertisementsfalse の場合、これらの副手順を中止します。

    2. advertisementreceived イベントを発火し、 当該広告イベントについて deviceObj 上で通知します。

広告イベント advBluetoothDevice deviceObj に対して advertisementreceived イベントを発火するには、UA は次の手順を実行しなければなりません(MUST):
  1. event を次のようにします

    {
      bubbles: true,
      device: deviceObj,
      uuids: [],
      manufacturerData: new Map(),
      serviceData: new Map()
    }
    
  2. adv 内のいずれかのパケットについて 受信信号強度が 利用可能であれば、event.rssi を dBm 単位のその値に設定します。

  3. adv の広告パケットおよびスキャン応答内の各 AD 構造について、 AD タイプに応じて次のステップを実行します:

    16 ビット Service UUID の不完全な一覧
    16 ビット Service UUID の完全な一覧
    32 ビット Service UUID の不完全な一覧
    32 ビット Service UUID の完全な一覧
    128 ビット Service UUID の不完全な一覧
    128 ビット Service UUID の完全な一覧
    列挙された各 uuid について、それが this.device.[[allowedServices]] に含まれている場合、 uuidevent.uuids に追加します。
    短縮された ローカル名
    完全な ローカル名
    AD データを BOM なしの UTF-8 デコードで復号し、 event.name に設定します。
    注記: 既存の API ではこの情報を得るために生の広告を読む必要があり、 API にフィールドを追加する前にその有用性のさらなる根拠が必要なため、 名前が完全かどうかは公開しません。
    メーカー固有データ
    各 16 ビットの Company Identifier Code manufacturerCode について、 それが this.device.[[allowedManufacturerData]] に含まれており、かつメーカー固有データが ブロックリストのメーカー固有データ でない場合、 manufacturerCode から、メーカー固有データを含む ArrayBuffer への写像を event.manufacturerData に追加します。
    TX パワーレベル
    event.txPower を AD データに設定します。
    サービスデータ - 16 ビット UUID
    サービスデータ - 32 ビット UUID
    サービスデータ - 128 ビット UUID
    サービスデータ内の各 UUID uuid について、それが this.device.[[allowedServices]] に含まれている場合、uuid から、サービスデータを含む ArrayBuffer への写像を event.serviceData に追加します。
    Appearance
    event.appearance を AD データに設定します。
    その他
    次の AD 構造へ進みます。
  4. イベントを発火します。イベント名は "advertisementreceived" で、 BluetoothAdvertisingEventevent で初期化し、 isTrusted 属性を true に初期化して、 deviceObj 上で発火します。

BluetoothAdvertisingEvent のすべてのフィールドは、最後に初期化または設定された値を返します。

BluetoothAdvertisingEvent(type, init) コンストラクターは、次の手順を実行しなければなりません(MUST):
  1. event を、DOM § 2.5 Constructing events の手順を、 uuidsmanufacturerData、 および serviceData メンバーを除いて実行した結果とします。

  2. init.uuids が設定されている場合、 event.uuids を、新しい FrozenArray に初期化し、 その内容を init.uuids.map( BluetoothUUID.getService) の要素とします。そうでなければ、 event.uuids を空の FrozenArray に初期化します。

  3. init.manufacturerData の各写像について:

    1. code を、キーを unsigned short に変換した値とします。

    2. value を、その値とします。

    3. valueBufferSource でない場合、 TypeError を投げます。

    4. bytes を、読み取り専用 ArrayBuffer の新しいインスタンスで、 保持しているバイト列のコピーとして value の内容を含むものとします。

    5. event.manufacturerData の [[BackingMap]] に、code から new DataView(bytes) への写像を追加します。

  4. init.serviceData の各写像について:

    1. key を、キーとします。

    2. service を、 BluetoothUUID.getService(key) を呼び出した結果とします。

    3. value を、その値とします。

    4. valueBufferSource でない場合、 TypeError を投げます。

    5. bytes を、読み取り専用 ArrayBuffer の新しいインスタンスで、 保持しているバイト列のコピーとして value の内容を含むものとします。

    6. event.serviceData の [[BackingMap]] に、service から new DataView(bytes) への写像を追加します。

  5. event を返します。

5.2.3.1. BluetoothManufacturerDataMap

BluetoothManufacturerDataMap のインスタンスは、 [[BackingMap]] スロットを持ちます。これは maplike であり、メーカーコードを メーカーのデータ(DataView に変換されたもの)へ写像します。

5.2.3.2. BluetoothServiceDataMap

BluetoothServiceDataMap のインスタンスは、 [[BackingMap]] スロットを持ちます。これは maplike であり、サービス UUID を サービスのデータ(DataView に変換されたもの)へ写像します。

6. GATT の相互作用

6.1. GATT 情報モデル

GATT プロファイル階層は、 GATT Server が Profiles、Primary ServiceIncluded ServiceCharacteristic、および Descriptor の 階層をどのように包含するかを記述します。

Profile は純粋に論理的な概念です。Profile の仕様は、その Profile が包含する他の GATT エンティティ間の期待される相互作用を記述しますが、 デバイスがどの Profile をサポートしているかを問い合わせることはできません。

GATT Client は、GATT 手続きの集合を用いて、 デバイス上の Service、Characteristic、Descriptor を発見し相互作用できます。本仕様では Service、Characteristic、Descriptor をまとめて Attribute と呼びます。 すべての Attribute は UUID によって識別される型を持ちます。 各 Attribute はまた、同一の GATT Server 上にある同じ型の他の Attribute と区別する 16 ビットの Attribute Handle を持ちます。 Attribute はその GATT Server 内で、その Attribute Handle によって概念的に順序付けられますが、 プラットフォームのインターフェイスは何らかの順序で属性を提供するものの、その順序が Attribute Handle の順序と一致することは保証しません。

ServiceIncluded ServiceCharacteristic の集合を含みます。 Included Service は他の Service への参照であり、1 つの Service は複数の別の Service に含まれることがあります。 GATT Server の直下に現れる Service は Primary Services と呼ばれ、 他の Service にのみ含まれている場合は Secondary Services と呼ばれますが、Primary Service が含まれることもあります。

Characteristic は バイト配列である値と、 Descriptor の集合を含みます。 Characteristic の properties に応じて、 GATT Client はその値を読み書きしたり、値が変化したときに通知を受け取るよう登録したりできます。

最後に、Descriptor は (再びバイト配列である)値を含み、それが自身の Characteristic を記述または構成します。

6.1.1. 接続間の永続性

Bluetooth の Attribute Caching システムは、 bonded なクライアントが 1 回の接続から次の接続にわたって 属性への参照を保存できるようにします。Web Bluetooth は、サイトがアクセス権を持つデバイスに対して bonded ではない と見なします。つまり、 BluetoothRemoteGATTServiceBluetoothRemoteGATTCharacteristic、 および BluetoothRemoteGATTDescriptor オブジェクトは 切断時に無効になり、サイトは再接続時に それらを再取得しなければなりません。

6.1.2. Bluetooth キャッシュ

UA は、あるデバイス上で発見した Service、Characteristic、Descriptor の階層について、 Bluetooth キャッシュを 維持しなければなりません(MUST)。UA は、同じデバイスにアクセスする複数のオリジン間でこのキャッシュを共有してもかまいません(MAY)。 キャッシュ内の各可能なエントリは、known-present(存在が既知)、known-absent(非存在が既知)、あるいは unknown(不明)のいずれかです。 キャッシュは 同一の attribute に対する 2 つのエントリを含んではなりません(MUST NOT)。キャッシュ内の各 known-present エントリは、 それぞれの Bluetooth インスタンスごとに、 任意の Promise<BluetoothRemoteGATTService>Promise<BluetoothRemoteGATTCharacteristic>、 または Promise<BluetoothRemoteGATTDescriptor> インスタンスに関連付けられます。

注記: 例えば、ユーザーが serviceA.getCharacteristic(uuid1) 関数を、初期状態で空の Bluetooth キャッシュに対して呼び出すと、 UA は返される Promise を満たすために必要なキャッシュエントリを埋めるべく Discover Characteristics by UUID 手続きを用い、 1 つの Characteristic だけが必要であるためにその手続きを早期終了します。 このとき serviceA 内の UUID uuid1 を持つ最初の Characteristic は known-present となり、 それ以降の同 UUID の Characteristic は unknown のままです。ユーザーが後で serviceA.getCharacteristics(uuid1) を呼び出した場合、UA は Discover Characteristics by UUID 手続きを再開または再実行する必要があります。 もし serviceA に UUID uuid1 を持つ Characteristic が 1 つしかなかったことが判明すれば、 それ以降の Characteristic は known-absent となります。

Bluetooth キャッシュ内の known-present エントリには順序があります。 Primary Service はデバイス内で特定の順序で現れ、Included Service と Characteristic は各 Service 内で特定の順序で、 Descriptor は各 Characteristic 内で特定の順序で現れます。順序はデバイス上の Attribute Handle の順序と一致すべきです(SHOULD)が、 デバイスの順序が利用できない場合は UA は別の順序を用いてもかまいません(MAY)。

Bluetooth キャッシュを構築して、 ある記述に一致するエントリを追加するために、UA は以下の手順を実行しなければなりません(MUST)。
注記: これらの手順はブロックし得るため、このアルゴリズムの利用箇所は 並行して 実行される必要があります。
  1. 一致するキャッシュ内のすべてのエントリを known-present か known-absent のいずれかにしようと試みます。 その際、[BLUETOOTH42] が 十分な情報が返ると規定している任意の GATT 手続きの並びを使用します。 エラー処理は § 6.7 エラー処理 に記述されているとおりに行います。

  2. 前の手順がエラーを返した場合、このアルゴリズムからそのエラーを返します。

BluetoothDevice インスタンス deviceObj において、ある記述に一致するエントリを Bluetooth キャッシュに問い合わせる には、UA は deviceObj.gatt接続チェックラッパー新しい promise promise を包んで返し、 次の手順を並行して実行します。
  1. globaldeviceObj関連付けられたグローバルオブジェクトとします。

  2. 記述に一致するエントリで Bluetooth キャッシュを構築します。

  3. 前の手順がエラーを返した場合、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、reject により そのエラーで promise を拒否し、これらの手順を中止します。

  4. 記述に一致する known-present のキャッシュエントリの列を entries とします。

  5. contextdeviceObj.[[context]] とします。

  6. result を新しい列とします。

  7. entries の各 entry について:

    1. もし context.[[attributeInstanceMap]]Promise<BluetoothGATT*> インスタンスが関連付けられていなければ、 entry が Service の場合は BluetoothRemoteGATTService を表すオブジェクトを作成し、 Characteristic の場合は BluetoothRemoteGATTCharacteristic を表すオブジェクトを作成し、 Descriptor の場合は BluetoothRemoteGATTDescriptor を表すオブジェクトを作成し、 context.[[attributeInstanceMap]]entry から得られた Promise への対応を追加します。

    2. context.[[attributeInstanceMap]] において entry に関連付けられている Promise<BluetoothGATT*> インスタンスを result に追加します。

  8. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、resolve により 全要素の完了待ちの結果で promise を解決します。

Represented(obj: Device or GATT Attribute) は、 obj の型に応じて次を返します:
BluetoothDevice
obj.[[representedDevice]]
BluetoothRemoteGATTService
obj.[[representedService]]
BluetoothRemoteGATTCharacteristic
obj.[[representedCharacteristic]]
BluetoothRemoteGATTDescriptor
obj.[[representedDescriptor]]
GetGATTChildren( attribute: GATT Attribute,
single: boolean,
uuidCanonicalizer: function,
uuid: optional (DOMString or unsigned int),
allowedUuids: optional ("all" or Array<DOMString>),
child type: GATT declaration type),

を実行するために、UA は以下の手順を実行しなければなりません(MUST):
  1. uuid が存在する場合、uuiduuidCanonicalizer(uuid) に設定します。 uuidCanonicalizer が例外を投げた場合は、その例外で 拒否された promise を返し、 これらの手順を中止します。

  2. uuid が存在し、かつ blocklisted である場合、 SecurityError拒否された promise を返し、 これらの手順を中止します。

  3. attribute の型に応じて、deviceObj を次のように定めます:

    BluetoothDevice
    attribute
    BluetoothRemoteGATTService
    attribute.device
    BluetoothRemoteGATTCharacteristic
    attribute.service.device
  4. もし deviceObj.gatt.connectedfalse であれば、 NetworkError拒否された promise を返し、 これらの手順を中止します。

  5. もし Represented(attribute) が null であれば、 InvalidStateError拒否された promise を返し、 これらの手順を中止します。

    注記: これは、Service または Characteristic がデバイスから削除されたり、 切断によって無効化された後に、そのオブジェクトが再度使用されたときに発生します。

  6. deviceObjBluetooth キャッシュへの問い合わせを実行し、 次の条件を満たすエントリを取得します:

    • Represented(attribute) の内部にあること

    • child type で記述される型を持つこと

    • UUID が blocklisted でないこと

    • uuid が存在する場合、その UUID が uuid であること

    • allowedUuids が存在し、かつ "all" でない場合、 その UUID が allowedUuids に含まれること

    • single フラグが設定されている場合、これらのうち最初のものであること

    結果を promise とします。

  7. fulfillment により promiseresult で満たされたとき、次を実行します:

    • result が空であれば、 NotFoundError を投げます。

    • それ以外で single フラグが設定されている場合、result の最初(かつ唯一)の要素を返します。

    • それ以外の場合、result を返します。

6.1.4. Service、Characteristic、Descriptor の識別

2 つの Service、Characteristic、または Descriptor、ab同一の attribute であるかどうかを確認する際、 UA は、ab同一のデバイス 内にあり、 かつ同じ Attribute Handle を持つ場合に 同一であると判断すべきです(SHOULD)。ただし、以下の条件のいずれかに該当する場合には、 ab同一の attribute と 見なしてはなりません(MUST NOT)。UA はこの制約の範囲で任意のアルゴリズムを用いてもかまいません(MAY)。

注記: この定義が緩いのは、プラットフォーム API が Attribute Handle の等価性に基づくかどうかを文書化しないまま、 それぞれ独自の同一性の概念を露出しているためです。
注記: 2 つの JavaScript オブジェクト xy が Service、Characteristic、または Descriptor を表している場合、 x === y は、それらのオブジェクトが Bluetooth キャッシュへの問い合わせアルゴリズムが 新しいオブジェクトを作成・キャッシュする方法により、同一の attribute を表すかどうかを返します。

6.2. BluetoothRemoteGATTServer

BluetoothRemoteGATTServer は、 リモートデバイス上の GATT Server を表します。

[Exposed=Window, SecureContext]
interface BluetoothRemoteGATTServer {
  [SameObject]
  readonly attribute BluetoothDevice device;
  readonly attribute boolean connected;
  Promise<BluetoothRemoteGATTServer> connect();
  undefined disconnect();
  Promise<BluetoothRemoteGATTService> getPrimaryService(BluetoothServiceUUID service);
  Promise<sequence<BluetoothRemoteGATTService>>
    getPrimaryServices(optional BluetoothServiceUUID service);
};
注記: BluetoothRemoteGATTServer の属性
device は、このサーバーを実行しているデバイスです。

connected は、 このインスタンスが this.device に接続されている間は true です。 物理的には UA が接続されていても、例えば他の グローバルオブジェクト向けの 他の BluetoothRemoteGATTServer インスタンスが接続されている場合などには false になり得ます。

もはやいかなる ECMAScript コードからも BluetoothRemoteGATTServer インスタンス server が観測されなくなった場合、UA は server.disconnect() を 実行すべきです(SHOULD)。

注記: navigator.bluetooth.[[deviceInstanceMap]]BluetoothDevice インスタンスが保存されるため、 少なくともナビゲーションによってグローバルオブジェクトが解放されるか、タブやウィンドウを閉じて 閲覧コンテキストが破棄されるまでは、 これは起こりません。
注記: ガベージコレクション時に切断することで、UA がリモートデバイス上のリソースを不要に消費し続けないことを保証します。

BluetoothRemoteGATTServer のインスタンスは、 以下の表で説明する 内部スロットとともに作成されます:

Internal Slot Initial Value Description (non-normative)
[[activeAlgorithms]] new Set() このサーバーの接続を使用している各アルゴリズムに対応する Promise を含みます。 disconnect() は このセットを空にし、アルゴリズムが実行中に自身の realm が一度でも切断されたかどうかを判定できるようにします。
[[automatedGATTConnectionResponse]] "not-expected" GATT 接続試行に対するシミュレートされた GATT 接続応答コード。
connect() メソッドは、呼び出されたとき、以下の手順を実行しなければなりません(MUST):
  1. globalthis関連付けられたグローバルオブジェクトとします。

  2. もし this.device.[[representedDevice]]null であれば、 "NetworkError" の DOMException拒否された promise を返します。

  3. UA が現在 Bluetooth システムを使用中である場合、UA は "NetworkError" の DOMException拒否された promise を返してもよいです(MAY)。

    実装によってはこの NetworkError を回避できるかもしれませんが、 現時点ではサイトはこの API の使用を直列化する必要があり、 かつ/または失敗した操作を再試行できる手段をユーザーに提供する必要があります。 [Issue #188]

  4. promise新しい promise とします。

  5. もし this.connectedtrue であれば、resolve により promisethis で解決し、promise を返します。

  6. this.[[activeAlgorithms]]promise を追加します。

  7. 次の手順を並行して実行します:

    1. もし globalnavigabletop-level traversablesimulated Bluetooth adapter が空でないなら、次を実行します:

      1. gatt connection attempted イベントをトリガーし、 globalnavigablethis.device を与えます。

      2. もし this.[[automatedGATTConnectionResponse]]"not-expected" であるなら、これを "expected" に設定します。

      3. もし this.[[automatedGATTConnectionResponse]]"expected" であるなら、これが変化するまで待ちます。

      4. response を、this.[[automatedGATTConnectionResponse]] とします。

      5. this.[[automatedGATTConnectionResponse]]"not-expected" に設定します。

      6. もし response0 でなければ、次の副手順を実行します:

        1. this.[[activeAlgorithms]] から promise を削除します。

        2. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 "NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

    2. それ以外の場合、次の手順を実行します:

      1. もし this.device.[[representedDevice]]ATT Bearer を持たない場合、次の副手順を実行します:

        1. ATT Bearer を作成しようと試みます。 その際、GAP Interoperability Requirements の "Connection Establishment" に記述された手順を用います。 this.[[activeAlgorithms]] から promise が削除された場合は、この試行を中断します。

          注記: 接続可能な広告が受信されない限り、これらの手順は永遠に待機する可能性があります。 ウェブサイトは、もはや接続を望まない場合には disconnect() を呼び出すべきです。
        2. この試行が、promisethis.[[activeAlgorithms]] から 削除されたために中断されたのであれば、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 "AbortError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

        3. この試行が別の理由で失敗した場合は、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 "NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

        4. Exchange MTU 手続きを用いて、 サポートされる最大の MTU をネゴシエートします。この手順でのエラーは無視します。

        5. UA は、BR/EDR Bonding Procedure または LE Bonding Procedure を用いて、 リモートデバイスとのボンディングを試みてもよいです(MAY)。

          注記: 通常であれば、ボンディングの有無やタイミングの制御はウェブサイト側に任せたいところですが、 Core Bluetooth の プラットフォーム API は UA がそのような制御を実装する手段を提供していません。 ボンディングがある方がない場合よりも安全であるため、この仕様では、そのようなことが可能なプラットフォームにおいて UA が機会を見てボンディングを作成することを許容します。 これは、接続が作成された時点でユーザーが目にするペアリングダイアログが表示される可能性があり、 制限付きの characteristic にアクセスしたときではない場合があることを意味します。

    3. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、次の副手順を実行します:

      1. もし promisethis.[[activeAlgorithms]] に存在しないなら、 "AbortError" の DOMExceptionreject により promise を拒否し、 接続のガベージコレクションthis.device.[[representedDevice]] に対して実行し、 これらの手順を中止します。

      2. this.[[activeAlgorithms]] から promise を削除します。

      3. もし this.device.[[representedDevice]]null であれば、 "NetworkError" の DOMExceptionreject により promise を拒否し、 接続のガベージコレクションthis.device.[[representedDevice]] に対して実行し、 これらの手順を中止します。

      4. this.connectedtrue に設定します。

      5. Resolve により promisethis で解決します。

  8. promise を返します。

disconnect() メソッドは、呼び出されたとき、以下の手順を実行しなければなりません(MUST):
  1. this.[[activeAlgorithms]] をクリアして、 すべての アクティブな connect() 呼び出し を中断します。

  2. もし this.connectedfalse であれば、これらの手順を中止します。

  3. 切断されたデバイスのクリーンアップthis.device に対して実行します。

  4. devicethis.device.[[representedDevice]] とします。

  5. 接続のガベージコレクションdevice に対して実行します。

device接続のガベージコレクションを行うには、 UA は以下の手順を並行して実行しなければなりません(MUST):
  1. この API を使用していないシステム(UA の内外を問わず)が deviceATT Bearer を使用している場合、 このアルゴリズムを中止します。

  2. UA 全体のすべての BluetoothDevice deviceObj について:

    1. もし deviceObj.[[representedDevice]]device同一のデバイス でなければ、 次の deviceObj に進みます。

    2. もし deviceObj.gatt.connectedtrue であれば、このアルゴリズムを中止します。

    3. もし deviceObj.gatt.[[activeAlgorithms]]Promiseconnect() 呼び出しのもの)が含まれている場合、 このアルゴリズムを中止します。

  3. deviceATT Bearer を破棄します。

注記: アルゴリズムは、実行中にその BluetoothRemoteGATTServer が切断された場合、 たとえ UA が全期間を通じて物理的に接続を維持し、その後に BluetoothRemoteGATTServer が再接続されたとしても、 失敗しなければなりません。これを実現するために、返される Promise をラップします。

promise を包む、gattServer に対する 接続チェックラッパーを作成するには、 UA は次を行わなければなりません(MUST):

  1. もし gattServer.connectedtrue であれば、 promisegattServer.[[activeAlgorithms]] に追加します。

  2. promise の完了に反応します:

    • promise が値 result で fulfill された場合:

      1. もし promisegattServer.[[activeAlgorithms]] に存在するなら、 これを削除して result を返します。

      2. それ以外の場合、NetworkError を投げます。

        注記: このエラーは、gattServer がメインのアルゴリズムの実行中に切断されたために投げられます。
    • promise が理由 error で reject された場合:

      1. もし promisegattServer.[[activeAlgorithms]] に存在するなら、 これを削除して error を投げます。

      2. それ以外の場合、NetworkError を投げます。

        注記: このエラーは、gattServer がメインのアルゴリズムの実行中に切断されたために投げられます。
getPrimaryService(service) メソッドは、呼び出されたとき、以下の手順を実行しなければなりません(MUST):
  1. もし this.device.[[allowedServices]]"all" ではなく、かつ servicethis.device.[[allowedServices]] に含まれていない場合、 SecurityError拒否された promise を返し、 これらの手順を中止します。

  2. GetGATTChildren(attribute=this.device,
    single=true,
    uuidCanonicalizer=BluetoothUUID.getService,
    uuid=service,
    allowedUuids=this.device.[[allowedServices]],
    child type="GATT Primary Service")
    を返します。

getPrimaryServices(service) メソッドは、呼び出されたとき、以下の手順を実行しなければなりません(MUST):
  1. もし this.device.[[allowedServices]]"all" ではなく、service が存在し、かつ this.device.[[allowedServices]] に含まれていない場合、 SecurityError拒否された promise を返し、 これらの手順を中止します。

  2. GetGATTChildren(attribute=this.device,
    single=false,
    uuidCanonicalizer=BluetoothUUID.getService,
    uuid=service,
    allowedUuids=this.device.[[allowedServices]],
    child type="GATT Primary Service")
    を返します。

6.3. BluetoothRemoteGATTService

BluetoothRemoteGATTService は GATT の Service(特性および他サービスとの関係の集合で、デバイスの一部の動作をカプセル化するもの)を表します。

[Exposed=Window, SecureContext]
interface BluetoothRemoteGATTService : EventTarget {
  [SameObject]
  readonly attribute BluetoothDevice device;
  readonly attribute UUID uuid;
  readonly attribute boolean isPrimary;
  Promise<BluetoothRemoteGATTCharacteristic>
    getCharacteristic(BluetoothCharacteristicUUID characteristic);
  Promise<sequence<BluetoothRemoteGATTCharacteristic>>
    getCharacteristics(optional BluetoothCharacteristicUUID characteristic);
  Promise<BluetoothRemoteGATTService>
    getIncludedService(BluetoothServiceUUID service);
  Promise<sequence<BluetoothRemoteGATTService>>
    getIncludedServices(optional BluetoothServiceUUID service);
};
BluetoothRemoteGATTService includes CharacteristicEventHandlers;
BluetoothRemoteGATTService includes ServiceEventHandlers;
device は、この GATT サービスが属するリモート周辺機器を表す BluetoothDevice です。

uuid はサービスの UUID です。例: '0000180d-0000-1000-8000-00805f9b34fb'Heart Rate サービス。

isPrimary は、このサービスの種別が primary か secondary かを示します。

BluetoothRemoteGATTService のインスタンスは、以下の表で説明される 内部スロットを持って作成されます:

Internal Slot Initial Value Description (non-normative)
[[representedService]] <always set in prose> このオブジェクトが表す Service。 そのサービスが削除されるなどして無効になっている場合は null
BluetoothRemoteGATTService を作成して表現する ために、Service service に対して UA は次の手順を実行しなければなりません(MUST):
  1. global を、this関連付けられたグローバルオブジェクトとします。

  2. promise を、新しい promise とします。

  3. 次の手順を並行して実行します:

    1. result を、新しい BluetoothRemoteGATTService のインスタンスとし、その [[representedService]] スロットを service に初期化します。

    2. BluetoothDevice を取得して表現する を実行して、 service が存在するデバイスを取得し、結果を device とします。

    3. 前の手順でエラーが投げられた場合、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、そのエラーで reject により promise を拒否し、これらの手順を中止します。

    4. resultdevicedevice から初期化します。

    5. resultuuidservice の UUID から初期化します。

    6. service が Primary Service であれば、 resultisPrimarytrue に、そうでなければ false に初期化します。

    7. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 resolve により promiseresult で解決します。

  4. promise を返します。

getCharacteristic(characteristic) メソッドは、この Service 内の Characteristic を取得します。呼び出されたとき、次を返さなければなりません(MUST)

GetGATTChildren(attribute=this,
single=true,
uuidCanonicalizer=BluetoothUUID.getCharacteristic,
uuid=characteristic,
allowedUuids=undefined,
child type="GATT Characteristic")

getCharacteristics(characteristic) メソッドは、この Service 内の Characteristic の一覧を取得します。呼び出されたとき、次を返さなければなりません(MUST)

GetGATTChildren(attribute=this,
single=false,
uuidCanonicalizer=BluetoothUUID.getCharacteristic,
uuid=characteristic,
allowedUuids=undefined,
child type="GATT Characteristic")

getIncludedService(service) メソッドは、この Service 内の Included Service を取得します。呼び出されたとき、次を返さなければなりません(MUST)

GetGATTChildren(attribute=this,
single=true,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
allowedUuids=undefined,
child type="GATT Included Service")

getIncludedServices(service) メソッドは、この Service 内の Included Service の一覧を取得します。呼び出されたとき、次を返さなければなりません(MUST)

GetGATTChildren(attribute=this,
single=false,
uuidCanonicalizer=BluetoothUUID.getService,
uuid=service,
allowedUuids=undefined,
child type="GATT Included Service")

6.4. BluetoothRemoteGATTCharacteristic

BluetoothRemoteGATTCharacteristic は GATT の Characteristic を表し、周辺機器のサービスに関する追加情報を提供する基本的なデータ要素です。

[Exposed=Window, SecureContext]
interface BluetoothRemoteGATTCharacteristic : EventTarget {
  [SameObject]
  readonly attribute BluetoothRemoteGATTService service;
  readonly attribute UUID uuid;
  readonly attribute BluetoothCharacteristicProperties properties;
  readonly attribute DataView? value;
  Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUID descriptor);
  Promise<sequence<BluetoothRemoteGATTDescriptor>>
    getDescriptors(optional BluetoothDescriptorUUID descriptor);
  Promise<DataView> readValue();
  Promise<undefined> writeValue(BufferSource value);
  Promise<undefined> writeValueWithResponse(BufferSource value);
  Promise<undefined> writeValueWithoutResponse(BufferSource value);
  Promise<BluetoothRemoteGATTCharacteristic> startNotifications();
  Promise<BluetoothRemoteGATTCharacteristic> stopNotifications();
};
BluetoothRemoteGATTCharacteristic includes CharacteristicEventHandlers;
service は、この characteristic が属する GATT サービスです。

uuid は characteristic の UUID です。例: '00002a37-0000-1000-8000-00805f9b34fb' Heart Rate Measurement characteristic。

properties は、この characteristic のプロパティを保持します。

value は現在キャッシュされている characteristic の値です。 この値は、読み出しや通知・インジケーションによる更新の際に更新されます。

BluetoothRemoteGATTCharacteristic のインスタンスは、以下の表で説明される 内部スロットを持って作成されます。

Internal Slot Initial Value Description (non-normative)
[[representedCharacteristic]] <always set in prose> このオブジェクトが表す Characteristic。characteristic が削除されるなどして無効になっている場合は null
[[automatedCharacteristicReadResponse]] "not-expected" GATT characteristic の読み取り試行に対するシミュレートされた応答コード。
[[automatedCharacteristicReadResponseData]] 空の byte sequence GATT characteristic の読み取り試行に対するシミュレートされた応答データ。
[[automatedCharacteristicWriteResponse]] "not-expected" GATT characteristic の書き込み試行に対するシミュレートされた応答コード。
[[automatedCharacteristicSubscribeToNotificationsResponse]] "not-expected" GATT characteristic 通知の購読試行に対するシミュレートされた応答コード。
[[automatedCharacteristicUnsubscribeFromNotificationsResponse]] "not-expected" GATT characteristic 通知の購読解除試行に対するシミュレートされた応答コード。
BluetoothRemoteGATTCharacteristic を作成して表現する ために、Characteristic characteristic に対して UA は次の手順を実行しなければなりません(MUST):
  1. global を、this関連付けられたグローバルオブジェクトとします。

  2. promise を、新しい promise とします。

  3. 次の手順を並行して実行します:

    1. result を、新しい BluetoothRemoteGATTCharacteristic のインスタンスとし、 [[representedCharacteristic]] スロットを characteristic に初期化します。

    2. resultservice< を、 BluetoothRemoteGATTService のうち characteristic が属する Service を表すインスタンスから初期化します。

    3. resultuuidcharacteristic の UUID から初期化します。

    4. Characteristic から BluetoothCharacteristicProperties のインスタンスを作成し、 結果を properties とします。

    5. 前の手順がエラーを返した場合、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、そのエラーで reject により promise を拒否し、これらの手順を中止します。

    6. resultpropertiesproperties に初期化します。

    7. resultvaluenull に初期化します。UA は、可能であれば characteristic から直近に読み出した値を含む new DataViewnew ArrayBuffer をラップして result.value を初期化してもよいです(MAY)。

    8. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 resolve により promiseresult で解決します。

  4. promise を返します。

getDescriptor(descriptor) メソッドは、この Characteristic 内の Descriptor を取得します。呼び出されたとき、次を返さなければなりません(MUST)

GetGATTChildren(attribute=this,
single=true,
uuidCanonicalizer=BluetoothUUID.getDescriptor,
uuid=descriptor,
allowedUuids=undefined,
child type="GATT Descriptor")

getDescriptors(descriptor) メソッドは、この Characteristic 内の Descriptor の一覧を取得します。呼び出されたとき、次を返さなければなりません(MUST)

GetGATTChildren(attribute=this,
single=false,
uuidCanonicalizer=BluetoothUUID.getDescriptor,
uuid=descriptor,
allowedUuids=undefined,
child type="GATT Descriptor")

readValue() メソッドは、呼び出されたとき、次の手順を実行しなければなりません(MUST):
  1. global を、this関連付けられたグローバルオブジェクトとします。

  2. gatt を、 this.service.device.gatt とします。

  3. もし this.uuid読み取りに対してブロックリスト入りしている場合、 "SecurityError" の 拒否された promiseDOMException)を返し、これらの手順を中止します。

  4. もし gatt.connectedfalse であれば、 "NetworkError" の 拒否された promiseDOMException)を返し、これらの手順を中止します。

  5. characteristic を、 this.[[representedCharacteristic]] とします。

  6. もし characteristicnull であれば、 "InvalidStateError" の 拒否された promiseDOMException)を返し、これらの手順を中止します。

  7. gatt に対する 接続チェックラッパー新しい promise promise を包んで返し、次の手順を並行して実行します:

    1. もし characteristicpropertiesRead ビットが設定されていなければ、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 "NotSupportedError" の reject により promise を拒否して、これらの手順を中止します。

    2. もし globalnavigabletop-level traversablesimulated Bluetooth adapter が空でない場合、次を実行します:

      1. もし this.[[automatedCharacteristicReadResponse]]"not-expected" でないなら、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 "InvalidStateError" の reject により promise を拒否して、これらの手順を中止します。

      2. simulated characteristic イベントをトリガーし、 globalnavigablethis.devicecharacteristic、および read を与えます。

      3. this.[[automatedCharacteristicReadResponse]]"expected" に設定し、変化するまで待ちます。

      4. response を、 this.[[automatedCharacteristicReadResponse]] とします。

      5. this.[[automatedCharacteristicReadResponse]]"not-expected" に設定します。

      6. もし response0 でなければ、次の副手順を実行します:

        1. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 "NetworkError" の reject により promise を拒否して、これらの手順を中止します。

      7. それ以外の場合、buffer を、 newArrayBuffer とし、 this.[[automatedCharacteristicReadResponseData]] を含むものとします。

    3. それ以外の場合、次の手順を実行します:

      1. UA が現在 Bluetooth システムを使用中であれば、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、 "NetworkError" の reject により promise を拒否して、これらの手順を中止してもよいです(MAY)。

        実装によってはこの NetworkError を回避できるかもしれませんが、現状ではサイトはこの API の使用を直列化し、かつ失敗した操作を再試行できる手段をユーザーに提供する必要があります。[Issue #188]

      2. Characteristic Value Read 手続きの副手続きの任意の組み合わせを用いて characteristic の値を取得し、取得した値を保持する newArrayBufferbuffer とします。エラー処理は § 6.7 Error handling に従います。

    4. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、次を実行します:

      1. もし promisegatt.[[activeAlgorithms]] に存在しなければ、 "NetworkError" の reject により promise を拒否し、これらの手順を中止します。

      2. 上記の副手続きがエラーを返していれば、そのエラーで reject により promise を拒否し、これらの手順を中止します。

      3. buffer で作成した newDataViewthis.value に代入します。

      4. イベントを発火します。イベント名は "characteristicvaluechanged" で、 その bubbles 属性を true に初期化して this に対して発火します。

      5. Resolve により promisethis.value で解決します。

WriteCharacteristicValue( this: BluetoothRemoteGATTCharacteristic,
value: BufferSource,
response: string),

を実行するために、UA は次の手順を実行しなければなりません(MUST):
  1. globalthis関連付けられたグローバルオブジェクトとします。

  2. gattthis.service.device.gatt とします。

  3. もし this.uuid書き込みに対してブロックリスト入りしている場合は、"SecurityError" の DOMException拒否された promise を返し、これらの手順を中止します。

  4. bytes を、value が保持するバイト列のコピーとします。

  5. もし bytes が 512 バイトを超える場合(Long Attribute Values による属性値の最大長)、 "InvalidModificationError" の DOMException拒否された promise を返し、これらの手順を中止します。

  6. もし gatt.connectedfalse であれば、"NetworkError" の DOMException拒否された promise を返し、これらの手順を中止します。

  7. characteristicthis.[[representedCharacteristic]] とします。

  8. もし characteristicnull であれば、 "InvalidStateError" の DOMException拒否された promise を返し、これらの手順を中止します。

  9. gatt に対する 接続チェックラッパー新しい promisepromise を包んで返し、次の手順を並行して実行します。

    1. 表明: response は "required"、"never"、"optional" のいずれかです。

    2. もし globalnavigabletop-level traversablesimulated Bluetooth adapter が空でない場合、次の手順を実行します:

      1. this.[[automatedCharacteristicWriteResponse]]"not-expected" でない場合は、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"InvalidStateError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      2. simulated characteristic イベントをトリガーし、 globalnavigablethis.devicecharacteristicwrite、および bytes を与えます。

      3. this.[[automatedCharacteristicWriteResponse]]"expected" に設定し、変化するまで待ちます。

      4. responsethis.[[automatedCharacteristicWriteResponse]] とします。

      5. this.[[automatedCharacteristicWriteResponse]]"not-expected" に設定します。

      6. もし response0 でなければ、次の副手順を実行します:

        1. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

    3. それ以外の場合、次の手順を実行します:

      1. UA が現在 Bluetooth システムを使用中である場合、グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"NetworkError" の DOMExceptionreject により promise を拒否してもよく(MAY)、これらの手順を中止します。

        実装によってはこの NetworkError を回避できるかもしれませんが、現状ではサイトはこの API の使用を直列化し、かつ/またはユーザーに失敗した操作を再試行できる手段を提供する必要があります。[Issue #188]

      2. characteristicbytes を書き込むため、次の手順を実行します:

        もし response が "required" の場合
        Write Characteristic Value 手続きを用います。
        もし response が "never" の場合
        Write Without Response 手続きを用います。
        それ以外の場合
        Characteristic Value Write 手続きの副手続きの任意の組み合わせを用います。
        エラー処理は § 6.7 Error handling に記載されているとおりに行います。
    4. グローバルタスクをキューして global 上で Bluetooth タスクソースを用い、次の手順を実行します:

      1. もし promisegatt.[[activeAlgorithms]] に存在しなければ、"NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      2. 上記の手続きがエラーを返した場合は、そのエラーで reject により promise を拒否し、これらの手順を中止します。

      3. this.value を、 newDataViewnewArrayBufferbytes を格納したものをラップ)に設定します。

      4. Resolve により promiseundefined で解決します。

非推奨。 代わりに writeValueWithResponse()writeValueWithoutResponse() を使用してください。

writeValue(value) メソッドは、呼び出されたとき、次を返さなければなりません(MUST)

WriteCharacteristicValue( this=this,
value=value,
response="optional")

このメソッドは後方互換性のためだけのものです。新しい実装ではこのメソッドを実装すべきではありません。[Issue #238]

writeValueWithResponse(value) メソッドは、呼び出されたとき、次を返さなければなりません(MUST)

WriteCharacteristicValue( this=this,
value=value,
response="required")

writeValueWithoutResponse(value) メソッドは、呼び出されたとき、次を返さなければなりません(MUST)

WriteCharacteristicValue( this=this,
value=value,
response="never")

UA は、既知の各 GATT Characteristic から、特性の active notification context set と呼ばれる Bluetooth オブジェクトの集合へのマップを維持しなければなりません(MUST)。

注記: ある特性に対する集合には、通知を登録した各 Realmnavigator.bluetooth オブジェクトが保持されます。デバイスが切断されると、すべての通知は非アクティブになります。再接続後も通知を受け取り続けたいサイトは startNotifications() を再度呼び出す必要があり、startNotifications() が有効になる前の隙間でいくつかの通知が取りこぼされるリスクは避けられません。
startNotifications() メソッドは、呼び出されたとき、次の手順を実行しなければなりません(MUST)。通知の受信の詳細は § 6.6.4 Responding to Notifications and Indications を参照してください。
  1. globalthis関連付けられたグローバルオブジェクトとします。

  2. gattthis.service.device.gatt とします。

  3. もし this.uuid読み取りに対してブロックリスト入りしている場合は、"SecurityError" の DOMException拒否された promise を返します。

  4. もし gatt.connectedfalse であれば、"NetworkError" の DOMException拒否された promise を返します。

  5. characteristic を、this.[[representedCharacteristic]] とします。

  6. もし characteristicnull であれば、"InvalidStateError" の DOMException拒否された promise を返します。

  7. gatt に対する 接続チェックラッパー新しい promisepromise を包んで返し、次の手順を並行して実行します。

    1. もし characteristicpropertiesNotifyIndicate のいずれのビットも設定されていない場合は、 グローバルタスクをキューして Bluetooth タスクソース 上で global に与え、NotSupportedErrorreject により promise を拒否して、これらの手順を中止します。

    2. もし characteristicactive notification context setnavigator.bluetooth が含まれている場合は、 グローバルタスクをキューして Bluetooth タスクソース 上で global に与え、resolve により promisethis で解決し、これらの手順を中止します。

    3. もし globalnavigabletop-level traversablesimulated Bluetooth adapter が空でない場合、次の手順を実行します:

      1. this.[[automatedCharacteristicSubscribeToNotificationsResponse]]"not-expected" でない場合は、 グローバルタスクをキューして Bluetooth タスクソース 上で global に与え、"InvalidStateError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      2. simulated characteristic イベントをトリガーし、 globalnavigablethis.devicecharacteristic、および subscribe-to-notifications を与えます。

      3. this.[[automatedCharacteristicSubscribeToNotificationsResponse]]"expected" に設定し、変化するまで待ちます。

      4. responsethis.[[automatedCharacteristicSubscribeToNotificationsResponse]] とします。

      5. this.[[automatedCharacteristicSubscribeToNotificationsResponse]]"not-expected" に設定します。

      6. もし response0 でなければ、次の副手順を実行します:

        1. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      7. それ以外の場合、successtrue とします。

    4. それ以外の場合、次の手順を実行します:

      1. UA が現在 Bluetooth システムを使用中である場合、グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"NetworkError" の DOMExceptionreject により promise を拒否してもよく(MAY)、これらの手順を中止します。

        実装によってはこの NetworkError を回避できるかもしれませんが、 現状ではサイトはこの API の使用を直列化し、かつ/またはユーザーに失敗した操作を再試行する手段を提供する必要があります。[Issue #188]

      2. 特性に Client Characteristic Configuration デスクリプタがある場合、Characteristic Descriptors 手続きのいずれかを用いて、characteristicClient Characteristic Configuration デスクリプタ内の Notification または Indication のどちらか一方のビットが、characteristicproperties の制約に合うように設定されていることを確実にします。UA は両方のビットを設定することは避けるべき(SHOULD)であり、両方のビットが設定されている場合は value-change events を重複排除しなければなりません(MUST)。エラー処理は § 6.7 Error handling に従います。

        注記: 一部のデバイスには、プロパティに Notify または Indicate ビットが含まれているにもかかわらず、Client Characteristic Configuration デスクリプタを持たない characteristic があります。これらの仕様非準拠の characteristic は無条件に通知またはインジケーションを送信する傾向があるため、本仕様ではアプリケーションが単にそれらのメッセージを購読できるようにしています。
      3. 手続きが成功した場合、successtrue とします。

    5. もし successtrue であれば、characteristicactive notification context setnavigator.bluetooth を追加します。

    6. グローバルタスクをキューして Bluetooth タスクソース 上で global に与え、次の手順を実行します:

      1. もし promisegatt.[[activeAlgorithms]] に存在しなければ、"NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      2. 上記の手続きがエラーを返した場合、そのエラーで reject により promise を拒否し、これらの手順を中止します。

      3. Resolve により promisethis で解決します。

注記: 通知が有効化された後、結果として生じる value-change events は、現在の マイクロタスク・チェックポイントが終わるまで配信されません。これにより、開発者は結果の promise の .then ハンドラ内でハンドラを設定できます。
stopNotifications() メソッドは、呼び出されたとき、新しい promise promise を返し、次の手順を並行して実行しなければなりません(MUST):
  1. characteristicthis.[[representedCharacteristic]] とします。

  2. もし characteristicnull であれば、拒否された promiseInvalidStateError)を返し、これらの手順を中止します。

  3. もし characteristicactive notification context setnavigator.bluetooth が含まれていれば、これを削除します。

    1. もし globalnavigabletop-level traversablesimulated Bluetooth adapter が空でない場合、次の手順を実行します:

      1. this.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]"not-expected" でない場合は、 グローバルタスクをキューして Bluetooth タスクソース 上で global に与え、"InvalidStateError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      2. simulated characteristic イベントをトリガーし、 globalnavigablethis.devicecharacteristic、および unsubscribe-from-notifications を与えます。

      3. this.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]"expected" に設定し、変化するまで待ちます。

      4. responsethis.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]] とします。

      5. this.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]"not-expected" に設定します。

      6. もし response0 でなければ、次の副手順を実行します:

        1. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

    2. それ以外の場合、次の手順を実行します:

      1. もし characteristicactive notification context set が空になり、かつその characteristic が Client Characteristic Configuration デスクリプタを持つ場合、UA は Characteristic Descriptors 手続きのいずれかを用いて、characteristicClient Characteristic Configuration デスクリプタ内の NotificationIndication のビットをクリアするべきです(SHOULD)。

  4. グローバルタスクをキューして Bluetooth タスクソース 上で、this関連付けられたグローバルオブジェクトに与え、resolve により promisethis で解決します。

注記: promise を解決するタスクをキューすることで、通知による value change events が promise 解決後に到着することがないように保証します。

6.4.1. BluetoothCharacteristicProperties

BluetoothRemoteGATTCharacteristic は、特性プロパティBluetoothCharacteristicProperties オブジェクトを通じて公開します。これらのプロパティは、その特性に対して有効な操作を表します。

[Exposed=Window, SecureContext]
interface BluetoothCharacteristicProperties {
  readonly attribute boolean broadcast;
  readonly attribute boolean read;
  readonly attribute boolean writeWithoutResponse;
  readonly attribute boolean write;
  readonly attribute boolean notify;
  readonly attribute boolean indicate;
  readonly attribute boolean authenticatedSignedWrites;
  readonly attribute boolean reliableWrite;
  readonly attribute boolean writableAuxiliaries;
};
Characteristic から BluetoothCharacteristicProperties インスタンスを作成するために、 characteristic に対して UA は次の手順を実行しなければなりません(MUST):
  1. propertiesObjBluetoothCharacteristicProperties の新しいインスタンスとします。

  2. propertiescharacteristic特性プロパティとします。

  3. properties 内の対応するビットに基づいて propertiesObj の属性を初期化します:

    属性 ビット
    broadcast Broadcast
    read Read
    writeWithoutResponse Write Without Response
    write Write
    notify Notify
    indicate Indicate
    authenticatedSignedWrites Authenticated Signed Writes
  4. もし 特性プロパティの Extended Properties ビットが 設定されていなければ、propertiesObj.reliableWrite および propertiesObj.writableAuxiliariesfalse に初期化します。そうでなければ、次の手順を実行します:

    1. 検出により Characteristic Extended Properties デスクリプタを characteristic について見つけ、 その値を読み取り extendedProperties に格納します。 エラー処理は § 6.7 Error handling に従います。

      Characteristic Extended Properties が、特定の Characteristic に対して 拡張プロパティが不変かどうかは明確ではありません。 もし不変であるなら、UA はそれらをキャッシュできるようにすべきです。

    2. 前の手順がエラーを返した場合は、そのエラーを返します。

    3. propertiesObj.reliableWrite を、extendedProperties の Reliable Write ビットに基づいて初期化します。

    4. propertiesObj.writableAuxiliaries を、extendedProperties の Writable Auxiliaries ビットに基づいて初期化します。

  5. propertiesObj を返します。

6.5. BluetoothRemoteGATTDescriptor

BluetoothRemoteGATTDescriptor は GATT の Descriptor を表し、 Characteristic の値に関する追加情報を提供します。

[Exposed=Window, SecureContext]
interface BluetoothRemoteGATTDescriptor {
  [SameObject]
  readonly attribute BluetoothRemoteGATTCharacteristic characteristic;
  readonly attribute UUID uuid;
  readonly attribute DataView? value;
  Promise<DataView> readValue();
  Promise<undefined> writeValue(BufferSource value);
};
characteristic は、 このデスクリプタが属する GATT 特性です。

uuid は特性デスクリプタの UUID です。例: '00002902-0000-1000-8000-00805f9b34fb' Client Characteristic Configuration デスクリプタです。

value は現在キャッシュされている デスクリプタ値です。この値はデスクリプタの値が読み取られたときに更新されます。

BluetoothRemoteGATTDescriptor のインスタンスは、以下の表で説明される 内部スロットとともに作成されます:

内部スロット 初期値 説明(非規範)
[[representedDescriptor]] <always set in prose> このオブジェクトが表す Descriptor。 Descriptor が削除されるなどして無効になっている場合は null
[[automatedDescriptorReadResponse]] "not-expected" GATT デスクリプタの読み取り試行に対するシミュレートされた応答コード。
[[automatedDescriptorReadResponseData]] 空の バイト列 GATT デスクリプタの読み取り試行に対するシミュレートされた応答データ。
[[automatedDescriptorWriteResponse]] "not-expected" GATT デスクリプタの書き込み試行に対するシミュレートされた応答コード。
BluetoothRemoteGATTDescriptor を作成して表現する ために、デスクリプタ descriptor に対して UA は次の手順を実行しなければなりません(MUST)。
  1. promise新しい promise とします。

  2. 次の手順を並行して実行します:

    1. result を、新しい BluetoothRemoteGATTDescriptor のインスタンスとし、その [[representedDescriptor]] スロットを descriptor に初期化します。

    2. resultcharacteristic を、 BluetoothRemoteGATTCharacteristic のうち descriptor が現れる Characteristic を表すインスタンスから初期化します。

    3. resultuuiddescriptor の UUID から初期化します。

    4. resultvaluenull に初期化します。 UA は、可能であれば resultvalue を、 newDataViewnewArrayBuffer をラップし、 descriptor から直近に読み取られた値を含むもの)に初期化してもよいです(MAY)。

    5. グローバルタスクをキューして、Bluetooth タスクソース上で this関連付けられたグローバルオブジェクトに与え、 resolve により promiseresult で解決します。

  3. promise を返します。

readValue() メソッドは、呼び出されたとき、次の手順を実行しなければなりません(MUST):
  1. globalthis関連付けられたグローバルオブジェクトとします。

  2. gattthis.characteristic.service.device.gatt とします。

  3. もし this.uuid読み取りに対してブロックリスト入りしている場合は、"SecurityError" の DOMException拒否された promise を返します。

  4. もし gatt.connectedfalse であれば、"NetworkError" の DOMException拒否された promise を返します。

  5. descriptorthis.[[representedDescriptor]] とします。

  6. もし descriptornull であれば、"InvalidStateError" の DOMException拒否された promise を返します。

  7. gatt に対する 接続チェックラッパー新しい promisepromise を包んで返し、 次の手順を並行して実行します:

    1. もし globalnavigabletop-level traversablesimulated Bluetooth adapter が空でない場合、次を実行します:

      1. もし this.[[automatedDescriptorReadResponse]]"not-expected" でないなら、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"InvalidStateError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      2. シミュレートされたデスクリプタイベントをトリガーし、 globalnavigablethis.devicedescriptor、および read を与えます。

      3. this.[[automatedDescriptorReadResponse]]"expected" に設定し、変化するまで待ちます。

      4. responsethis.[[automatedDescriptorReadResponse]] とします。

      5. this.[[automatedDescriptorReadResponse]]"not-expected" に設定します。

      6. もし response0 でなければ、次の副手順を実行します:

        1. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      7. それ以外の場合、buffernewArrayBuffer とし、this.[[automatedDescriptorReadResponseData]] を含むものとします。

    2. それ以外の場合、次の手順を実行します:

      1. UA が現在 Bluetooth システムを使用中である場合、グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"NetworkError" の DOMExceptionreject により promise を拒否してもよく(MAY)、これらの手順を中止します。

        実装によってはこの NetworkError を回避できるかもしれませんが、現状ではサイトはこの API の使用を直列化し、かつユーザーに失敗した操作を再試行できる手段を提供する必要があります。[Issue #188]

      2. Read Characteristic Descriptors または Read Long Characteristic Descriptors のいずれかの副手続きを用いて descriptor の値を取得し、その値を保持する newArrayBufferbuffer とします。エラー処理は § 6.7 Error handling に従います。

    3. グローバルタスクをキューして、Bluetooth タスクソース上で global に与え、次の手順を実行します:

      1. もし promisegatt.[[activeAlgorithms]] に存在しなければ、"NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      2. 上記の副手続きがエラーを返した場合は、そのエラーで reject により promise を拒否し、これらの手順を中止します。

      3. newDataViewbuffer から生成)を this.value に代入します。

      4. Resolve により promisethis.value で解決します。

writeValue(value) メソッドは、呼び出されたとき、次の手順を実行しなければなりません(MUST):
  1. globalthis関連付けられたグローバルオブジェクトとします。

  2. gattthis.characteristic.service.device.gatt とします。

  3. もし this.uuid書き込みに対してブロックリスト入りしている場合は、"SecurityError" の DOMException拒否された promise を返します。

  4. bytes を、value が保持するバイト列のコピーとします。

  5. もし bytes が 512 バイトを超える場合(Long Attribute Values による属性値の最大長)、 "InvalidModificationError" の DOMException拒否された promise を返します。

  6. もし gatt.connectedfalse であれば、"NetworkError" の DOMException拒否された promise を返します。

  7. descriptorthis.[[representedDescriptor]] とします。

  8. もし descriptornull であれば、"InvalidStateError" の DOMException拒否された promise を返します。

  9. gatt に対する 接続チェックラッパー新しい promisepromise を包んで返し、 次の手順を並行して実行します。

    1. もし globalnavigabletop-level traversablesimulated Bluetooth adapter が空でない場合、次を実行します:

      1. もし this.[[automatedDescriptorWriteResponse]]"not-expected" でないなら、 グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"InvalidStateError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      2. シミュレートされたデスクリプタイベントをトリガーし、 globalnavigablethis.devicedescriptorwrite、および bytes を与えます。

      3. this.[[automatedDescriptorWriteResponse]]"expected" に設定し、変化するまで待ちます。

      4. responsethis.[[automatedDescriptorWriteResponse]] とします。

      5. this.[[automatedDescriptorWriteResponse]]"not-expected" に設定します。

      6. もし response0 でなければ、次の副手順を実行します:

        1. グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

    2. それ以外の場合、次の手順を実行します:

      1. UA が現在 Bluetooth システムを使用中である場合、グローバルタスクをキューして Bluetooth タスクソース上で global に与え、"NetworkError" の DOMExceptionreject により promise を拒否してもよく(MAY)、これらの手順を中止します。

        実装によってはこの NetworkError を回避できるかもしれませんが、現状ではサイトはこの API の使用を直列化し、かつユーザーに失敗した操作を再試行できる手段を提供する必要があります。[Issue #188]

      2. Write Characteristic Descriptors または Write Long Characteristic Descriptors のいずれかの副手続きを用いて、 bytesdescriptor に書き込みます。エラー処理は § 6.7 Error handling に従います。

    3. グローバルタスクをキューして、Bluetooth タスクソース上で global に与え、次の手順を実行します:

      1. もし promisegatt.[[activeAlgorithms]] に存在しなければ、"NetworkError" の DOMExceptionreject により promise を拒否し、これらの手順を中止します。

      2. 上記の副手続きがエラーを返した場合、そのエラーで reject により promise を拒否し、これらの手順を中止します。

      3. this.value を、newDataViewnewArrayBufferbytes を格納したものをラップ)に設定します。

      4. Resolve により promiseundefined で解決します。

6.6. イベント

6.6.1. Bluetooth ツリー

Bluetooth tree は、 navigator.bluetooth と、 BluetoothDeviceBluetoothRemoteGATTServiceBluetoothRemoteGATTCharacteristic、 または BluetoothRemoteGATTDescriptor インターフェイスを実装し、木構造に参加するオブジェクトに与えられた名称です。

6.6.2. イベント型

advertisementreceived
BluetoothDevice 上で、そのデバイスからの広告イベントを受信したときに発火します。
availabilitychanged
navigator.bluetooth 上で、 Bluetooth システム全体が UA に対して利用可能または不可能になったときに発火します。
characteristicvaluechanged
BluetoothRemoteGATTCharacteristic 上で、その値が変更されたときに発火します。これは 読み出し要求の結果、または 値変更の通知/インジケーションの結果です。
gattserverdisconnected
BluetoothDevice 上で、アクティブな GATT 接続が失われたときに発火します。
serviceadded
新しい BluetoothRemoteGATTService 上で、 リモートデバイス上で検出されたときに、Bluetooth ツリーに追加された直後に発火します。
servicechanged
BluetoothRemoteGATTService 上で、その状態が変更されたときに発火します。これは、サービスに追加または削除されたあらゆる characteristic および/または descriptor、 ならびにリモートデバイスからの Service Changed インジケーションを含みます。
serviceremoved
BluetoothRemoteGATTService 上で、そのサービスがデバイスから削除されたときに、Bluetooth ツリーから削除される直前に発火します。

6.6.3. 切断への応答

Bluetooth デバイス deviceATT Bearer が失われた(例: リモートデバイスが範囲外に移動した、またはユーザーがプラットフォーム機能で切断した)とき、 各 BluetoothDevice deviceObj について、UA は グローバルタスクをキューして、Bluetooth タスクソース上で deviceObj関連付けられたグローバルオブジェクトに与え、次の手順を実行しなければなりません(MUST):
  1. deviceObj.[[representedDevice]]同一のデバイス device でなければ、これらの手順を中止します。

  2. !deviceObj.gatt.connected であれば、これらの手順を中止します。

  3. 切断されたデバイスのクリーンアップ deviceObj を実行します。

切断されたデバイスのクリーンアップ deviceObj を行うために、UA は次を実施しなければなりません:
  1. deviceObj.gatt.connectedfalse に設定します。

  2. deviceObj.gatt.[[activeAlgorithms]] をクリアします。

  3. deviceObj.gatt.[[automatedGATTConnectionResponse]]"not-expected" に設定します。

  4. contextdeviceObj.[[context]] とします。

  5. context.[[attributeInstanceMap]] から、キーが deviceObj.[[representedDevice]] 内にあるすべてのエントリを削除します。

  6. UA の realm 内の各 BluetoothRemoteGATTService service について、 service.[[representedService]]null に設定します。

  7. deviceObjrealm 内の各 BluetoothRemoteGATTCharacteristic characteristic について、次の副手順を行います:

    1. notificationContextscharacteristic.[[representedCharacteristic]]active notification context set とします。

    2. notificationContexts から context を削除します。

    3. もし notificationContexts が空になり、かつ deviceObj.[[representedDevice]] への ATT Bearer がまだ存在し、 さらに characteristicClient Characteristic Configuration デスクリプタを持つ場合、UA は Characteristic Descriptors 手続きのいずれかを用いて、 characteristic のそのデスクリプタ内の NotificationIndication ビットをクリアするべきです(SHOULD)。

    4. characteristic.[[representedCharacteristic]]null に設定します。

  8. deviceObjrealm 内の各 BluetoothRemoteGATTDescriptor descriptor について、 descriptor.[[representedDescriptor]]null に設定します。

  9. イベントを発火します。イベント名は gattserverdisconnected で、bubbles 属性を true に初期化して deviceObj に対して発火します。

    注記: このイベントは BluetoothRemoteGATTServer では発火しません。

6.6.4. 通知・インジケーションへの応答

UA が Bluetooth の Characteristic Value Notification または Indication を受信したとき、次の手順を実施しなければなりません:
  1. Characteristic の active notification context set 内の 各 bluetoothGlobal について、グローバルタスクをキューして、Bluetooth タスクソース上で bluetoothGlobal関連付けられたグローバルオブジェクトに与え、次の副手順を実行します:

    1. characteristicObject を、bluetoothGlobal をルートとする Bluetooth ツリー内で その Characteristic を表す BluetoothRemoteGATTCharacteristic とします。

    2. characteristicObject .service.device.gatt.connectedfalse であれば、これらの副手順を中止します。

    3. characteristicObject.value を、 新しい DataView(新しい ArrayBuffer をラップし、Characteristic の新しい値を保持するもの)に設定します。

    4. イベントを発火します。イベント名は characteristicvaluechanged で、bubbles 属性を true に初期化して characteristicObject に対して発火します。

6.6.5. サービス変更への応答

Bluetooth の Attribute Caching システムは、クライアントが ServiceCharacteristic、および Descriptor の変更を追跡できるようにします。 これらの属性をウェブページに公開する目的で発見する前に、UA は(存在する場合) Service Changed characteristic からのインジケーションを購読しなければなりません(MUST)。 UA が Service Changed characteristic のインジケーションを受信したとき、次の手順を実行しなければなりません(MUST)。
  1. removedAttributes を、インジケーション前に UA が発見していた、 Service Changed characteristic が示す範囲内の属性のリストとします。

  2. Primary Service DiscoveryRelationship DiscoveryCharacteristic Discovery、および Characteristic Descriptor Discovery 手続きを用いて、Service Changed characteristic が示す範囲内の属性を再発見します。 その発見の結果が、後述のイベントに影響しないことを UA が証明できる場合、示された範囲の全部または一部の発見を省略してもかまいません(MAY)。

  3. addedAttributes を、前の手順で発見した属性のリストとします。

  4. Service Interoperability Requirements に示す 同一の定義(Characteristic と Descriptor の値は無視)を持つ属性が removedAttributesaddedAttributes の両方に現れる場合、それを両方から削除します。

    次のデバイス状態を仮定します:
    状態 1
    • Service A
      • Characteristic C: 値 [1, 2, 3]
    • Service B
    状態 2
    • Service A
      • Characteristic C: 値 [3, 2, 1]
    • Service B
    状態 3
    • Service A
      • Characteristic D: 値 [3, 2, 1]
    • Service B
    状態 4
    • Service A
      • Characteristic C: 値 [1, 2, 3]
    • Service B
      • Include Service A

    状態 1 から 2 への遷移では、サービス A は「Characteristic と Descriptor の値を無視した同じ定義」のままなので、 removedAttributesaddedAttributes の両方から削除され、 いかなる servicechanged イベントにも現れません。

    状態 1 から 3 への遷移では、サービス定義に characteristic 定義が含まれるため、 サービス A は異なる定義となります。よってサービス A は removedAttributesaddedAttributes の両方に残ります。その後 手順 8 でサービスは changedServices に移され、 servicechanged イベントのみを引き起こし、serviceaddedserviceremoved の両方にはなりません。 手順 9 でも、 Characteristic C が削除され D が追加されたため、サービス A が changedServices に追加されます。

    状態 1 から 4 への遷移は 1→3 の遷移に類似しています。サービス B は 手順 8changedServices に移されますが、 characteristic や descriptor は変更されていないため、 手順 9 で重複して追加されることはありません。

  5. invalidatedAttributes を、 removedAttributes にあって addedAttributes にはない属性とします。

  6. UA 内の各 environment settings object settings について、その responsible event loop 上で タスクをキューし、次の副手順を行います:

    1. BluetoothRemoteGATTService service のうち、 関連設定オブジェクトsettings であるものについて、 service.[[representedService]]invalidatedAttributes に含まれていれば、 service.[[representedService]]null に設定します。

    2. BluetoothRemoteGATTCharacteristic characteristic のうち、 関連設定オブジェクトsettings であるものについて、 characteristic.[[representedCharacteristic]]invalidatedAttributes に含まれていれば、 characteristic.[[representedCharacteristic]]null に設定します。

    3. BluetoothRemoteGATTDescriptor descriptor のうち、 関連設定オブジェクトsettings であるものについて、 descriptor.[[representedDescriptor]]invalidatedAttributes に含まれていれば、 descriptor.[[representedDescriptor]]null に設定します。

    4. globalsettingsグローバルオブジェクトとします。

    5. global.navigator.bluetooth.[[attributeInstanceMap]] から、invalidatedAttributes に含まれる属性を表すすべてのエントリを削除します。

  7. changedServices を空集合の Service の集合とします。

  8. 同一ServiceremovedAttributesaddedAttributes の両方に現れる場合、それを両方から削除し、changedServices に追加します。

  9. removedAttributes または addedAttributes にある各 Characteristic および Descriptor について、 それを元のリストから削除し、その親の ServicechangedServices に追加します。

    注記: この時点以降、removedAttributesaddedAttributes には Service のみが含まれます。
  10. ある ServiceaddedAttributes に含まれていても、それが過去の getPrimaryServicegetPrimaryServicesgetIncludedService、 または getIncludedServices のいずれの呼び出し時点でも存在していたとしても返されなかったであろう場合、 UA はその ServiceaddedAttributes から削除してもよい(MAY)とします。

  11. changedDevices を、 removedAttributesaddedAttributeschangedServices のいずれかに Service を含む Bluetooth デバイスの集合とします。

  12. changedDevices 内のデバイスに接続している各 BluetoothDevice deviceObj について、グローバルタスクをキューして、 Bluetooth タスクソース上で deviceObj関連付けられたグローバルオブジェクトに与え、次の手順を実行します:

    1. removedAttributes 内の各 Service service について:

      1. deviceObj.[[allowedServices]]"all" であるか、当該 Service の UUID を含む場合、 イベントを発火します。イベント名は serviceremoved で、bubbles 属性を true に初期化して、 その BluetoothRemoteGATTService に対して発火します。

      2. この BluetoothRemoteGATTServiceBluetooth ツリーから削除します。

    2. addedAttributes 内の各 Service について、 deviceObj.[[allowedServices]]"all" であるか、当該 Service の UUID を含む場合、 当該 Service を表す BluetoothRemoteGATTServiceBluetooth ツリーに追加し、 続いて イベントを発火します。イベント名は serviceadded で、bubbles 属性を true に初期化して、その BluetoothRemoteGATTService に対して発火します。

    3. changedServices 内の各 Service について、 deviceObj.[[allowedServices]]"all" であるか、当該 Service の UUID を含む場合、 イベントを発火します。イベント名は servicechanged で、bubbles 属性を true に初期化して、 当該 BluetoothRemoteGATTService に対して発火します。

6.6.6. IDL イベントハンドラー

[SecureContext]
interface mixin CharacteristicEventHandlers {
  attribute EventHandler oncharacteristicvaluechanged;
};

oncharacteristicvaluechanged は、 Event handler IDL 属性であり、 characteristicvaluechanged イベント型のためのものです。

[SecureContext]
interface mixin BluetoothDeviceEventHandlers {
  attribute EventHandler onadvertisementreceived;
  attribute EventHandler ongattserverdisconnected;
};

onadvertisementreceived は、Event handler IDL 属性であり、 advertisementreceived イベント型のためのものです。

ongattserverdisconnected は、Event handler IDL 属性であり、 gattserverdisconnected イベント型のためのものです。

[SecureContext]
interface mixin ServiceEventHandlers {
  attribute EventHandler onserviceadded;
  attribute EventHandler onservicechanged;
  attribute EventHandler onserviceremoved;
};

onserviceadded は、 Event handler IDL 属性であり、 serviceadded イベント型のためのものです。

onservicechanged は、 Event handler IDL 属性であり、 servicechanged イベント型のためのものです。

onserviceremoved は、 Event handler IDL 属性であり、 serviceremoved イベント型のためのものです。

6.7. エラー処理

注記: この節は主に、システムエラーから JavaScript エラー名へのマッピングを定義し、UA が特定の操作を再試行できるようにします。 再試行ロジックやエラーの区別可能性は OS に大きく制約されます。そのため、ここでの要件が現実を反映していない箇所は、 ブラウザのバグではなく 仕様のバグ である可能性が高いです。
UA がアルゴリズムの手順を実行するため、または Bluetooth キャッシュへの問い合わせ(以下、併せて「手順」と呼ぶ)を扱うために GATT 手続きを使用しており、その GATT 手続きが Error Response を返した場合、UA は次を実行しなければなりません(MUST):
  1. もし 手続きがタイムアウトするか、 Profile Fundamentals に記述の ATT Bearer が何らかの理由で存在しない/終了している場合、 当該手順から NetworkError を返し、これらの手順を中止します。

  2. Error Code に応じて、次のとおりにします:

    Invalid PDU
    Invalid Offset
    Attribute Not Found
    Unsupported Group Type
    これらのエラーコードはプロトコル層で予期しない事象(UA またはデバイスのバグの可能性)を示します。 当該手順から NotSupportedError を返します。
    Invalid Handle
    当該手順から InvalidStateError を返します。
    Invalid Attribute Value Length
    当該手順から InvalidModificationError を返します。
    Attribute Not Long

    このエラーコードを「Long」サブ手続きを用いずに受信した場合、デバイスのバグを示す可能性があります。 当該手順から NotSupportedError を返します。

    それ以外の場合、「Long」サブ手続きを使用せずに当該手順を再試行します。 書き込み値の長さのためにそれが不可能であれば、 InvalidModificationError を返します。

    Insufficient Authentication
    Insufficient Encryption
    Insufficient Encryption Key Size
    UA は接続のセキュリティレベルを引き上げるよう試みるべきです(SHOULD)。 この試みが失敗した、または UA がより高いセキュリティをサポートしない場合、 当該手順から SecurityError を返します。 そうでなければ、より高いセキュリティレベルで当該手順を再試行します。
    Insufficient Authorization
    当該手順から SecurityError を返します。
    Application Error
    GATT 手続きが Write であった場合、 当該手順から InvalidModificationError を返します。そうでなければ、 NotSupportedError を返します。
    Read Not Permitted
    Write Not Permitted
    Request Not Supported
    Prepare Queue Full
    Insufficient Resources
    Unlikely Error
    その他
    当該手順から NotSupportedError を返します。

7. UUID

typedef DOMString UUID;

UUID 文字列は 128-bit の [RFC4122] UUID を表します。 有効な UUID は、 [ECMAScript] の正規表現 /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/ に一致する文字列です。 つまり、有効な UUID は小文字であり、 Bluetooth 規格で定義される 16-bit や 32-bit の省略形は使用しません。 本仕様の関数や属性から返されるすべての UUID は 有効な UUID でなければなりません(MUST)。 さらに、本仕様の関数が UUID 型のパラメータ、 あるいは UUID 属性を含む辞書を受け取り、 任意の UUID スロットに渡された引数が 有効な UUID でない場合、 その関数は 拒否された promise を返し、TypeError で他の手順を中止しなければなりません(MUST)。

注記: 本規格は、 BluetoothUUID.canonicalUUID(alias) 関数を提供し、16-bit/32-bit の Bluetooth の UUID エイリアスを 128-bit 形式にマップします。
注記: Bluetooth デバイスは(Attribute Type に記述のとおり) 比較の前に 16-bit/32-bit の UUID を 128-bit に変換する必要がありますが、すべてのデバイスがそうしているわけではありません。 これらのデバイスと相互運用するため、UA がデバイスからある形式(16/32/128-bit)で UUID を受信した場合、 その UUID の他のエイリアスをデバイスへ送る際には同じ形式を用いるべきです。

7.1. 標準化された UUID

Bluetooth SIG は [BLUETOOTH-ASSIGNED] で、サービス、characteristic、descriptor、その他のエンティティを識別する UUID のレジストリを管理しています。 本節は、スクリプトがそれらの UUID を名前で参照できる方法を提供し、各アプリケーションで繰り返し定義する必要がないようにします。

有効な名前は、 [ECMAScript] の正規表現 /^[a-z0-9_-.]+$/ に一致する文字列です。

[Exposed=Window]
interface BluetoothUUID {
  static UUID getService((DOMString or unsigned long) name);
  static UUID getCharacteristic((DOMString or unsigned long) name);
  static UUID getDescriptor((DOMString or unsigned long) name);

  static UUID canonicalUUID([EnforceRange] unsigned long alias);
};

typedef (DOMString or unsigned long) BluetoothServiceUUID;
typedef (DOMString or unsigned long) BluetoothCharacteristicUUID;
typedef (DOMString or unsigned long) BluetoothDescriptorUUID;

静的メソッド BluetoothUUID. canonicalUUID(alias) は、呼び出されたとき、 16-bit または 32-bit の UUID エイリアス alias が表す 128-bit UUID を返さなければなりません(MUST)。

注記: このアルゴリズムは、「00000000-0000-1000-8000-00805f9b34fb」の上位 32 ビットをエイリアスのビットで置き換えることから成ります。 例えば、canonicalUUID(0xDEADBEEF)"deadbeef-0000-1000-8000-00805f9b34fb" を返します。

BluetoothServiceUUID は、 16/32-bit の UUID エイリアス、有効な UUID、 および GATT assigned services のキーからの 有効な名前を表します。言い換えると、 BluetoothUUID.getService() が例外を投げない値に相当します。

BluetoothCharacteristicUUID は、 16/32-bit の UUID エイリアス、有効な UUID、 および GATT assigned characteristics のキーからの 有効な名前を表します。言い換えると、 BluetoothUUID.getCharacteristic() が例外を投げない値に相当します。

BluetoothDescriptorUUID は、 16/32-bit の UUID エイリアス、有効な UUID、 および GATT assigned descriptors のキーからの 有効な名前を表します。言い換えると、 BluetoothUUID.getDescriptor() が例外を投げない値に相当します。

ResolveUUIDName(name, GATT assigned numbers) を行うために、UA は次の手順を実施しなければなりません(MUST):
  1. もし nameunsigned long であれば、 BluetoothUUID.canonicalUUID(name) を返し、これらの手順を中止します。

  2. もし name有効な UUID であれば、 name を返し、これらの手順を中止します。

  3. もし name有効な名前 で、 GATT assigned numbers において 有効な UUID に対応しているなら、 その割り当て番号を alias とし、 BluetoothUUID.canonicalUUID(alias) を返します。

  4. それ以外の場合、TypeError を投げます。

静的メソッド BluetoothUUID. getService(name) は、呼び出されたとき、 ResolveUUIDName(name, GATT assigned services) を返さなければなりません(MUST)。

静的メソッド BluetoothUUID. getCharacteristic(name) は、呼び出されたとき、 ResolveUUIDName(name, GATT assigned characteristics) を返さなければなりません(MUST)。

静的メソッド BluetoothUUID. getDescriptor(name) は、呼び出されたとき、 ResolveUUIDName(name, GATT assigned descriptors) を返さなければなりません(MUST)。

BluetoothUUID.getService(" cycling_power")"00001818-0000-1000-8000-00805f9b34fb" を返します。

BluetoothUUID.getService("00001801-0000-1000-8000-00805f9b34fb")"00001801-0000-1000-8000-00805f9b34fb" を返します。

BluetoothUUID.getService("unknown-service")TypeError を投げます。

BluetoothUUID.getCharacteristic("ieee_11073-20601_regulatory_certification_data_list")"00002a2a-0000-1000-8000-00805f9b34fb" を返します。

BluetoothUUID.getDescriptor("gatt.characteristic_presentation_format")"00002904-0000-1000-8000-00805f9b34fb" を返します。

7.2. GATT 割り当て番号

この仕様は、標準化された GATT のサービス、characteristic、descriptor を利用する開発者の可読性を高めるために、 GATT 割り当て番号に対する人間が読める名前を提供します。GATT 割り当て番号のファイルは https://github.com/WebBluetoothCG/registries リポジトリにあります。

この仕様では以前、Bluetooth SIG によって提供されたマッピングテーブルを用いて、これらの人間可読名を定義していました。 そのテーブルが保守されなくなっていることが判明したため、マッピングテーブルは仕様内に直接記載されるようになりました。
URL url にある GATT 割り当て番号の構文解析の結果は、 valid name から valid UUID へのマップ、またはエラーであり、次のアルゴリズムによって生成されます:
  1. url をフェッチし、そのボディを UTF-8 でデコードしたものを contents とします。

  2. linescontents'\n' で分割したものとします。

  3. result を空のマップとします。

  4. lines 内の各 line について、次の副手順を実行します:

    1. もし line が空、または先頭文字が '#' であれば、次の行へ進みます。

    2. もし linevalid name、スペース (U+0020)、および valid UUID からなる場合、 name をその名前、uuid をその UUID とします。

    3. それ以外の場合はエラーを返し、これらの手順を中止します。

    4. もし name がすでに result にある場合はエラーを返し、これらの手順を中止します。

    5. result において name から uuid への対応を追加します。

  5. result を返します。

GATT 割り当てサービスは、 GATT 割り当て番号の構文解析 https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_services.txt で行った結果です。 UA はこのファイルを定期的に再フェッチするべきですが、その頻度は未規定です。

GATT 割り当て characteristic は、 GATT 割り当て番号の構文解析 https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_characteristics.txt で行った結果です。 UA はこのファイルを定期的に再フェッチするべきですが、その頻度は未規定です。

GATT 割り当て descriptor は、 GATT 割り当て番号の構文解析 https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_descriptors.txt で行った結果です。 UA はこのファイルを定期的に再フェッチするべきですが、その頻度は未規定です。

8. Advertising Data Filter

広告データフィルターは、メーカーまたはサービスデータとの照合方法を表します。

advertising data filter を構文解析するために、 stringinput から、次の手順を実行します:
  1. words を、inputstrictly split/ 区切りにしたものとします。

  2. もし words の長さが 2 に等しくなければ、エラーを返してこれらの手順を中止します。

  3. もし words[0] の長さが words[1] の長さに等しくなければ、エラーを返して これらの手順を中止します。

  4. prefixDatawords[0] とします。

  5. prefixMaskwords[1] とします。

  6. もし prefixData または prefixMaskascii lower hex digit の並びでなければ、エラーを返します。

  7. prefixIndex0 とします。

  8. dataList を空のリストとします。

  9. maskList を空のリストとします。

  10. prefixIndexprefixData の長さより小さい間、次の副手順を実行します:

    1. data を、prefixData のインデックス prefixIndexprefixIndex + 1 の文字を 16 進数として解釈した結果とします。

    2. mask を、prefixMask のインデックス prefixIndexprefixIndex + 1 の文字を 16 進数として解釈した結果とします。

    3. dataListdata を追加します。

    4. maskListmask を追加します。

    5. prefixIndex|prefixIndex| + 2 に設定します。

  11. result を新しい BluetoothDataFilterInit 辞書とします。

  12. result[dataPrefix] を、dataList を用いて構築した Uint8Array に設定します。

  13. result[mask] を、maskList を用いて構築した Uint8Array に設定します。

  14. result を返します。

9. ブロックリスト

この仕様は、ウェブサイトがアクセスできる GATT 属性およびメーカー・データの集合を制限するために、 https://github.com/WebBluetoothCG/registries リポジトリ内のブロックリストファイルに依存します。

valid company identifier string は、 ascii lower hex digit の並びで、 長さが 0 より大きく 5 未満であるものです。公式の会社識別子一覧は Bluetooth Assigned Numbers のサイトにあります。

URL url にある manufacturer data blocklist の構文解析 の結果は、 Company Identifier Code から BluetoothDataFilterInit のリストへのマップ、 またはエラーであり、次のアルゴリズムによって生成されます:
  1. url をフェッチし、そのボディを UTF-8 でデコードしたものを contents とします。

  2. lines を、contents に対してセパレーター '\n' を用いて split(separator, limit) を呼び出した結果とします。

  3. result を空のマップとします。

  4. lines 内の各 line について、次の副手順を実行します:

    1. もし line が空、または先頭文字が '#' であれば、次の行へ進みます。

    2. regExp を、'manufacturer\ ([0-9a-f]+)\ ([0-9a-f]+\/[0-9a-f]+)' で構築した RegExp とします。

    3. matchResult を、line に対して regExp.exec(string) を呼び出した結果とし、matchResultnull または matchResult の長さが 3 に等しくない場合はエラーを返します。

    4. companyIdentifierStr を、matchResult[1] が valid company identifier string であるときは matchResult[1] とし、そうでなければエラーを返します。

    5. companyIdentifier を、companyIdentifierStr を 16 進数として解釈した結果とします。

    6. dataPrefixStrmatchResult[2] とします。

    7. もし companyIdentifierresult に存在しなければ、 result[companyIdentifier] を空のリストに設定します。

    8. dataFilter を、dataPrefixStr に対して advertising data filter を構文解析 した結果(エラーでない場合)とし、エラーであればエラーを返します。

    9. result[companyIdentifier] に dataFilter を追加します。

  5. result を返します。

URL url にある gatt blocklist の構文解析 の結果は、 valid UUID からトークンへのマップ、またはエラーであり、 次のアルゴリズムによって生成されます:
  1. url をフェッチし、そのボディを UTF-8 でデコードしたものを contents とします。

  2. linescontents'\n' で分割したものとします。

  3. result を空のマップとします。

  4. lines 内の各 line について、次の副手順を実行します:

    1. もし line が空、または先頭文字が '#' であれば、次の行へ進みます。

    2. もし linevalid UUID のみから成る場合、 uuid をその UUID、token を "exclude" とします。

    3. もし linevalid UUID、スペース (U+0020)、および "exclude-reads" または "exclude-writes" のいずれかのトークンから成る場合、 uuid をその UUID、token をそのトークンとします。

    4. それ以外の場合はエラーを返し、これらの手順を中止します。

    5. もし uuid がすでに result にある場合はエラーを返し、これらの手順を中止します。

    6. result において uuid から token への対応を追加します。

  5. result を返します。

GATT blocklist は、 gatt blocklist の構文解析 https://github.com/WebBluetoothCG/registries/blob/master/gatt_blocklist.txt で行った結果です。 Manufacturer Data blocklist は、 manufacturer data blocklist の構文解析 https://github.com/WebBluetoothCG/registries/blob/master/manufacturer_data_blocklist.txt で行った結果です。 UA はブロックリストを定期的に再フェッチするべきですが、その頻度は未規定です。

UUID は、 blocklisted であるのは、 GATT blocklist の値がエラーである場合、または その UUID が GATT blocklist で "exclude" にマップされる場合です。

UUID は、 blocklisted for reads であるのは、 GATT blocklist の値がエラーである場合、または その UUID が GATT blocklist で "exclude" もしくは "exclude-reads" にマップされる場合です。

UUID は、 blocklisted for writes であるのは、 GATT blocklist の値がエラーである場合、または その UUID が GATT blocklist で "exclude" もしくは "exclude-writes" にマップされる場合です。

manufacturer data manufacturerData は、次の手順が blocked を返す場合に blocklisted manufacturer data です:
  1. もし Manufacturer Data blocklist の値がエラーであれば、 blocked を返します。

  2. manufacturerBlocklist を、 Manufacturer Data blocklist の値とします。

  3. companyIdentifiermanufacturerData の会社識別子とします。

  4. もし companyIdentifiermanufacturerBlocklist に存在しなければ、 unblocked を返します。

  5. manufacturerBlocklist[companyIdentifier] 内の各 dataFilter について、 次の副手順を実行します:

    1. もし manufacturerData の広告データが matchesdataFilter に一致するなら、 blocked を返します。

  6. unblocked を返します。

manufacturer data filter manufacturerDataFilter は、次の手順が blocked を返す場合に blocklisted manufacturer data filter です:
  1. もし Manufacturer Data blocklist の値がエラーであれば、 blocked を返します。

  2. manufacturerBlocklist を、 Manufacturer Data blocklist の値とします。

  3. companyIdentifiermanufacturerDataFilter["companyIdentifier"] とします。

  4. もし companyIdentifiermanufacturerBlocklist に存在しなければ、 unblocked を返します。

  5. manufacturerBlocklist[companyIdentifier] 内の各 dataFilter について、 次の副手順を実行します:

    1. もし manufacturerDataFilterdataFilterstrict subset であれば、blocked を返します。

  6. unblocked を返します。

[SecureContext]
partial interface Navigator {
  [SameObject]
  readonly attribute Bluetooth bluetooth;
};

Navigator は、associated BluetoothBluetooth オブジェクト)を持ちます。 Navigator オブジェクトの作成時に、その associated Bluetooth は、 その Navigator オブジェクトの relevant realm で作成された新しい Bluetooth オブジェクトに設定されなければなりません。

Navigatorbluetooth ゲッター手順は、 thisassociated Bluetooth を返すことです。

11. 統合

11.1. Permissions Policy

この仕様は、トークン "bluetooth" によって識別される policy-controlled feature を定義します。 これは、bluetooth 属性によって公開されるメソッドが Navigator オブジェクト上で利用可能かどうかを制御します。

この機能の default allowlist["self"] です。

12. 自動テスト

ユーザーエージェントの自動化およびアプリケーションテストの目的のために、この文書は [WebDriver-BiDi] 仕様への拡張を定義します。

Web Bluetooth API とその拡張仕様は、物理的なハードウェアデバイスが予測可能な方法で応答することを必要とするため、 それらのインターフェイスを完全にテストすることがテスト作成者にとって課題となります。 この課題に対処するために、本書は物理デバイスとその広告と同様に振る舞う、シミュレートされた周辺機器と広告を定義・制御する いくつかの WebDriver-BiDi の拡張コマンドを定義します。これらのシミュレートされた周辺機器と広告は特定のプロパティを持つデバイスを表し、 その読み取り値はユーザーによって完全に定義できます。

top-level traversable は、 ソフトウェアで定義された Bluetooth アダプターで、発見済みの simulated Bluetooth devices を保持し、 Central のような役割を担うことができる simulated Bluetooth adapter を持つことがあります。

simulated Bluetooth adapter は、 Bluetooth アドレスの strings から simulated Bluetooth devices への ordered map である simulated Bluetooth device mapping を持ちます。

simulated Bluetooth adapter は、 現在のアダプターの状態を表す文字列の列挙である adapter state を持ちます。 取り得る列挙値は次のとおりです:

simulated Bluetooth adapter は、 アダプターが Bluetooth Low Energy をサポートするかどうかを示す boolean である low-energy supported state を持ちます。

シミュレートされたBluetoothデバイスは、物理デバイスのように動作するソフトウェア定義のBluetoothデバイスであり、シミュレートされたBluetoothアダプターに接続される場合があり、Manufacturer Specific DataサービスUUIDなどの関連プロパティを持つ場合があり、そしてシミュレートされたGATTサービスマッピングを持っている。これはBluetooth順序付きマップであり、UUID文字列からシミュレートされたGATTサービスへの対応関係を持つ。

simulated GATT service は、ソフトウェアで定義された Service で、 simulated Bluetooth device に属し、 UUID のプロパティを持ち、 Bluetooth cache に既知の存在として登録され、 さらに Bluetooth の ordered map である simulated GATT characteristic mappingUUID 文字列から simulated GATT characteristics へのマップ)を持ちます。

simulated GATT characteristic は、ソフトウェアで定義された Characteristic で、 simulated GATT service に属し、 UUIDCharacteristic Properties のプロパティを持ち、 Bluetooth cache に既知の存在として登録され、 さらに Bluetooth の ordered map である simulated GATT descriptor mappingUUID 文字列から simulated GATT descriptors へのマップ)を持ちます。

Simulated GATT characteristic properties は、 Characteristic Properties のソフトウェアで定義されたもので、 simulated GATT characteristic に属し、 Bluetooth cache に既知の存在として登録されます。

simulated GATT descriptor は、ソフトウェアで定義された Descriptor で、 simulated GATT characteristic に属し、 UUID のプロパティを持ち、 Bluetooth cache に既知の存在として登録されます。

CDDL スニペットは、 CDDL スニペットの独立したプログラム処理を可能にするために "browsingContext.BrowsingContext" の代わりに "text" 型を使用します。現在、他のモジュールは参照できません。

12.1. 定義

bluetooth.BluetoothUuid = text;
bluetooth.BluetoothManufacturerData = { key: uint, data: tstr };
bluetooth.CharacteristicProperties = {
  ? broadcast: bool,
  ? read: bool,
  ? writeWithoutResponse: bool,
  ? write: bool,
  ? notify: bool,
  ? indicate: bool,
  ? authenticatedSignedWrites: bool,
  ? extendedProperties: bool
}
key
Company Identifier Code です。
data
メーカー・データの byte sequence を base64 エンコードしたものです。

12.2. bluetooth モジュール

bluetooth モジュールには、リモート側の Bluetooth の挙動を管理するためのコマンドが含まれます。

12.2.1.

12.2.1.1. bluetooth.RequestDevice 型
bluetooth.RequestDevice = text

bluetooth.RequestDevice は、デバイス選択プロンプト内の 1 つのデバイスを識別するための識別子です。

device prompt は、 tuple で、 文字列である device prompt id と、 set である set of devicesBluetoothDevice オブジェクトの集合) から構成されます。これはユーザーが choose によって Bluetooth device を選択できるプロンプトを表します。

12.2.1.2. bluetooth.RequestDeviceInfo 型
bluetooth.RequestDeviceInfo = {
   id: bluetooth.RequestDevice,
   name: text / null,
}

bluetooth.RequestDeviceInfo は、デバイス選択プロンプト内の 1 つのデバイスを表します。

BluetoothDevice device が与えられたときに、 デバイスを直列化するには:
  1. iddevice.id とします。

  2. namedevice.name とします。

  3. bluetooth.RequestDeviceInfo の生成規則に一致する map を返し、 そこでは "id"id に、"name"name に設定されます。

12.2.1.3. bluetooth.RequestDevicePrompt 型
bluetooth.RequestDevicePrompt = text

bluetooth.RequestDevicePrompt は、単一のプロンプトを識別するための識別子です。

リモート側は、map である map of navigables to device prompts を持ち、 そのキーは navigable ids、値は device prompts です。

navigableIdpromptId が与えられたときに、 プロンプトを取得するには:
  1. promptMapmap of navigables to device prompts とします。

  2. もし promptMap[navigableId] が exist しなければ:

    1. error を返します。error codeno such prompt です。

  3. promptmap of navigables to device prompts[navigableId] とします。

  4. もし promptdevice prompt idpromptId でない場合:

    1. error を返します。error codeno such prompt です。

  5. success をデータ prompt とともに返します。

device promptpromptdeviceId が与えられたときに、 プロンプト内のデバイスに一致させるには:
  1. promptset of devices 内の各 device について:

    1. もし device.iddeviceId であれば、 データ device とともに success を返します。

  2. それ以外の場合:

    1. error を返します。error codeno such device です。

device promptprompt が与えられたときに、 プロンプトのデバイスを直列化するには:
  1. devices を空の list とします。

  2. promptset of devices 内の各 device について。

    1. Append を用いて、 直列化 した devicedevices に追加します。

  3. devices を返します。

12.2.1.4. bluetooth.ScanRecord 型
bluetooth.ScanRecord = {
  ? name: text,
  ? uuids: [ * bluetooth.BluetoothUuid ],
  ? appearance: number,
  ? manufacturerData: [ * bluetooth.BluetoothManufacturerData ],
}

bluetooth.ScanRecord は、 Bluetooth device によって送信された 広告パケットのデータを表します。

name
Bluetooth device のローカル名、 もしくはそのプレフィックスです。
uuids
このスキャンレコードが、その Bluetooth device の GATT サーバーがサポートしていると示す Service UUID の一覧です。
appearance
Appearance であり、 gap.appearance characteristic によって定義される値の一つです。
manufacturerData
BluetoothManufacturerData のリストで、 unsigned short の Company Identifier Code から、 base64 エンコードされたメーカー・データの byte sequences へのマッピングです。

12.2.2. エラー

この仕様は、エラーコードの集合を WebDriver BiDi から拡張し、以下の追加コードを定義します:

no such device
未知の BluetoothDevice を参照しようとしました。
no such prompt
未知の device prompt を参照しようとしました。

12.2.3. コマンド

BluetoothCommand = (
  bluetooth.HandleRequestDevicePrompt //
  bluetooth.SimulateAdapter //
  bluetooth.DisableSimulation //
  bluetooth.SimulatePreconnectedPeripheral //
  bluetooth.SimulateAdvertisement //
  bluetooth.SimulateGattConnectionResponse //
  bluetooth.SimulateGattDisconnection //
  bluetooth.SimulateService //
  bluetooth.SimulateCharacteristic //
  bluetooth.SimulateCharacteristicResponse //
  bluetooth.SimulateDescriptor //
  bluetooth.SimulateDescriptorResponse
)
12.2.3.1. bluetooth.handleRequestDevicePrompt コマンド
bluetooth.HandleRequestDevicePrompt = (
   method: "bluetooth.handleRequestDevicePrompt",
   params: bluetooth.HandleRequestDevicePromptParameters,
)

bluetooth.HandleRequestDevicePromptParameters = {
   context: text,
   prompt: bluetooth.RequestDevicePrompt,
   (
       bluetooth.HandleRequestDevicePromptAcceptParameters //
       bluetooth.HandleRequestDevicePromptCancelParameters
   )
}

bluetooth.HandleRequestDevicePromptAcceptParameters = (
   accept: true,
   device: bluetooth.RequestDevice,
)

bluetooth.HandleRequestDevicePromptCancelParameters = (
   accept: false,
)
リモートエンドの手順で、command parameters が与えられた場合は次のとおりです:
  1. contextIdparams["context"] とします。

  2. promptIdparams["prompt"] とします。

  3. prompt を、試行して プロンプトを取得 し、 contextIdpromptId を用いた結果とします。

  4. accept を、command parametersaccept フィールドの値とします。

  5. もし accept が true の場合:

    1. deviceId を、command parametersdevice フィールドの値とします。

    2. device を、試行して プロンプト内のデバイスに一致 させた結果とし、 引数は promptdeviceId とします。

    3. device を用いて prompt を承認します。

  6. それ以外の場合:

    1. prompt を却下します。

  7. success をデータ null とともに返します。

ローカルエンドは、次のメッセージを送信することでプロンプトを却下できます:
{
  "method": "bluetooth.handleRequestDevicePrompt",
  "params": {
    "context": "cxt-d03fdd81",
    "prompt": "pmt-e0a234b",
    "accept": true,
    "device": "dvc-9b3b872"
  }
}
12.2.3.2. bluetooth.simulateAdapter コマンド
bluetooth.SimulateAdapter = (
   method: "bluetooth.simulateAdapter",
   params: bluetooth.SimulateAdapterParameters,
)

bluetooth.SimulateAdapterParameters = {
   context: text,
   ? leSupported: bool,
   state: "absent" / "powered-off" / "powered-on"
}
リモートエンドの手順で、コマンド引数 params が与えられた場合は次のとおりです:
  1. contextIdparams["context"] とします。

  2. navigable を、試行して navigable を取得した contextId に対する結果とします。

  3. もし navigableトップレベルトラバーサブルでなければ、errorエラーコード invalid argument とともに返します。

  4. simulatedBluetoothAdapter を、navigablesimulated Bluetooth adapter とします。

  5. もし simulatedBluetoothAdapter が空であれば、次の手順を実行します:

    1. もし params["leSupported"] が 存在しない 場合、 params["leSupported"] を true に設定します。

    2. simulatedBluetoothAdapter を新しい simulated Bluetooth adapter とします。

    3. simulatedBluetoothAdapterLE supported stateparams["leSupported"] に設定します。

    4. simulatedBluetoothAdapteradapter stateparams["state"] に設定します。

    5. navigablesimulated Bluetooth adaptersimulatedBluetoothAdapter に設定します。

    6. success をデータ null とともに返します。

  6. もし simulatedBluetoothAdapter が空でない場合、次の手順を実行します:

    1. もし params["leSupported"] が 存在する 場合、errorエラーコード invalid argument とともに返します。

    2. simulatedBluetoothAdapteradapter stateparams["state"] に設定します。

    3. success をデータ null とともに返します。

ローカルエンドは、次のメッセージを送信することで Bluetooth Low Energy をサポートするアダプターをシミュレートできます:
{
  "method": "bluetooth.simulateAdapter",
  "params": {
    "context": "cxt-d03fdd81",
    "leSupported": true,
    "state": "powered-on",
  }
}
ローカルエンドは、次のメッセージを送信することで既存のアダプターの adapter state を更新できます:
{
  "method": "bluetooth.simulateAdapter",
  "params": {
    "context": "cxt-d03fdd81",
    "state": "powered-off",
  }
}
12.2.3.3. bluetooth.disableSimulation コマンド
bluetooth.DisableSimulation = (
   method: "bluetooth.disableSimulation",
   params: bluetooth.DisableSimulationParameters,
)

bluetooth.DisableSimulationParameters = {
   context: text
}
リモートエンドの手順で、コマンド引数 params が与えられた場合は次のとおりです:
  1. contextIdparams["context"] とします。

  2. navigable を、試行して navigable を取得した contextId に対する結果とします。

  3. もし navigableトップレベルトラバーサブルでなければ、errorエラーコード invalid argument とともに返します。

  4. navigablesimulated Bluetooth adapter を空に設定します。

  5. success をデータ null とともに返します。

ローカルエンドは、次のメッセージを送信することで既存のシミュレーションを無効化できます:
{
  "method": "bluetooth.disableSimulation",
  "params": {
    "context": "cxt-d03fdd81"
  }
}
12.2.3.4. bluetooth.simulatePreconnectedPeripheral コマンド
bluetooth.SimulatePreconnectedPeripheral = (
   method: "bluetooth.simulatePreconnectedPeripheral",
   params: bluetooth.SimulatePreconnectedPeripheralParameters,
)

bluetooth.SimulatePreconnectedPeripheralParameters = {
   context: text,
   address: text,
   name: text,
   manufacturerData: [ * bluetooth.BluetoothManufacturerData ],
   knownServiceUuids: [ * bluetooth.BluetoothUuid ]
}
リモートエンドの手順で、コマンド引数 params が与えられた場合は次のとおりです:
  1. contextId を params["context"] とします。

  2. navigable を、試行して navigable を取得した contextId に対する結果とします。

  3. もし navigableトップレベルトラバーサブルでなければ、errorエラーコード invalid argument とともに返します。

  4. simulatedBluetoothAdapter を、navigablesimulated Bluetooth adapter とします。

  5. もし simulatedBluetoothAdapter が空であれば、errorエラーコード invalid argument とともに返します。

  6. deviceAddressparams["address"] とします。

  7. deviceMapping を、simulatedBluetoothAdaptersimulated Bluetooth device mapping とします。

  8. もし deviceMapping[deviceAddress] が 存在する 場合、 errorエラーコード invalid argument とともに返します。

  9. simulatedBluetoothDevice を新しい simulated Bluetooth device とします。

  10. simulatedBluetoothDevice の name を params["name"] に設定します。

  11. simulatedBluetoothDevice の address を params["address"] に設定します。

  12. simulatedBluetoothDevicemanufacturer specific data を、params["manufacturerData"] に対して実行した forgiving-base64 decode の出力に設定します。

  13. simulatedBluetoothDeviceservice UUIDsparams["knownServiceUuids"] に設定します。

  14. deviceMapping[deviceAddress] に simulatedBluetoothDevice を設定します。

  15. success をデータ null とともに返します。

ローカルエンドは、次のメッセージを送信することで事前接続されたペリフェラルをシミュレートできます:
{
  "method": "bluetooth.simulatePreconnectedPeripheral",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "name": "Some Device",
    "manufacturerData": [ { key: 17, data: "AP8BAX8=" } ],
    "knownServiceUuids": [
      "12345678-1234-5678-9abc-def123456789",
    ],
  }
}
12.2.3.5. bluetooth.simulateAdvertisement コマンド
bluetooth.SimulateAdvertisement = (
   method: "bluetooth.simulateAdvertisement",
   params: bluetooth.SimulateAdvertisementParameters,
)

bluetooth.SimulateAdvertisementParameters = {
   context: text,
   scanEntry: bluetooth.SimulateAdvertisementScanEntryParameters
}

bluetooth.SimulateAdvertisementScanEntryParameters = {
   deviceAddress: text,
   rssi: number,
   scanRecord: bluetooth.ScanRecord
}

リモートエンドの手順で、コマンド引数 params が与えられた場合は次のとおりです:
  1. contextIdparams["context"] とします。

  2. topLevelNavigable を、試行して navigable を取得した contextId に対する結果とします。

  3. もし topLevelNavigableトップレベルトラバーサブルでなければ、errorエラーコード invalid argument とともに返します。

  4. scanEntryparams["scanEntry"] とします。

  5. deviceAddressscanEntry["deviceAddress"] とします。

  6. simulatedBluetoothAdapter を、topLevelNavigablesimulated Bluetooth adapter とします。

  7. もし simulatedBluetoothAdapter が空であれば、errorエラーコード invalid argument とともに返します。

  8. deviceMapping を、simulatedBluetoothAdaptersimulated Bluetooth device mapping とします。

  9. もし deviceMapping[deviceAddress] が 存在する 場合は simulatedDevicedeviceMapping[deviceAddress] とし、そうでない場合は simulatedDevice を新しい simulated Bluetooth devicedeviceAddress を持つ)とし、 deviceMapping[deviceAddress] に simulatedDevice を設定します。

  10. もし topLevelNavigable が現在 scan for devices アルゴリズムを実行中なら、 そのアルゴリズム内の変数 simulatedBluetoothDevicessimulatedDevice を挿入します。

    他のアルゴリズムの変数へデータを挿入することは厳密には定義されていません。 実装に合わせるため、scan for devices アルゴリズムは非同期デバイス発見を定義する必要があります。

  11. navigables を、topLevelNavigableアクティブドキュメント包括的子孫 navigables とします。

  12. navigables の各 navigable について:

    1. documentnavigableアクティブドキュメント とします。

    2. タスクをキューして、document関連設定オブジェクト責務を負うイベントループ上で次の副手順を実行します:

      1. simulatedDeviceInstance を、 BluetoothDevice を表すオブジェクトを取得した結果とし、 navigableアクティブウィンドウ対応する Navigatorassociated Bluetooth 内で simulatedDevice を表すものとします。

      2. もし simulatedDeviceInstance.[[watchAdvertisementsState]]not-watching であれば、これらの副手順を中止します。

      3. advertisementreceived イベントを発火し、 scanEntry["scanRecord"] が表す広告イベントに対して simulatedDeviceInstance 上で発生させます。

  13. success をデータ null とともに返します。

ローカルエンドは、次のメッセージを送信することでデバイス広告をシミュレートできます:
{
  "method": "bluetooth.simulateAdvertisement",
  "params": {
    "context": "cxt-d03fdd81",
    "scanEntry": {
      "deviceAddress": "08:08:08:08:08:08",
      "rssi": -10,
      "scanRecord": {
        "name": "Heart Rate",
        "uuids": ["0000180d-0000-1000-8000-00805f9b34fb"],
        "manufacturerData": [ { key: 17, data: "AP8BAX8=" } ],
        "appearance": 1,
        "txPower": 1
      }
    }
  }
}
12.2.3.6. bluetooth.simulateGattConnectionResponse コマンド
bluetooth.SimulateGattConnectionResponse = (
   method: "bluetooth.simulateGattConnectionResponse",
   params: bluetooth.SimulateGattConnectionResponseParameters,
)

bluetooth.SimulateGattConnectionResponseParameters = {
   context: text,
   address: text,
   code: uint
}

リモートエンドの手順で、コマンド引数 params が与えられた場合は次のとおりです:
  1. contextIdparams["context"] とします。

  2. navigable を、試行して navigable を取得した contextId に対する結果とします。

  3. deviceAddressparams["address"] とします。

  4. simulatedBluetoothAdapter を、navigablesimulated Bluetooth adapter とします。

  5. もし simulatedBluetoothAdapter が空であれば、errorエラーコード invalid argument とともに返します。

  6. deviceMapping を、simulatedBluetoothAdaptersimulated Bluetooth device mapping とします。

  7. もし deviceMapping[deviceAddress] が 存在する 場合は simulatedDevicedeviceMapping[deviceAddress] とし、 そうでない場合は errorエラーコード invalid argument とともに返します。

  8. simulatedDeviceInstance を、BluetoothDevice を表すオブジェクトを取得した結果とし、 navigableアクティブウィンドウ対応する Navigatorassociated Bluetooth 内で simulatedDevice を表すものとします。

  9. もし simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]"expected" であれば、 simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]params["code"] に設定します。

  10. それ以外の場合は、errorエラーコード invalid element state とともに返します。

ローカルエンドは、成功(List of Error Codes によればエラーコード 0x00)の デバイス gatt 接続レスポンスを、次のメッセージを送信することでシミュレートできます:
{
  "method": "bluetooth.simulateGattConnectionResponse",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "code": 0
  }
}
12.2.3.7. bluetooth.simulateGattDisconnection コマンド
bluetooth.SimulateGattDisconnection = (
   method: "bluetooth.simulateGattDisconnection",
   params: bluetooth.SimulateGattDisconnectionParameters,
)

bluetooth.SimulateGattDisconnectionParameters = {
   context: text,
   address: text,
}

リモートエンドの手順で、コマンド引数 params が与えられた場合は次のとおりです:
  1. contextIdparams["context"] とします。

  2. navigable を、試行して navigable を取得した contextId に対する結果とします。

  3. deviceAddressparams["address"] とします。

  4. simulatedBluetoothAdapter を、navigablesimulated Bluetooth adapter とします。

  5. もし simulatedBluetoothAdapter が空であれば、errorエラーコード invalid argument とともに返します。

  6. deviceMapping を、simulatedBluetoothAdaptersimulated Bluetooth device mapping とします。

  7. もし deviceMapping[deviceAddress] が 存在する 場合は simulatedDevicedeviceMapping[deviceAddress] とし、 そうでない場合は errorエラーコード invalid argument とともに返します。

  8. simulatedDeviceInstance を、BluetoothDevice を表すオブジェクトを取得した結果とし、 navigableアクティブウィンドウ対応する Navigatorassociated Bluetooth 内で simulatedDevice を表すものとします。

  9. もし simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]"expected" であれば、 simulatedDeviceInstance.[[gatt]].[[automatedGATTConnectionResponse]]0x15 に設定します。

    0x15List of Error Codes によれば "Remote Device Terminated Connection due to Power Off" を表します。これは、Bluetooth デバイスが GATT 接続試行に応答できない状況をシミュレートします。
  10. それ以外の場合は、切断されたデバイスのクリーンアップsimulatedDeviceInstance に対して実行します。

ローカルエンドは、次のメッセージを送信することでデバイスの GATT 切断をシミュレートできます:
{
  "method": "bluetooth.simulateGattDisconnection",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
  }
}
12.2.3.8. bluetooth.simulateService コマンド
bluetooth.SimulateService = (
   method: "bluetooth.simulateService",
   params: bluetooth.SimulateServiceParameters,
)

bluetooth.SimulateServiceParameters = {
   context: text,
   address: text,
   uuid: bluetooth.BluetoothUuid,
   type: "add" / "remove",
}
リモートエンドの手順で、コマンド引数 params が与えられた場合は次のとおりです:
  1. contextIdparams["context"] とします。

  2. navigable を、試行して navigable を取得した contextId に対する結果とします。

  3. deviceAddressparams["address"] とします。

  4. simulatedBluetoothAdapter を、navigablesimulated Bluetooth adapter とします。

  5. もし simulatedBluetoothAdapter が空であれば、errorエラーコード invalid argument とともに返します。

  6. deviceMapping を、simulatedBluetoothAdaptersimulated Bluetooth device mapping とします。

  7. もし deviceMapping[deviceAddress] が 存在する 場合は simulatedDevicedeviceMapping[deviceAddress] とします。

  8. それ以外の場合は、errorエラーコード invalid argument とともに返します。

  9. simulatedDeviceInstance を、BluetoothDevice を表すオブジェクトを取得した結果とし、 navigableアクティブウィンドウ対応する Navigatorassociated Bluetooth 内で simulatedDevice を表すものとします。

  10. serviceMapping を、simulatedDevicesimulated GATT service mapping とします。

  11. uuidparams["uuid"] とします。

  12. もし params["type"] が "add" の場合:

    1. もし serviceMapping[uuid] が 存在する 場合、errorエラーコード invalid element state とともに返します。

    2. simulatedGattService を新しい simulated GATT service とします。

    3. simulatedGattServiceUUIDuuid に設定します。

    4. serviceMapping[uuid] を simulatedGattService に設定します。

    5. BluetoothRemoteGATTService を表すオブジェクトを作成し、 その結果の Promise への simulatedGattService からのマッピングを simulatedDeviceInstance.[[context]].[[attributeInstanceMap]] に追加します。

    6. success をデータ null とともに返します。

  13. もし params["type"] が "remove" の場合:

    1. もし serviceMapping[uuid] が 存在する 場合、simulatedGattServiceserviceMapping[uuid] とします。

    2. それ以外の場合は、errorエラーコード invalid element state とともに返します。

    3. simulatedGattServicesimulatedDeviceInstance.[[context]].[[attributeInstanceMap]] から削除します。

    4. serviceMapping から uuid を削除します。

    5. success をデータ null とともに返します。

  14. errorエラーコード invalid argument とともに返します。

ローカルエンドは、次のメッセージを送信することで GATT サービスの追加をシミュレートできます:
{
  "method": "bluetooth.simulateService",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "uuid": "0000180d-0000-1000-8000-00805f9b34fb",
    "type": "add"
  }
}
ローカルエンドは、次のメッセージを送信することで GATT サービスの削除をシミュレートできます:
{
  "method": "bluetooth.simulateService",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "uuid": "0000180d-0000-1000-8000-00805f9b34fb",
    "type": "remove"
  }
}
12.2.3.9. bluetooth.simulateCharacteristic コマンド
bluetooth.SimulateCharacteristic = (
   method: "bluetooth.simulateCharacteristic",
   params: bluetooth.SimulateCharacteristicParameters,
)

bluetooth.SimulateCharacteristicParameters = {
   context: text,
   address: text,
   serviceUuid: bluetooth.BluetoothUuid,
   characteristicUuid: bluetooth.BluetoothUuid,
   ? characteristicProperties: bluetooth.CharacteristicProperties,
   type: "add" / "remove"
}
リモートエンドの手順で、コマンド引数 params が与えられた場合は次のとおりです:
  1. contextIdparams["context"] とします。

  2. navigable を、試行して navigable を取得した contextId に対する結果とします。

  3. deviceAddressparams["address"] とします。

  4. simulatedBluetoothAdapter を、navigablesimulated Bluetooth adapter とします。

  5. もし simulatedBluetoothAdapter が空であれば、errorエラーコード invalid argument とともに返します。

  6. deviceMapping を、simulatedBluetoothAdaptersimulated Bluetooth device mapping とします。

  7. もし deviceMapping[deviceAddress] が 存在する 場合は simulatedDevicedeviceMapping[deviceAddress] とします。

  8. それ以外の場合は、errorエラーコード invalid argument とともに返します。

  9. BluetoothDevice を表すオブジェクトを取得した結果を simulatedDeviceInstance とし、navigableアクティブウィンドウ対応する Navigatorassociated Bluetooth 内で simulatedDevice を表すものとします。

  10. serviceMapping を、simulatedDevicesimulated GATT service mapping とします。

  11. serviceUuidparams["serviceUuid"] とします。

  12. もし serviceMapping[serviceUuid] が 存在する 場合は simulatedServiceserviceMapping[serviceUuid] とします。

  13. それ以外の場合は、errorエラーコード invalid argument とともに返します。

  14. characteristicMapping を、simulatedServicesimulated GATT characteristic mapping とします。

  15. characteristicUuidparams["characteristicUuid"] とします。

  16. もし params["type"] が "add" の場合:

    1. もし characteristicMapping[characteristicUuid] が 存在する 場合、errorエラーコード invalid element state とともに返します。

    2. もし params["characteristicProperties"] が 存在しない 場合、errorエラーコード invalid argument とともに返します。

    3. simulatedGattCharacteristicProperties を新しい simulated GATT characteristic properties とし、次を実行します:

      1. propertiesparams["characteristicProperties"] とします。

      2. もし properties["broadcast"] が 存在する 場合、 properties["broadcast"] が true なら simulatedGattCharacteristicPropertiesBroadcast ビットをセットします。

      3. もし properties["read"] が 存在する 場合、 properties["read"] が true なら simulatedGattCharacteristicPropertiesRead ビットをセットします。

      4. もし properties["writeWithoutResponse"] が 存在する 場合、 properties["writeWithoutResponse"] が true なら simulatedGattCharacteristicPropertiesWrite Without Response ビットをセットします。

      5. もし properties["write"] が 存在する 場合、 properties["write"] が true なら simulatedGattCharacteristicPropertiesWrite ビットをセットします。

      6. もし properties["notify"] が 存在する 場合、 properties["notify"] が true なら simulatedGattCharacteristicPropertiesNotify ビットをセットします。

      7. もし properties["indicate"] が 存在する 場合、 properties["indicate"] が true なら simulatedGattCharacteristicPropertiesIndicate ビットをセットします。

      8. もし properties["authenticatedSignedWrites"] が 存在する 場合、 properties["authenticatedSignedWrites"] が true なら simulatedGattCharacteristicPropertiesAuthenticated Signed Writes ビットをセットします。

      9. もし properties["extendedProperties"] が 存在する 場合、 properties["extendedProperties"] が true なら simulatedGattCharacteristicPropertiesExtended Properties ビットをセットします。

    4. simulatedGattCharacteristic を新しい simulated GATT characteristic とします。

    5. simulatedGattCharacteristicUUIDcharacteristicUuid に設定します。

    6. simulatedGattCharacteristicCharacteristic PropertiessimulatedGattCharacteristicProperties に設定します。

    7. characteristicMapping[characteristicUuid] を simulatedGattCharacteristic に設定します。

    8. BluetoothRemoteGATTCharacteristic を表すオブジェクトを作成し、 その結果の Promise への simulatedGattCharacteristic からのマッピングを simulatedDeviceInstance.[[context]].[[attributeInstanceMap]] に追加します。

    9. success をデータ null とともに返します。

  17. もし params["type"] が "remove" の場合:

    1. もし params["characteristicProperties"] が 存在する 場合、errorエラーコード invalid argument とともに返します。

    2. もし characteristicMapping[characteristicUuid] が 存在する 場合、simulatedGattCharacteristiccharacteristicMapping[characteristicUuid] とします。

    3. それ以外の場合は、errorエラーコード invalid element state とともに返します。

    4. simulatedGattCharacteristicsimulatedDeviceInstance.[[context]].[[attributeInstanceMap]] から削除します。

    5. characteristicUuidcharacteristicMapping から削除します。

    6. success をデータ null とともに返します。

  18. errorエラーコード invalid argument とともに返します。

ローカルエンドは、read・write・notify のプロパティをもつ GATT characteristic の追加を 次のメッセージを送信することでシミュレートできます:
{
  "method": "bluetooth.simulateCharacteristic",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "serviceUuid": "0000180d-0000-1000-8000-00805f9b34fb",
    "characteristicUuid": "00002a21-0000-1000-8000-00805f9b34fb",
    "characteristicProperties": {
      "read": true,
      "write": true,
      "notify": true
    },
    "type": "add"
  }
}
ローカルエンドは、次のメッセージを送信することで GATT characteristic の削除をシミュレートできます:
{
  "method": "bluetooth.simulateCharacteristic",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "serviceUuid": "0000180d-0000-1000-8000-00805f9b34fb",
    "characteristicUuid": "00002a21-0000-1000-8000-00805f9b34fb",
    "type": "remove"
  }
}
12.2.3.10. bluetooth.simulateCharacteristicResponse コマンド
bluetooth.SimulateCharacteristicResponse = (
   method: "bluetooth.simulateCharacteristicResponse",
   params: bluetooth.SimulateCharacteristicResponseParameters,
)

bluetooth.SimulateCharacteristicResponseParameters = {
   context: text,
   address: text,
   serviceUuid: bluetooth.BluetoothUuid,
   characteristicUuid: bluetooth.BluetoothUuid,
   type: "read" / "write" / "subscribe-to-notifications" / "unsubscribe-from-notifications",
   code: uint,
   ? data: [ * uint ]
}
リモートエンドの手順で、コマンド引数 params が与えられた場合は次のとおりです:
  1. contextIdparams["context"] とします。

  2. navigable を、試行して navigable を取得した contextId に対する結果とします。

  3. deviceAddressparams["address"] とします。

  4. simulatedBluetoothAdapter を、navigablesimulated Bluetooth adapter とします。

  5. もし simulatedBluetoothAdapter が空であれば、errorエラーコード invalid argument とともに返します。

  6. deviceMapping を、simulatedBluetoothAdaptersimulated Bluetooth device mapping とします。

  7. もし deviceMapping[deviceAddress] が 存在する 場合は simulatedDevicedeviceMapping[deviceAddress] とし、 それ以外の場合は errorエラーコード invalid argument とともに返します。

  8. serviceMapping を、simulatedDevicesimulated GATT service mapping とします。

  9. serviceUuidparams["serviceUuid"] とします。

  10. もし serviceMapping[serviceUuid] が 存在する 場合は simulatedServiceserviceMapping[serviceUuid] とします。

  11. それ以外の場合は、errorエラーコード invalid argument とともに返します。

  12. characteristicMapping を、simulatedServicesimulated GATT characteristic mapping とします。

  13. characteristicUuidparams["characteristicUuid"] とします。

  14. もし characteristicMapping[characteristicUuid] が 存在する 場合は simulatedGattCharacteristiccharacteristicMapping[characteristicUuid] とします。

  15. それ以外の場合は、errorエラーコード invalid element state とともに返します。

  16. BluetoothDevice を表すオブジェクトを取得した結果を simulatedDeviceInstance とし、navigableアクティブウィンドウ対応する Navigatorassociated Bluetooth 内で simulatedDevice を表すものとします。

  17. promisesimulatedDeviceInstance.[[context]].[[attributeInstanceMap]][simulatedGattCharacteristic] とします。

  18. Upon fulfillment において、promisecharacteristic で解決されたとき、次を実行します:

    1. もし params["type"] が read の場合、次を実行します:

      1. もし characteristic.[[automatedCharacteristicReadResponse]]expected であれば、 characteristic.[[automatedCharacteristicReadResponse]]params["code"] に、 characteristic.[[automatedCharacteristicReadResponseData]]a copy of the bytes heldparams["data"] のバイト列のコピー)に設定します。

      2. それ以外の場合は、errorエラーコード invalid element state とともに返します。

    2. もし params["type"] が write の場合、次を実行します:

      1. もし characteristic.[[automatedCharacteristicWriteResponse]]expected であれば、 characteristic.[[automatedCharacteristicWriteResponse]]params["code"] に設定します。

      2. それ以外の場合は、errorエラーコード invalid element state とともに返します。

    3. もし params["type"] が subscribe-to-notifications の場合、次を実行します:

      1. もし characteristic.[[automatedCharacteristicSubscribeToNotificationsResponse]]expected であれば、 characteristic.[[automatedCharacteristicSubscribeToNotificationsResponse]]params["code"] に設定します。

      2. それ以外の場合は、errorエラーコード invalid element state とともに返します。

    4. もし params["type"] が unsubscribe-from-notifications の場合、次を実行します:

      1. もし characteristic.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]expected であれば、 characteristic.[[automatedCharacteristicUnsubscribeFromNotificationsResponse]]params["code"] に設定します。

      2. それ以外の場合は、errorエラーコード invalid element state とともに返します。

    5. それ以外の場合は、errorエラーコード invalid argument とともに返します。

ローカルエンドは、Error Response によればエラーコード 0x00(成功)となる characteristic の読み取り操作のデータ付き応答を、次のメッセージを送信することでシミュレートできます:
{
  "method": "bluetooth.simulateCharacteristicResponse",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "serviceUuid": "0000180d-0000-1000-8000-00805f9b34fb",
    "characteristicUuid": "00002a21-0000-1000-8000-00805f9b34fb",
    "type": "read",
    "code": 0,
    "data": [1, 2]
  }
}
12.2.3.11. bluetooth.simulateDescriptor コマンド
bluetooth.SimulateDescriptor = (
   method: "bluetooth.simulateDescriptor",
   params: bluetooth.SimulateDescriptorParameters,
)

bluetooth.SimulateDescriptorParameters = {
   context: text,
   address: text,
   serviceUuid: bluetooth.BluetoothUuid,
   characteristicUuid: bluetooth.BluetoothUuid,
   descriptorUuid: bluetooth.BluetoothUuid,
   type: "add" / "remove"
}
  1. contextIdparams["context"] とします。

  2. navigable を、試行して navigable を取得した contextId に対する結果とします。

  3. deviceAddressparams["address"] とします。

  4. simulatedBluetoothAdapter を、navigablesimulated Bluetooth adapter とします。

  5. もし simulatedBluetoothAdapter が空であれば、errorエラーコード invalid argument とともに返します。

  6. deviceMapping を、simulatedBluetoothAdaptersimulated Bluetooth device mapping とします。

  7. もし deviceMapping[deviceAddress] が 存在する 場合は simulatedDevicedeviceMapping[deviceAddress] とします。

  8. それ以外の場合は、errorエラーコード invalid argument とともに返します。

  9. BluetoothDevice を表すオブジェクトを取得した結果を simulatedDeviceInstance とし、navigableアクティブウィンドウ対応する Navigatorassociated Bluetooth 内で simulatedDevice を表すものとします。

  10. serviceMapping を、simulatedDevicesimulated GATT service mapping とします。

  11. serviceUuidparams["serviceUuid"] とします。

  12. もし serviceMapping[serviceUuid] が 存在する 場合は simulatedServiceserviceMapping[serviceUuid] とします。

  13. それ以外の場合は、errorエラーコード invalid argument とともに返します。

  14. characteristicMapping を、simulatedServicesimulated GATT characteristic mapping とします。

  15. characteristicUuidparams["characteristicUuid"] とします。

  16. もし characteristicMapping[characteristicUuid] が 存在する 場合は simulatedCharacteristiccharacteristicMapping[characteristicUuid] とします。

  17. それ以外の場合は、errorエラーコード invalid argument とともに返します。

  18. descriptorMapping を、simulatedCharacteristicsimulated GATT descriptor mapping とします。

  19. descriptorUuidparams["descriptorUuid"] とします。

  20. もし params["type"] が "add" の場合:

    1. もし descriptorMapping[descriptorUuid] が 存在する 場合、errorエラーコード invalid element state とともに返します。

    2. simulatedGattDescriptor を新しい simulated GATT descriptor とします。

    3. simulatedGattDescriptorUUIDdescriptorUuid に設定します。

    4. descriptorMapping[descriptorUuid] を simulatedGattDescriptor に設定します。

    5. BluetoothRemoteGATTDescriptor を表すオブジェクトを作成し、 その結果の Promise への simulatedGattDescriptor からのマッピングを simulatedDeviceInstance.[[context]].[[attributeInstanceMap]] に追加します。

    6. success をデータ null とともに返します。

  21. もし params["type"] が "remove" の場合:

    1. もし descriptorMapping[descriptorUuid] が 存在する 場合、simulatedGattDescriptordescriptorMapping[descriptorUuid] とします。

    2. それ以外の場合は、errorエラーコード invalid element state とともに返します。

    3. simulatedGattDescriptorsimulatedDeviceInstance.[[context]].[[attributeInstanceMap]] から削除します。

    4. descriptorUuiddescriptorMapping から削除します。

    5. success をデータ null とともに返します。

  22. errorエラーコード invalid argument とともに返します。

ローカルエンドは、次のメッセージを送信することで GATT descriptor の追加をシミュレートできます:
{
  "method": "bluetooth.simulateDescriptor",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "serviceUuid": "0000180d-0000-1000-8000-00805f9b34fb",
    "characteristicUuid": "00002a21-0000-1000-8000-00805f9b34fb",
    "descriptorUuid": "00002901-0000-1000-8000-00805f9b34fb",
    "type": "add"
  }
}
ローカルエンドは、次のメッセージを送信することで GATT descriptor の削除をシミュレートできます:
{
  "method": "bluetooth.simulateDescriptor",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "serviceUuid": "0000180d-0000-1000-8000-00805f9b34fb",
    "characteristicUuid": "00002a21-0000-1000-8000-00805f9b34fb",
    "descriptorUuid": "00002901-0000-1000-8000-00805f9b34fb",
    "type": "remove"
  }
}
12.2.3.12. bluetooth.simulateDescriptorResponse コマンド
bluetooth.SimulateDescriptorResponse = (
   method: "bluetooth.simulateDescriptorResponse",
   params: bluetooth.SimulateDescriptorResponseParameters,
)

bluetooth.SimulateDescriptorResponseParameters = {
   context: text,
   address: text,
   serviceUuid: bluetooth.BluetoothUuid,
   characteristicUuid: bluetooth.BluetoothUuid,
   descriptorUuid: bluetooth.BluetoothUuid,
   type: "read" / "write",
   code: uint,
   ? data: [ * uint ]
}
  1. contextIdparams["context"] とします。

  2. navigable を、試行して navigable を取得した contextId に対する結果とします。

  3. deviceAddressparams["address"] とします。

  4. simulatedBluetoothAdapter を、navigablesimulated Bluetooth adapter とします。

  5. もし simulatedBluetoothAdapter が空であれば、errorエラーコード invalid argument とともに返します。

  6. deviceMapping を、simulatedBluetoothAdaptersimulated Bluetooth device mapping とします。

  7. もし deviceMapping[deviceAddress] が 存在する 場合は simulatedDevicedeviceMapping[deviceAddress] とし、 それ以外の場合は errorエラーコード invalid argument とともに返します。

  8. serviceMapping を、simulatedDevicesimulated GATT service mapping とします。

  9. serviceUuidparams["serviceUuid"] とします。

  10. もし serviceMapping[serviceUuid] が 存在する 場合は simulatedServiceserviceMapping[serviceUuid] とします。

  11. それ以外の場合は、errorエラーコード invalid argument とともに返します。

  12. characteristicMapping を、simulatedServicesimulated GATT characteristic mapping とします。

  13. characteristicUuidparams["characteristicUuid"] とします。

  14. もし characteristicMapping[characteristicUuid] が 存在する 場合は simulatedCharacteristiccharacteristicMapping[characteristicUuid] とします。

  15. それ以外の場合は、errorエラーコード invalid element state とともに返します。

  16. descriptorMapping を、simulatedCharacteristicsimulated GATT descriptor mapping とします。

  17. descriptorUuidparams["descriptorUuid"] とします。

  18. もし descriptorMapping[descriptorUuid] が 存在する 場合は simulatedDescriptordescriptorMapping[descriptorUuid] とします。

  19. それ以外の場合は、errorエラーコード invalid element state とともに返します。

  20. BluetoothDevice を表すオブジェクトを取得した結果を simulatedDeviceInstance とし、navigableアクティブウィンドウ対応する Navigatorassociated Bluetooth 内で simulatedDevice を表すものとします。

  21. promisesimulatedDeviceInstance.[[context]].[[attributeInstanceMap]][simulatedDescriptor] とします。

  22. Upon fulfillment において、promisedescriptor で解決されたとき、次を実行します:

    1. もし params["type"] が read の場合、次を実行します:

      1. もし descriptor.[[automatedDescriptorReadResponse]]expected であれば、 descriptor.[[automatedDescriptorReadResponse]]params["code"] に、 descriptor.[[automatedDescriptorReadResponseData]]a copy of the bytes heldparams["data"] のバイト列のコピー)に設定します。

      2. それ以外の場合は、errorエラーコード invalid element state とともに返します。

    2. もし params["type"] が write の場合、次を実行します:

      1. もし characteristic.[[automatedDescriptorWriteResponse]]expected であれば、 characteristic.[[automatedDescriptorWriteResponse]]params["code"] に設定します。

      2. それ以外の場合は、errorエラーコード invalid element state とともに返します。

    3. それ以外の場合は、errorエラーコード invalid argument とともに返します。

ローカルエンドは、Error Response によればエラーコード 0x00(成功)となる descriptor の読み取り操作のデータ付き応答を、次のメッセージを送信することでシミュレートできます:
{
  "method": "bluetooth.simulateDescriptorResponse",
  "params": {
    "context": "cxt-d03fdd81",
    "address": "09:09:09:09:09:09",
    "serviceUuid": "0000180d-0000-1000-8000-00805f9b34fb",
    "characteristicUuid": "00002a21-0000-1000-8000-00805f9b34fb",
    "descriptorUuid": "00002901-0000-1000-8000-00805f9b34fb",
    "type": "read",
    "code": 0,
    "data": [1, 2]
  }
}

12.2.4. イベント

BluetoothEvent = (
  bluetooth.RequestDevicePromptUpdated //
  bluetooth.GattConnectionAttempted
)
12.2.4.1. bluetooth.requestDevicePromptUpdated イベント
bluetooth.RequestDevicePromptUpdated = (
   method: "bluetooth.requestDevicePromptUpdated",
   params: bluetooth.RequestDevicePromptUpdatedParameters
)

bluetooth.RequestDevicePromptUpdatedParameters = {
   context: text,
   prompt: bluetooth.RequestDevicePrompt,
   devices: [* bluetooth.RequestDeviceInfo],
}
プロンプト更新イベントをトリガーする ために、navigable navigable、文字列 promptId、および setBluetooth devices devices が与えられたときは次のとおりです:
  1. navigableIdnavigablenavigable id とします。

  2. prompt を、device prompt (promptId, devices) とします。

  3. serialized devices を、promptserialize prompt devices を実行した結果とします。

  4. map of navigables to device prompts[navigableId] を prompt に設定します。

  5. params を、mapbluetooth.RequestDevicePromptUpdatedParameters 生成規則に合致するものとし、 context フィールドを navigableIdprompt フィールドを promptIddevices フィールドを serialized devices に設定します。

  6. body を、mapbluetooth.RequestDevicePromptUpdated 生成規則に合致するものとし、params フィールドを params に設定します。

  7. relatedNavigables を、navigable を含む set とします。

  8. set of sessions for which an event is enabled("bluetooth.requestDevicePromptUpdated" と relatedNavigables が与えられたもの)の各 session について:

    1. イベントを送出し、sessionbody を用います。

12.2.4.2. bluetooth.gattConnectionAttempted イベント
bluetooth.GattConnectionAttempted = (
   method: "bluetooth.gattConnectionAttempted",
   params: bluetooth.GattConnectionAttemptedParameters
)

bluetooth.GattConnectionAttemptedParameters = {
   context: text,
   address: text
}
gatt 接続試行イベントをトリガーする ために、navigable navigableBluetoothDevice device が与えられたときは次のとおりです:
  1. navigableIdnavigablenavigable id とします。

  2. params を、mapbluetooth.GattConnectionAttemptedParameters 生成規則に合致するものとし、 context フィールドを navigableId に、address フィールドを device.[[representedDevice]] の address に設定します。

  3. body を、mapbluetooth.GattConnectionAttempted 生成規則に合致するものとし、params フィールドを params に設定します。

  4. relatedNavigables を、navigable を含む set とします。

  5. set of sessions for which an event is enabled の各 session( "bluetooth.gattEventGenerated" と relatedNavigables が与えられたもの)について:

    1. イベントを送出し、sessionbody を用います。

12.2.4.3. bluetooth.characteristicEventGenerated イベント
bluetooth.CharacteristicEventGenerated = (
   method: "bluetooth.characteristicEventGenerated",
   params: bluetooth.CharacteristicEventGeneratedParameters
)

bluetooth.CharacteristicEventGeneratedParameters = {
  context: text,
  address: text,
  serviceUuid: bluetooth.BluetoothUuid,
  characteristicUuid: bluetooth.BluetoothUuid,
  type: "read" / "write-with-response" / "write-without-response" / "subscribe-to-notifications" / "unsubscribe-from-notifications",
  ? data: [ * uint ]
}

シミュレートされた characteristic イベントをトリガーする ために、navigable navigableBluetoothDevice devicesimulated GATT characteristic characteristicstring type、任意の byte sequence bytes が与えられたときは次のとおりです:

  1. navigableIdnavigablenavigable id とします。

  2. params を、mapbluetooth.CharacteristicEventGeneratedParameters 生成規則に合致するものとし、次を実行します:

    1. params["context"] を navigableId に設定します。

    2. params["address"] を device.[[representedDevice]] の address に設定します。

    3. service を、simulated GATT servicecharacteristic を含むものとします。

    4. params["serviceUuid"] を serviceUUID に設定します。

    5. params["characteristicUuid"] を characteristicUUID に設定します。

    6. params["type"] を type に設定します。

    7. もし typewrite であれば、次を実行します:

      1. data を空リストとします。

      2. bytes 内の各 byte について:

        1. bytevaluedata に追加します。

      3. params["data"] を data に設定します。

  3. body を、mapbluetooth.CharacteristicEventGenerated 生成規則に合致するものとし、params フィールドを params に設定します。

  4. relatedNavigables を、navigable を含む set とします。

  5. set of sessions for which an event is enabled の各 session( "bluetooth.characteristicEventGenerated" と relatedNavigables が与えられたもの)について:

    1. イベントを送出し、sessionbody を用います。

12.2.4.4. bluetooth.descriptorEventGenerated イベント
bluetooth.DescriptorEventGenerated = (
   method: "bluetooth.descriptorEventGenerated",
   params: bluetooth.DescriptorEventGeneratedParameters
)

bluetooth.DescriptorEventGeneratedParameters = {
  context: text,
  address: text,
  serviceUuid: bluetooth.BluetoothUuid,
  characteristicUuid: bluetooth.BluetoothUuid,
  descriptorUuid: bluetooth.BluetoothUuid,
  type: "read" / "write",
  ? data: [ * uint ]
}

シミュレートされた descriptor イベントをトリガーする ために、navigable navigableBluetoothDevice devicesimulated GATT descriptor descriptorstring type、任意の byte sequence bytes が与えられたときは次のとおりです:

  1. navigableIdnavigablenavigable id とします。

  2. params を、mapbluetooth.DescriptorEventGeneratedParameters 生成規則に合致するものとし、次を実行します:

    1. params["context"] を navigableId に設定します。

    2. params["address"] を device.[[representedDevice]] の address に設定します。

    3. characteristic を、simulated GATT characteristicdescriptor を含むものとします。

    4. service を、simulated GATT servicecharacteristic を含むものとします。

    5. params["serviceUuid"] を serviceUUID に設定します。

    6. params["characteristicUuid"] を characteristicUUID に設定します。

    7. params["descriptorUuid"] を descriptorUUID に設定します。

    8. params["type"] を type に設定します。

    9. もし typewrite であれば、次を実行します:

      1. data を空リストとします。

      2. bytes 内の各 byte について:

        1. bytevaluedata に追加します。

      3. params["data"] を data に設定します。

  3. body を、mapbluetooth.DescriptorEventGenerated 生成規則に合致するものとし、params フィールドを params に設定します。

  4. relatedNavigables を、navigable を含む set とします。

  5. set of sessions for which an event is enabled の各 session( "bluetooth.descriptorEventGenerated" と relatedNavigables が与えられたもの)について:

    1. イベントを送出し、sessionbody を用います。

13. 用語と規約

この仕様は、いくつかの規約と他の仕様からの複数の用語を使用します。本節ではそれらを列挙し、その一次定義へのリンクを示します。

この仕様のアルゴリズムが本仕様または他の仕様で定義された名前を使用する場合、その名前は現在の実行環境でその名前に対して加えられた変更を無視し、初期値に解決されなければなりません。例えば、requestDevice() アルゴリズムが Array.prototype.map.call(filter.services, BluetoothUUID.getService) を呼び出すよう指示する場合、これは [ECMAScript] に定義された Array.prototype.map アルゴリズムを、その this 引数として filter.services を用い、 § 7.1 Standardized UUIDs に定義された BluetoothUUID.getService のアルゴリズムを callbackfn 引数として適用しなければなりません。これは、windowArrayArray.prototypeArray.prototype.mapFunctionFunction.prototypeBluetoothUUIDBluetoothUUID.getService、その他の オブジェクトに対して行われた変更に関わらず適用されます。

この仕様では、WebIDL の FrozenArray に類似した読み取り専用型を使用します。

[BLUETOOTH42]
  1. アーキテクチャと用語の概要
    1. 概要
      1. Bluetooth Low Energy の動作概要 (定義: advertising events)
    2. 通信トポロジと動作
      1. 運用手順とモード
        1. BR/EDR 手順
          1. Inquiry(探索)手順
            1. Extended Inquiry Response
  2. コアシステムパッケージ [BR/EDR コントローラー巻]
    1. エラーコード
      1. エラーコードの概要
        1. List of Error Codes
    2. ホストコントローラインターフェイス機能仕様
      1. HCI コマンドとイベント
        1. 情報パラメータ
          1. Read BD_ADDR Command
        2. ステータスパラメータ
          1. 読み取り RSSI コマンド
  3. コアシステムパッケージ [ホスト巻]
    1. サービス検出プロトコル(SDP)仕様
      1. 概要
        1. Searching for Services
          1. UUID (定義: UUID alias と、 UUID alias により the 128-bit UUID represented を計算するアルゴリズム)
    2. 一般アクセスプロファイル
      1. プロファイル概要
        1. プロファイルロール
          1. LE 物理トランスポート上でのロール
            1. Broadcaster ロール
            2. Observer ロール
            3. Peripheral ロール
            4. Central ロール
      2. ユーザーインターフェイスの側面
        1. Bluetooth パラメータの表現
          1. Bluetooth Device Name(ユーザーフレンドリー名)
      3. アイドルモード手順 — BR/EDR 物理トランスポート
        1. Device Discovery Procedure
        2. BR/EDR Bonding Procedure
      4. 運用モードと手順 — LE 物理トランスポート
        1. ブロードキャストモードと観測手順
          1. Observation Procedure
        2. 検出モードと手順
          1. General Discovery Procedure
          2. Name Discovery Procedure
        3. 接続モードと手順
        4. ボンディングモードと手順
          1. LE Bonding Procedure
      5. セキュリティの側面 — LE 物理トランスポート
        1. Privacy Feature
        2. ランダムデバイスアドレス
          1. Static Address
          2. Private address
            1. Resolvable Private Address Resolution Procedure
      6. Advertising Data とスキャン応答データ形式 (定義: AD structure)
      7. Bluetooth デバイス要件
        1. Bluetooth デバイスアドレス(定義: BD_ADDR
          1. Bluetooth デバイスアドレスタイプ
            1. Public Bluetooth Address
      8. 定義 (定義: bond)
    3. Attribute Protocol (ATT)
      1. プロトコル要件
        1. 基本概念
          1. Attribute Type
          2. Attribute Handle
          3. Long Attribute Values
        2. Attribute Protocol Pdus
          1. エラー処理
            1. Error Response
    4. Generic Attribute Profile (GATT)
      1. プロファイル概要
        1. 構成とロール (定義: GATT Client および GATT Server)
        2. Profile FundamentalsATT Bearer を定義
        3. Attribute Protocol
          1. Attribute Caching
        4. GATT Profile Hierarchy
          1. Service
          2. Included Services
          3. Characteristic
      2. Service Interoperability Requirements
        1. Service Definition
        2. Characteristic 定義
          1. Characteristic 宣言
            1. Characteristic Properties
          2. Characteristic Descriptor 宣言
            1. Characteristic Extended Properties
            2. Client Characteristic Configuration
      3. GATT 機能要件 — GATT procedures を定義。
        1. サーバー構成
          1. Exchange MTU
        2. Primary Service Discovery
          1. すべてのプライマリサービスを検出
          2. Discover Primary Service by Service UUID
        3. Relationship Discovery
          1. 含まれるサービスの検出
        4. Characteristic Discovery
          1. サービスのすべての Characteristic を検出
          2. Discover Characteristics by UUID
        5. Characteristic Descriptor Discovery
          1. Discover All Characteristic Descriptors
        6. Characteristic Value Read
        7. Characteristic Value Write
          1. Write Without Response
          2. Write Characteristic Value
        8. Characteristic Value Notification
        9. Characteristic Value Indications
        10. Characteristic Descriptors
          1. Read Characteristic Descriptors
          2. Read Long Characteristic Descriptors
          3. Write Characteristic Descriptors
          4. Write Long Characteristic Descriptors
        11. Procedure Timeouts
      4. GAP 相互運用要件
        1. BR/EDR GAP 相互運用要件
          1. 接続確立
        2. LE GAP 相互運用要件
          1. 接続確立
      5. 定義済み Generic Attribute Profile サービス
        1. Service Changed
    5. セキュリティマネージャ仕様
      1. セキュリティマネージャ
        1. Bluetooth Low Energy におけるセキュリティ
          1. Definition of Keys and Values、 定義: Identity Resolving Key (IRK)
  4. コアシステムパッケージ [Low Energy コントローラー巻]
    1. リンクレイヤ仕様
      1. 概要
        1. デバイスアドレス
          1. Public Device Address
          2. ランダムデバイスアドレス
            1. Static Device Address
      2. 空中インターフェイスプロトコル
        1. 非接続状態
          1. スキャン状態
            1. Passive Scanning
[BLUETOOTH-SUPPLEMENT6]
  1. データタイプ仕様
    1. データタイプの定義とフォーマット
      1. Service UUID Data Type
      2. Local Name Data Type
      3. Flags Data Type (定義: Discoverable Mode フラグ)
      4. Manufacturer Specific Data
      5. TX Power Level
      6. Service Data
      7. Appearance

適合性

文書の規約

適合要件は、記述的な断言と RFC 2119 の用語の組み合わせで表現されます。 この文書の規範的な部分における “MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”、“OPTIONAL” というキーワードは、RFC 2119 に記述されたとおりに解釈されます。 ただし、可読性のために、 本仕様ではこれらの語はすべて大文字では現れません。

明示的に非規範と記された節、例、注記を除き、 本仕様のすべての本文は規範的です。[RFC2119]

本仕様の例は “for example” という語で導入されるか、 または規範的な本文から class="example" を用いて以下のように区別されます:

これは情報的な例です。

情報的な注記は “Note” という語で始まり、 規範的な本文から class="note" を用いて以下のように区別されます:

Note、これは情報的な注記です。

索引

この仕様で定義される用語

参照によって定義される用語

参考文献

規範参照

[BLUETOOTH-ASSIGNED]
Assigned Numbers. Living Standard. URL: https://www.bluetooth.com/specifications/assigned-numbers/
[BLUETOOTH-SUPPLEMENT6]
Supplement to the Bluetooth Core Specification Version 6. 14 July 2015. URL: https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=302735
[BLUETOOTH42]
BLUETOOTH SPECIFICATION Version 4.2. 2 December 2014. URL: https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMAScript]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[ENCODING]
Anne van Kesteren. Encoding Standard. Living Standard. URL: https://encoding.spec.whatwg.org/
[FINGERPRINTING-GUIDANCE]
Nick Doty; Tom Ritter. Mitigating Browser Fingerprinting in Web Specifications. URL: https://w3c.github.io/fingerprinting-guidance/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PAGE-VISIBILITY]
Jatinder Mann; Arvind Jain. Page Visibility (Second Edition). 29 October 2013. REC. URL: https://www.w3.org/TR/page-visibility/
[PERMISSIONS]
Marcos Caceres; Mike Taylor. Permissions. URL: https://w3c.github.io/permissions/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. URL: https://w3c.github.io/webappsec-permissions-policy/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[RFC4122]
P. Leach; M. Mealling; R. Salz. A Universally Unique IDentifier (UUID) URN Namespace. July 2005. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc4122
[RFC8610]
H. Birkholz; C. Vigano; C. Bormann. Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures. June 2019. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc8610
[WEBDRIVER-BIDI]
James Graham; Alex Rudenko; Maksim Sadym. WebDriver BiDi. URL: https://w3c.github.io/webdriver-bidi/
[WEBDRIVER1]
Simon Stewart; David Burns. WebDriver. URL: https://w3c.github.io/webdriver/
[WEBDRIVER2]
Simon Stewart; David Burns. WebDriver. URL: https://w3c.github.io/webdriver/
[WEBHID]
WebHID API. Draft Community Group Report. URL: https://wicg.github.io/webhid/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

参考情報

[CSP3]
Mike West; Antonio Sartori. Content Security Policy Level 3. URL: https://w3c.github.io/webappsec-csp/

IDL 索引

dictionary BluetoothDataFilterInit {
  BufferSource dataPrefix;
  BufferSource mask;
};

dictionary BluetoothManufacturerDataFilterInit : BluetoothDataFilterInit {
  required [EnforceRange] unsigned short companyIdentifier;
};

dictionary BluetoothServiceDataFilterInit : BluetoothDataFilterInit {
  required BluetoothServiceUUID service;
};

dictionary BluetoothLEScanFilterInit {
  sequence<BluetoothServiceUUID> services;
  DOMString name;
  DOMString namePrefix;
  sequence<BluetoothManufacturerDataFilterInit> manufacturerData;
  sequence<BluetoothServiceDataFilterInit> serviceData;
};

dictionary RequestDeviceOptions {
  sequence<BluetoothLEScanFilterInit> filters;
  sequence<BluetoothLEScanFilterInit> exclusionFilters;
  sequence<BluetoothServiceUUID> optionalServices = [];
  sequence<unsigned short> optionalManufacturerData = [];
  boolean acceptAllDevices = false;
};

[Exposed=Window, SecureContext]
interface Bluetooth : EventTarget {
  Promise<boolean> getAvailability();
  attribute EventHandler onavailabilitychanged;
  [SameObject]
  readonly attribute BluetoothDevice? referringDevice;
  Promise<sequence<BluetoothDevice>> getDevices();
  Promise<BluetoothDevice> requestDevice(optional RequestDeviceOptions options = {});
};

Bluetooth includes BluetoothDeviceEventHandlers;
Bluetooth includes CharacteristicEventHandlers;
Bluetooth includes ServiceEventHandlers;

dictionary BluetoothPermissionDescriptor : PermissionDescriptor {
  DOMString deviceId;
  // These match RequestDeviceOptions.
  sequence<BluetoothLEScanFilterInit> filters;
  sequence<BluetoothServiceUUID> optionalServices = [];
  sequence<unsigned short> optionalManufacturerData = [];
  boolean acceptAllDevices = false;
};

dictionary AllowedBluetoothDevice {
  required DOMString deviceId;
  required boolean mayUseGATT;
  // An allowedServices of "all" means all services are allowed.
  required (DOMString or sequence<UUID>) allowedServices;
  required sequence<unsigned short> allowedManufacturerData;
};
dictionary BluetoothPermissionStorage {
  required sequence<AllowedBluetoothDevice> allowedDevices;
};

[Exposed=Window]
interface BluetoothPermissionResult : PermissionStatus {
  attribute FrozenArray<BluetoothDevice> devices;
};

[
  Exposed=Window,
  SecureContext
]
interface ValueEvent : Event {
  constructor(DOMString type, optional ValueEventInit initDict = {});
  readonly attribute any value;
};

dictionary ValueEventInit : EventInit {
  any value = null;
};

[Exposed=Window, SecureContext]
interface BluetoothDevice : EventTarget {
  readonly attribute DOMString id;
  readonly attribute DOMString? name;
  readonly attribute BluetoothRemoteGATTServer? gatt;

  Promise<undefined> forget();
  Promise<undefined> watchAdvertisements(
      optional WatchAdvertisementsOptions options = {});
  readonly attribute boolean watchingAdvertisements;
};
BluetoothDevice includes BluetoothDeviceEventHandlers;
BluetoothDevice includes CharacteristicEventHandlers;
BluetoothDevice includes ServiceEventHandlers;

dictionary WatchAdvertisementsOptions {
  AbortSignal signal;
};

[Exposed=Window, SecureContext]
interface BluetoothManufacturerDataMap {
  readonly maplike<unsigned short, DataView>;
};
[Exposed=Window, SecureContext]
interface BluetoothServiceDataMap {
  readonly maplike<UUID, DataView>;
};
[
  Exposed=Window,
  SecureContext
]
interface BluetoothAdvertisingEvent : Event {
  constructor(DOMString type, BluetoothAdvertisingEventInit init);
  [SameObject]
  readonly attribute BluetoothDevice device;
  readonly attribute FrozenArray<UUID> uuids;
  readonly attribute DOMString? name;
  readonly attribute unsigned short? appearance;
  readonly attribute byte? txPower;
  readonly attribute byte? rssi;
  [SameObject]
  readonly attribute BluetoothManufacturerDataMap manufacturerData;
  [SameObject]
  readonly attribute BluetoothServiceDataMap serviceData;
};
dictionary BluetoothAdvertisingEventInit : EventInit {
  required BluetoothDevice device;
  sequence<(DOMString or unsigned long)> uuids;
  DOMString name;
  unsigned short appearance;
  byte txPower;
  byte rssi;
  BluetoothManufacturerDataMap manufacturerData;
  BluetoothServiceDataMap serviceData;
};

[Exposed=Window, SecureContext]
interface BluetoothRemoteGATTServer {
  [SameObject]
  readonly attribute BluetoothDevice device;
  readonly attribute boolean connected;
  Promise<BluetoothRemoteGATTServer> connect();
  undefined disconnect();
  Promise<BluetoothRemoteGATTService> getPrimaryService(BluetoothServiceUUID service);
  Promise<sequence<BluetoothRemoteGATTService>>
    getPrimaryServices(optional BluetoothServiceUUID service);
};

[Exposed=Window, SecureContext]
interface BluetoothRemoteGATTService : EventTarget {
  [SameObject]
  readonly attribute BluetoothDevice device;
  readonly attribute UUID uuid;
  readonly attribute boolean isPrimary;
  Promise<BluetoothRemoteGATTCharacteristic>
    getCharacteristic(BluetoothCharacteristicUUID characteristic);
  Promise<sequence<BluetoothRemoteGATTCharacteristic>>
    getCharacteristics(optional BluetoothCharacteristicUUID characteristic);
  Promise<BluetoothRemoteGATTService>
    getIncludedService(BluetoothServiceUUID service);
  Promise<sequence<BluetoothRemoteGATTService>>
    getIncludedServices(optional BluetoothServiceUUID service);
};
BluetoothRemoteGATTService includes CharacteristicEventHandlers;
BluetoothRemoteGATTService includes ServiceEventHandlers;

[Exposed=Window, SecureContext]
interface BluetoothRemoteGATTCharacteristic : EventTarget {
  [SameObject]
  readonly attribute BluetoothRemoteGATTService service;
  readonly attribute UUID uuid;
  readonly attribute BluetoothCharacteristicProperties properties;
  readonly attribute DataView? value;
  Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUID descriptor);
  Promise<sequence<BluetoothRemoteGATTDescriptor>>
    getDescriptors(optional BluetoothDescriptorUUID descriptor);
  Promise<DataView> readValue();
  Promise<undefined> writeValue(BufferSource value);
  Promise<undefined> writeValueWithResponse(BufferSource value);
  Promise<undefined> writeValueWithoutResponse(BufferSource value);
  Promise<BluetoothRemoteGATTCharacteristic> startNotifications();
  Promise<BluetoothRemoteGATTCharacteristic> stopNotifications();
};
BluetoothRemoteGATTCharacteristic includes CharacteristicEventHandlers;

[Exposed=Window, SecureContext]
interface BluetoothCharacteristicProperties {
  readonly attribute boolean broadcast;
  readonly attribute boolean read;
  readonly attribute boolean writeWithoutResponse;
  readonly attribute boolean write;
  readonly attribute boolean notify;
  readonly attribute boolean indicate;
  readonly attribute boolean authenticatedSignedWrites;
  readonly attribute boolean reliableWrite;
  readonly attribute boolean writableAuxiliaries;
};

[Exposed=Window, SecureContext]
interface BluetoothRemoteGATTDescriptor {
  [SameObject]
  readonly attribute BluetoothRemoteGATTCharacteristic characteristic;
  readonly attribute UUID uuid;
  readonly attribute DataView? value;
  Promise<DataView> readValue();
  Promise<undefined> writeValue(BufferSource value);
};

[SecureContext]
interface mixin CharacteristicEventHandlers {
  attribute EventHandler oncharacteristicvaluechanged;
};

[SecureContext]
interface mixin BluetoothDeviceEventHandlers {
  attribute EventHandler onadvertisementreceived;
  attribute EventHandler ongattserverdisconnected;
};

[SecureContext]
interface mixin ServiceEventHandlers {
  attribute EventHandler onserviceadded;
  attribute EventHandler onservicechanged;
  attribute EventHandler onserviceremoved;
};

typedef DOMString UUID;

[Exposed=Window]
interface BluetoothUUID {
  static UUID getService((DOMString or unsigned long) name);
  static UUID getCharacteristic((DOMString or unsigned long) name);
  static UUID getDescriptor((DOMString or unsigned long) name);

  static UUID canonicalUUID([EnforceRange] unsigned long alias);
};

typedef (DOMString or unsigned long) BluetoothServiceUUID;
typedef (DOMString or unsigned long) BluetoothCharacteristicUUID;
typedef (DOMString or unsigned long) BluetoothDescriptorUUID;

[SecureContext]
partial interface Navigator {
  [SameObject]
  readonly attribute Bluetooth bluetooth;
};

CDDL 索引

課題索引

§ 3 Privacy considerations の節を参照。 [Issue #575]
実際には、プロンプトが開いている間にデバイス一覧は動的に更新される。仕様テキストは現時点でそれを反映していないが、このイベントは同じ promptId と新しいデバイス一覧で複数回発行される可能性がある。参照: https://github.com/WebBluetoothCG/web-bluetooth/issues/621.
TODO: 所要時間を確定する。
非同期デバイス検出をサポートする。
passive scanningPrivacy Feature はいずれも一意で不変なデバイス ID の漏洩を回避する。UA にどちらかの使用を要求すべきだが、どちらも OS の API では公開されていないように見える。Bluetooth もまた、passive scanning の使用を困難にしている。というのも、Central デバイスが Observation Procedure をサポートすることを要求していないためである。
BR/EDR のあらゆる問い合わせ/検出は、一意で不変なデバイスアドレスが漏洩するように見える。
サイトが、関心のあるデバイスが到達範囲に入ったときにイベントを受け取れるよう登録する手段が必要である。
そのような汎用イベント型はここではなく [HTML] または [DOM] に属する。
実装によってはこの NetworkError を回避できるかもしれないが、現時点ではサイトはこの API の使用を直列化し、かつ/または 失敗した操作を再試行できる手段をユーザーに提供する必要がある。 [Issue #188]
実装によってはこの NetworkError を回避できるかもしれないが、現時点ではサイトはこの API の使用を直列化し、かつ/または ユーザーに失敗した操作を再試行する手段を提供する必要がある。 [Issue #188]
実装によってはこの NetworkError を回避できるかもしれないが、現時点ではサイトはこの API の使用を直列化し、かつ/または 失敗した操作を再試行できる手段をユーザーに提供する必要がある。 [Issue #188]
このメソッドは後方互換性のためだけのもの。新しい実装ではこのメソッドを実装すべきではない。 [Issue #238]
実装によってはこの NetworkError を回避できるかもしれないが、 現時点ではサイトはこの API の使用を直列化し、かつ/または ユーザーに失敗した操作を再試行する手段を提供する必要がある。 [Issue #188]
Characteristic Extended Properties は、拡張プロパティが特定の Characteristic に対して不変かどうかが明確でない。 もし不変であるなら、UA はそれらをキャッシュできるようにすべきである。
実装によってはこの NetworkError を回避できるかもしれないが、現時点ではサイトはこの API の使用を直列化し、かつ/または 失敗した操作を再試行できる手段をユーザーに提供する必要がある。 [Issue #188]
実装によってはこの NetworkError を回避できるかもしれないが、現時点ではサイトはこの API の使用を直列化し、かつ/または 失敗した操作を再試行できる手段をユーザーに提供する必要がある。 [Issue #188]
CDDL スニペットは、CDDL スニペットを独立してプログラム的に処理できるように 「browsingContext.BrowsingContext」ではなく「text」型を使用している。現在のところ、他のモジュールは 参照できない。
別のアルゴリズムから変数にデータを挿入することは十分に定義されていない。実装に合わせるため、scan for devices アルゴリズムは 非同期デバイス検出を定義する必要がある。
MDN

Bluetooth/availabilitychanged_event

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for AndroidNoneAndroid WebView?Samsung Internet?Opera Mobile?
MDN

Bluetooth/availabilitychanged_event

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for AndroidNoneAndroid WebView?Samsung Internet?Opera Mobile?
MDN

Bluetooth/getAvailability

In only one current engine.

FirefoxNoneSafariNoneChrome78+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

Bluetooth/getDevices

In only one current engine.

FirefoxNoneSafariNoneChrome🔰 85+
Opera?Edge🔰 85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Bluetooth/requestDevice

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

Bluetooth

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/authenticatedSignedWrites

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/broadcast

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/indicate

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/notify

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/read

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/reliableWrite

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/writableAuxiliaries

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/write

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties/writeWithoutResponse

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothCharacteristicProperties

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothDevice/gatt

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothDevice/id

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothDevice/name

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothDevice

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/getDescriptor

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/getDescriptors

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/properties

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/readValue

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/service

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/startNotifications

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/stopNotifications

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/uuid

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/value

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/writeValueWithoutResponse

In only one current engine.

FirefoxNoneSafariNoneChrome85+
Opera?Edge85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic/writeValueWithResponse

In only one current engine.

FirefoxNoneSafariNoneChrome85+
Opera?Edge85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTCharacteristic

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTDescriptor/characteristic

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTDescriptor/readValue

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTDescriptor/uuid

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTDescriptor/value

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTDescriptor/writeValue

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTDescriptor

In only one current engine.

FirefoxNoneSafariNoneChrome57+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android57+Android WebViewNoneSamsung Internet?Opera Mobile44+
MDN

BluetoothRemoteGATTServer/connect

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer/connected

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer/device

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer/disconnect

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer/getPrimaryService

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer/getPrimaryServices

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTServer

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService/device

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService/getCharacteristic

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService/getCharacteristics

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService/isPrimary

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService/uuid

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothRemoteGATTService

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothUUID/canonicalUUID_static

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothUUID/getCharacteristic_static

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothUUID/getDescriptor_static

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothUUID/getService_static

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebViewNoneSamsung Internet?Opera Mobile?
MDN

BluetoothUUID

In only one current engine.

FirefoxNoneSafariNoneChrome56+
Opera?Edge79+
Edge (Legacy)NoneIENone
Firefox for Android?iOS Safari?Chrome for Android56+Android WebViewNoneSamsung Internet?Opera Mobile?