こんにちは。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
通信相手となるデバイス
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つの動作が可能なデバイスです。
この辺りの優しめの解説は
などがあります。BLEの仕様がすべて分からなくても、Web Bluetooth APIは詳しい通信に関する処理はかなり隠してくれているので
- Web Bluetooth APIはBluetooth通信できるデバイスのうち、一部のデバイスとしか通信できない
- Web Bluetooth APIは周辺にあるデバイスから接続したいPeripheralデバイスを選択する必要がある
- Web Bluetooth APIはデバイスとの接続後、GATTの仕様に則った双方向のデータ通信を操作する必要がある
の3つがイメージできれば大丈夫です。
デバイス接続後のGATTの仕様については詳細や解説記事は山ほどあるのでここではドキュメントの紹介だけにとどめます。
- 【サルでもわかる BLE 入門】(2) アドバタイズと GATT 通信 - 株式会社ムセンコネクト
- 【連載】Bluetooth LE (1) Bluetooth Low Energy の基礎 (フェンリル | デベロッパーズブログ)
- 備忘録 : BLE - GATT 仕様
- GATT とは | Bluetooth® v4 の上位プロトコルとプロファイル | TechWeb
Web Bluetooth API でのPeripheralデバイス操作
GATTではデバイスで定義された値を読み込んだり、書き換えたりすることでデータの受け渡しを行います。 デバイスはデータの受け渡し用の値を複数持つことができ、どの値を操作するかはサービスとキャラクタリスティックの2つの値で指定します。
Web Bluetooth APIを使ったデバイスへのデータの受け渡しには
の5ステップが必要です。
Web Bluetooth SamplesにはWeb Bluetooth APIのさまざまなデモが載っているため、サンプルの1つWeb Bluetooth / Battery Level (Async Await) SampleのJavaScriptを例に、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で何か作ってみたいと思った時にオススメの資料です。
-
- JavaScript を介した Bluetooth デバイスとの通信
- Web Bluetooth APIをGoogle Chromeから使う場合のフォローが丁寧です
- ドキュメントやデモの紹介も豊富です
- Web Bluetooth Draft Community Group Report
- Web Bluetooth API - Web APIs | MDN
- 使える関数とオブジェクトの詳細が載っています
- 実装時に詳細が気になれば見てみると良いです
- JavaScript を介した Bluetooth デバイスとの通信
Bluetooth Low Energy に関するもの
デバッグツール
- chrome://bluetooth-internals/
- Google Chromeを使っている人限定になりますが、ブラウザでPeripheral端末との接続ができ、キャラクタリスティックの簡易な操作もできます。ムダなソフトを入れなくても気軽に試せるのでぜひ
- nRF Connect
- iOS アプリ
- Android アプリ
- スマホアプリでBLEデバイスのスキャンやキャラクタリスティックの簡易な操作ができます
- chrome://bluetooth-internals/
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点が気になりました。
ユーザー操作がないとデバイスの選択ができない問題は、プライバシー保護やセキュリティーの観点からある程度仕方がないです。 しかし、操作する分だけ1手間2手間増えてしまい、ユーザーの体験としてはアプリなどに比べ、利便性が低くなります。
またPhotosynth社内のようにAkerunがたくさんいる場所ではフィルターを相当うまくかけないと該当端末がどれだかよくわからなくなってしまう問題があります。
ユーザーに混乱なく使ってもらうためには、デバイスに固有の名前またはサービス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