スマートフォンにはさまざまな無線技術が搭載されています。たとえばWiFiであったり、NFCなどは有名です。そして、Bluetoothもデスクトップ、スマートフォンを問わず利用されています。キーボードやマウス、イヤフォン、さらにスマートウォッチなどもBluetoothで通信しています。

今回はそんなBluetoothをブラウザから扱えるAPI、Web Bluetooth APIを紹介します。Webブラウザの可能性を一気に引き上げてくれることでしょう。

1. はじめに

Web Bluetooth APIの概要

Web Bluetooth APIはブラウザからBluetoothを扱えるAPIです。特にBluetoothを扱う際の面倒なネゴシエーションはブラウザが行ってくれるので、JavaScriptのコーディング量は大幅に減らせるのが特徴です。

2. Bluetoothとは?

Bluetoothの基本的な概念

Bluetoothは、近くの機器同士が無線で通信するための規格です。この技術は主に短距離での通信に使用され、バージョン5が現在広く使われています。新しいバージョンが出るたびに、電力消費が少なくなるよう改良されています。そのため、Bluetoothはイヤフォンやキーボードのような、ずっと接続しておく必要があるデバイスでよく使われます。

Bluetoothは、デバイス同士が直接データを送り合える「プロトコル」(通信のルールや手順)です。このため、写真や音楽ファイルのようなデータの送受信も可能です。しかし、Bluetoothの通信速度はそれほど高くないため、大きなファイルを送るには適していません。

Bluetoothの歴史と進化

BluetoothはBLEを実現したバージョン4で、規格の互換性が失われています。現在はBLEが利用できるものが基本なので、過去のBluetoothデバイスはほぼ出回っていないでしょう。

また、バージョンを重ねるごとに対応距離も増えています。元々数メートルまでが基本でしたが、現在は条件によっては1km程度まで利用できます。これはスタジアムなど、屋外で遮蔽物がない環境を想定し、業務用途になるようです。

一般的にはマウスやキーボード、スマートウォッチ、イヤフォンなどでBluetoothが利用されています。もちろんスマートフォン自身にもBluetoothが入っているので、デスクトップや別なスマートフォンとのデータ送受信にも利用できます。

3. Web Bluetooth APIの基本

仕様の概要

Web Bluetooth APIの便利な点を簡単に説明すると、このAPIを使用することで、Bluetoothデバイスとの間で行われる通常の接続確立プロセス(ネゴシエーション)などの複雑な操作を気にする必要がなくなります。

具体的には、Bluetoothデバイスの一覧を取得する際に、ユーザーが直接デバイスとの通信を行う代わりに、デバイスの検出や接続のプロセスに関しては、ブラウザが提供するネイティブ機能が背後で動作します。

これにより、Web Bluetooth APIを介してデバイスにアクセスする際、開発者はデバイスとの接続プロセスを簡素化し、より直接的にデバイスの制御やデータの交換に集中できるようになります。

document.querySelector('button').addEventListener('click', async () => {
  try {
    const device = await navigator.bluetooth.requestDevice({
      acceptAllDevices: true
    });
    console.log('選択されたデバイス:', device.name);
  } catch(error) {
    console.log('デバイスの選択に失敗しました:', error);
  }
});

このコードは、WebページからユーザーがBluetoothデバイスを選択し、そのデバイスに接続する許可を与えるプロセスを示しています。

具体的には、navigator.bluetooth.requestDevice関数を呼び出して、ユーザーにデバイス選択のダイアログを表示します。ここでacceptAllDevices: trueの設定により、すべての利用可能なBluetoothデバイスがダイアログに表示され、ユーザーがどれか一つを選択できるようになります。

ユーザーがデバイスを選択し、接続を許可すると、そのデバイスの情報がdevice変数に格納されます。この情報には、デバイス名やIDなどが含まれますが、大切な点は、JavaScriptコードが自動的に周囲のデバイス情報を取得するわけではないということです。

つまり、ユーザーが明示的に選択しない限り、そのデバイスの情報を取得することはできません。これはプライバシーを保護するための措置であり、不正なスクリプトがユーザーの知らない間にデバイス情報を収集することを防ぎます。

ビーコンの利用

Bluetoothビーコン技術を利用する際、requestLEScanという機能を使って周囲のビーコンデバイスを探します。この方法では、ビーコンから発信されるBluetoothの電波を検出し、デバイスの識別情報(IDなど)を受け取ることができますが、デバイスとの間で実際に接続を行うわけではありません。つまり、ビーコンが近くにあることを知ることができるものの、それ以上の情報や操作は行わないということです。

このrequestLEScan機能をWebアプリケーションで使用するためには、Chromeブラウザで特定の設定を変更する必要があります。具体的には、「Experimental Web Platform features」という実験的な機能を有効にすることで、requestLEScanを含むWeb Bluetooth APIの一部の実験的な機能を試すことが可能になります。この設定を変更することで、開発者はビーコンを使った様々なアプリケーションやサービスをWeb上で実装し、テストすることができます。

ChromeのExperimenta Web Platform featuresの設定

  1. Chromeブラウザのアドレスバーにchrome://flagsと入力してアクセスします。
  2. 「Experimental Web Platform features」を検索し、有効に設定します。
  3. ブラウザを再起動した後、WebアプリケーションからrequestLEScanメソッドを使用してBLEビーコンを検出できるようになります。
const scanner = await navigator.bluetooth.requestLEScan({
    acceptAllAdvertisements: true,
    keepRepeatedDevices: true,
});
navigator.bluetooth.addEventListener("advertisementreceived", ({ device }) => {
    // 見つかったビーコンデバイス
    console.log(device);
});

対応ブラウザとデバイス

現在、Web Bluetooth APIが使えるブラウザはChromium系に限られます。Safari、FirefoxともにWeb Bluetooth APIの実装は行われていません。特にAppleはプライバシー保護を理由に実装を拒否しており、今後も実装される可能性は低そうです。

4. Web Bluetooth APIのセットアップ

必要な条件

Web Bluetooth APIを使用するには、いくつかの重要な制限があります。まず、このAPIはセキュアな接続を提供するHTTPSプロトコルを使用しているウェブサイトでのみ動作します。これは、ユーザーのデータ保護とセキュリティを強化するための措置です。

次に、Web Bluetooth APIはService Workerでは使用できません。Service Workerはバックグラウンドでスクリプトを実行するWeb APIの一つですが、Web Bluetoothの機能はメインスレッド、つまり直接ウェブページとやり取りする部分でのみ使用できます。これは、Bluetoothデバイスとの通信がユーザーの直接的な操作や監視下で行われるべきであるという考えに基づいています。

Web Bluetooth APIを利用する際、特定のデバイスへのアクセスを求める許可ダイアログは表示されません。しかし、ユーザーがデバイスを選択するための付近にあるデバイス一覧は、ブラウザのネイティブ機能によって表示されます。この一覧表示はユーザーに対して透明で安全な方法でデバイスを選択させるためのものです。

さらに、ユーザーがWeb Bluetooth APIを利用するためには、そのデバイスのBluetooth機能が有効になっている必要があります。Webページから直接Bluetoothを有効にすることはできません。これは、ユーザーのプライバシーとセキュリティを保護するための措置であり、ユーザー自身がデバイスの設定を管理する必要があります。

実装例

以下はBlueoothを使ってデバイス情報を取得するコードです。まずデバイスを探します。フィルターを指定することで、デバイス情報サービスを提供しているものだけに絞り込めます。

const device = await navigator.bluetooth.requestDevice({
    filters: [{ services: ["device_information"] }]
});

次に、そのデバイスに接続します。

const server = await device.gatt.connect();

そして提供するサービスの中で、今回の目的にあったデバイス情報サービスに繋ぎます。

const infoService = await server.getPrimaryService("device_information");

サービスに接続できたら、値を取得します。

const characteristics = await infoService.getCharacteristics();
const ary = [];
for (const characteristic of characteristics) {
    const value = await characteristic.readValue();
    ary.push(new TextDecoder().decode(value));
}
console.log(ary);

例として、値は以下のようになります。

["DEVICE_ABCDE", "0.0.1", "ASIAL"]

値が変化した際に通知を受け取る際には、以下のようになります。

characteristic.addEventListener('characteristicvaluechanged', event => {
    // 新しい値
    console.log(event.target.value);
});

// 通知開始
characteristic.characteristic.startNotifications();

// 通知停止
characteristic.characteristic.stopNotifications();

デバイスの接続を解除する場合には disconnect を使います。

await device.gatt.disconnect();

全体のコード

<html>
<head>
  <script>
    // Bluetoothデバイスに接続する非同期関数
    async function connectBluetooth() {
      try {
        // ユーザーにデバイスを選択させ、選択されたデバイスを取得
        const device = await navigator.bluetooth.requestDevice({
            filters: [{ services: ["device_information"] }]
        });

        console.log(device);
        const server = await device.gatt.connect();

        // 選択されたデバイスに接続
        const infoService = await server.getPrimaryService("device_information");

        // デバイス情報サービスに接続
        const characteristics = await infoService.getCharacteristics();

        // サービスの特性を取得
        const ary = [];
        // 特性の値を読み取り、デコードして配列に格納
        for (const characteristic of characteristics) {
          const value = await characteristic.readValue();
          ary.push(new TextDecoder().decode(value));

          // 特性値が変更されたときのイベントリスナーを追加
          characteristic.addEventListener("characteristicvaluechanged", event => {
            console.log(new TextDecoder().decode(event.target.value));
          });

          // 通知を開始
          await characteristic.startNotifications();
        }
        // 読み取った特性の値をコンソールに表示
        console.log(ary);
      } catch (error) {
        // エラーが発生した場合、コンソールにエラーを表示
        console.error(error);
      }
    }
  </script>
</head>

<body>
  <button onclick="connectBluetooth()">Connect Bluetooth</button>
</body>

</html>

まとめ

Web Bluetooth APIを使用すると、Bluetooth Low Energy(BLE)に対応しているデバイスとWebアプリケーションが直接通信できるようになります。これにより、WebアプリからBLEデバイスの情報を読み取ったり、デバイスに情報を送信(書き込み)したりすることが可能です。この技術は、Webアプリケーションに新たな機能を追加し、ユーザー体験を向上させる大きな可能性を秘めています。

ただし、このAPIをサポートしているブラウザは限られています。主に、Androidのブラウザやいくつかのデスクトップブラウザで利用可能です。そのため、すべてのユーザーがこの機能を利用できるわけではありませんが、対応しているブラウザを使用している場合は、この先進的な機能を活用して、よりインタラクティブなWebアプリケーションを開発することができます。

Web Bluetooth API - Web API | MDN