Web Bluetooth API で Akerun とサポートサイトの連携を検討する

こんにちは。FWチームのnaritakuです。

本ブログの過去記事でも紹介されている Web Bluetooth API は皆様ご存知でしょうか?

Web Bluetooth APIはこの記事を見ているようなWebブラウザ上で、Bluetooth通信ができる優れものです。 (アプリでご覧になられている方はごめんなさい 🙏)

弊社のサポートサイトはWebページですので、Web Bluetooth APIとの相性は本来とてもいいはずです。 普段の業務はAkerunプロダクト同士のBluetooth通信を担当していますが、この記事では、Web Bluetooth APIを使い、弊社製品とWEBブラウザとの通信について色々試した過程を紹介します。

Web Bluetooth API を使った開発を完全に理解する

Web Bluetooth API が使えるブラウザ

Web Bluetooth APIは一部のブラウザのみ対応しています。 現在の実装状況は githubなどで確認できます。

caniuse.com によると、2022年7月現在、利用可能なブラウザから見た世界のシェアは7割越えのようです。1

Chromeは動く。iOSはほぼ動かない。

通信相手となるデバイス

Bluetooth APIと銘打っているものの、Web Bluetooth API - Web APIs | MDNの記載には

The Web Bluetooth API provides the ability to connect and interact with Bluetooth Low Energy peripherals.

とあります。実際に通信できるデバイスBluetooth Low Energyによる通信ができるデバイスのうち、Peripheralの役割を持つものに限られています。2

Peripheral のデバイスとは

Bluetooth Low Energy (以下BLE) による通信では、GAP (Generic Access Profile) 、 GATT (Generic Attribute Profile) と呼ばれるプロファイルが広く利用されています。 PeripheralはGAPで定義された役割 (role) の1つで、次の2つの動作が可能なデバイスです。

  • 不特定多数のデバイスに対して自身の存在や固有のデータを一方的に発信する
  • 存在に気づいた他のデバイスと接続処理を行った後、GATTの仕様に則った双方向のデータ通信を行う

この辺りの優しめの解説は

などがあります。BLEの仕様がすべて分からなくても、Web Bluetooth APIは詳しい通信に関する処理はかなり隠してくれているので

の3つがイメージできれば大丈夫です。

バイス接続後のGATTの仕様については詳細や解説記事は山ほどあるのでここではドキュメントの紹介だけにとどめます。

Web Bluetooth API でのPeripheralデバイス操作

GATTではデバイスで定義された値を読み込んだり、書き換えたりすることでデータの受け渡しを行います。 デバイスはデータの受け渡し用の値を複数持つことができ、どの値を操作するかはサービスとキャラクタリスティックの2つの値で指定します。

Web Bluetooth APIを使ったデバイスへのデータの受け渡しには

  1. BLEデバイスの検索
  2. BLEデバイスとの接続
  3. サービスの選択
  4. キャラクタリスティックの選択
  5. 値の操作

の5ステップが必要です。

Web Bluetooth SamplesにはWeb Bluetooth APIのさまざまなデモが載っているため、サンプルの1つWeb Bluetooth / Battery Level (Async Await) SampleJavaScriptを例に、GATTの仕様に則ったデータ通信を紹介します。

Sampleコードの上記5ステップに対応した箇所へコメントを追加しました。デモでは値の読み取り後にバッテリー残量のログを出力する実装になってますね。

function onButtonClick() {
    //1. BLE デバイスの検索
    log("Requesting Bluetooth Device...");
    navigator.bluetooth
        .requestDevice({ filters: [{ services: ["battery_service"] }] })
        .then((device) => {
            //2. BLEデバイスとの接続
            log("Connecting to GATT Server...");
            return device.gatt.connect();
        })
        .then((server) => {
            //3. サービスの選択
            log("Getting Battery Service...");
            return server.getPrimaryService("battery_service");
        })
        .then((service) => {
            //4. キャラクタリスティックの選択
            log("Getting Battery Level Characteristic...");
            return service.getCharacteristic("battery_level");
        })
        .then((characteristic) => {
            //5. 値の操作
            log("Reading Battery Level...");
            return characteristic.readValue();
        })
        .then((value) => {
            // フロントエンドでよしなに扱う
            let batteryLevel = value.getUint8(0);
            log("> Battery Level is " + batteryLevel + "%");
        })
        .catch((error) => {
            log("Argh! " + error);
        });
}

このサンプルコードは5. 値の操作 にて値の読み取りを行っていますが、値の書き込み操作であるWriteやPeripheralデバイスからの定期的な通知を期待するNotifyによる操作も可能です。 下記のデモを参照すると基本的な通信の流れがより理解できるかと思います。

その他のデモも、デバイスとの接続状態や電波強度の取得など実用的なものが多くあるのでぜひみてみてください。

参考になる素敵なドキュメント/ツールたち

自分でもWeb Bluetooth APIで何か作ってみたいと思った時にオススメの資料です。

Akerun と通信させてみる

やりたいこと

昨年6月にAkerun Pro はバージョンアップしました。 このバージョンアップにより、ハードウェアのアップデートだけでなく、サポートページも新旧機種に対応するための更新がなされています。

この新旧機種の判別についてですが、現在のサポートサイトではカードリーダーの見た目やAkerun IDと呼ばれる番号で誘導するようになっています。 サポートサイトスクリーンショット Akerun サポートサイト より

Akerun IDの確認方法はいくつかありますが、本体の印字で確認するためには、デバイスを扉から取り外さないと見えない、という課題がありました。 幸い、とあるAkerunデバイスとの通信はWeb Bluetooth APIでも行えるため、 Web Bluetooth APIを使った新旧機種の判別と電池交換方法の解説ページへ画面遷移するデモを作ってみます。3

ソースコード

const AKERUN_NAME_PREFIX= "akerun_";
const AKERUN_SERVICE_UUID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";

class Akerun {
    constructor() {
        this.ble_device = null;
    }

    async ble_disconnect() {
        if (this.ble_device != null && this.ble_device.gatt.connected) {
            await this.ble_device.gatt.disconnect();
            this.ble_device = null;
        }
    }

    async ble_connect() {
        await this.ble_disconnect();
        this.ble_device = await navigator.bluetooth.requestDevice({
            filters: [{ namePrefix: AKERUN_NAME_PREFIX }],
            optionalServices: [AKERUN_SERVICE_UUID],
        });
        return await this.ble_device.gatt.connect();
    }

    async ble_read_generation(server) {
        if (server===null || ! this.ble_device.gatt.connected) {
            throw new Error("device is not connected");
        }
        return await /* GATTによる読み取り処理 */
    }

};

async function search() {
    const ak = new Akerun();
    return ak
        .ble_connect()
        .then((server) => ak.ble_read_generation(server))
        .then((ak_generation) => open_support_page(ak_generation))
        .catch((error) => {
            console.error(error);
            ak.ble_disconnect();
        });
}

function open_support_page(generation) {
    const support_url =
        generation === 2
            ? "https://support.akerun.com/hc/ja/articles/4402400483725"
            : "https://support.akerun.com/hc/ja/articles/115007327088";
    window.onbeforeunload = function (event) {
        event = event || window.event;
        event.returnValue = "電池を交換したいAkerunは光りましたか?";
    };
    window.location.href = support_url;
}

動作

旧機種での動作

新機種での動作

どちらのバージョンも問題なく動作しました 🎉

今後の課題

Akerunとサポートサイトに限らず、一般的なBLEデバイスでWeb Bluetooth APIを使ったサービスを提供するためにはいくつかのハードルがあります。

API の融通の効かなさ

今回のデモでAPIを利用して、下記の2点が気になりました。

  • ユーザーがデバイスを選択しないとGATT通信ができない
  • ペア設定するデバイスの候補を絞るフィルターが、表示名の前方一致または完全一致、サービスのUUIDの完全一致の3点しかない

ユーザー操作がないとデバイスの選択ができない問題は、プライバシー保護やセキュリティーの観点からある程度仕方がないです。 しかし、操作する分だけ1手間2手間増えてしまい、ユーザーの体験としてはアプリなどに比べ、利便性が低くなります。

またPhotosynth社内のようにAkerunがたくさんいる場所ではフィルターを相当うまくかけないと該当端末がどれだかよくわからなくなってしまう問題があります。

社内でのscan結果

ユーザーに混乱なく使ってもらうためには、デバイスに固有の名前またはサービスUUIDを検索し、スキャン結果には特定のデバイスだけ表示されるユースケースが望ましそうです。

GATT サーバーのアクセス先がわかってしまうリスク

BLEデバイスは、周囲にある不特定多数のデバイスがお互いの通信内容を受信することができ、他のデバイスの真似をすることで簡単にそのデバイスのふりをすることも可能です。 Web Bluetooth APIを使うと、Webページのソースコードから、人間の読みやすい形でGATT通信の値の操作がわかってしまいます。 それは本来想定されていない悪意あるデバイスがPeripheralデバイスとの通信を試みることを容易にしています。 BLE通信のリスクを正しく評価し、事前にGATTサーバーのアクセス先などがバレても安全な設計にしておく必要があります。 具体的な方法は述べませんが、 Akerunの製品群ではもちろん対策をしています。安心ですね。

対応していないブラウザもある問題

実際にサポートサイトへ導入したとしても、ユーザーのブラウザやそのバージョンによって利用の可否が分かれてしまいます。 動かない機能が表示されてしまうとユーザーやサポートサイトのオペレーターに思わぬ混乱を与えてしまうため、この点も検討する必要があります。

Web Bluetooth APIで提供されているメソッドnavigator.bluetooth.getAvailability() を使うことで、 Web Bluetooth APIの機能が使える人にだけに機能を表示することもできそうです。

まとめ

Web Bluetooth APIとAkerun製品を組み合わせてできることを調査、検証しました。

運用中の製品で実際に動くものが作れたことは嬉しいニュースでした。 しかし、本機能をお客様へリリースするためには、APIと弊社製品の歩み寄りが必要そうです。 Web Bluetooth API対応ブラウザや、新機能の追加など、今後の発展にも注目したいです。


株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 hrmos.co

Akerun Proにご興味のある方はこちらから akerun.com


  1. 2022年6月のIEのサポート終了はWeb Bluetooth APIにとっての追い風になってますね。
  2. Peripheralの機能を一部制限した役割にあたるBroadcasterもいくつかの機能で利用できます。
  3. 弊社サポートサイトはChromeを推奨環境としているのでWeb Bluetooth APIはバッチリ使えます。相性が良かったです。