masato-ka's diary

日々思ったこととか、やったことの備忘録。

WebブラウザからBLE接続 WEB Bluetooth APIでNotificationを受け取る方法

この記事について

 この記事ではWebBluetooth API を使い、BLEデバイスからNotificationを受け取る方法を説明します。 対象とするデバイス2JCIE-BL01を利用します。デバイスから一定間隔で環境データを取得します。

WEB Bluetooth API

 WEB Bluetooth APIはWEBブラウザ上でBLEデバイスと通信を実現するJavaScriptAPIです。実装は各ブラウザごとに 違いますが2017年9月現在、各ブラウザともそんなに違いはないそうです。iOSについては今の所非対応のようですが、OSXでは問題なく使えそうです。

WEB Bluetooth APIの実装

WEB Bluetooth API を使いデバイスからNotificationを受ける実装は非常に簡単です。以下のコードで実現できます。onStartNotifyをブラウザのUIから呼び出すことで、実行することが可能です。今回ブラウザはChromeを利用しました。

var SensorServiceUUID = "0c4c3000-7700-46f4-aa96-d5e974e32a54" // WxBeacon2のSensorService UUID
var LatestDataUUID = "0c4c3001-7700-46f4-aa96-d5e974e32a54"// 最新データ取得のためのキャラクタリスティック UUID

function onStartNotify() {

    navigator.bluetooth.requestDevice(
        { acceptAllDevices:true,optionalServices:[SensorServiceUUID] } // (1)
     ) 
        .then(device => device.gatt.connect())//(2)
        .then(server => server.getPrimaryService(SensorServiceUUID))
        .then(service => service.getCharacteristic(LatestDataUUID))
        .then(characteristic =>{
            characteristic.addEventListener('characteristicvaluechanged', onRecvSensorData); //(3)
            characteristic.startNotifications();//(4)
        })

}

  • コード解説

(1) requestDeviceでBLEデバイスの検索を開始します。引数には探索するデバイスのフィルタを指定できます。今回はデバイスの指定は行わず、すべてのデバイスを受信します。また、デフォルトでは任意のサービスに接続できないため、予め接続できるサービスのUUIDをoptionalServicesで指定しておきます。

このメソッドは実行されると以下のようなダイアログがWeb ブラウザ上に表示されます。接続したいデバイスを選択し、ペア設定を押します。

f:id:masato-ka:20170924144104p:plain

(2) (1)で指定した デバイスに対して接続処理を行います。接続後、サービスの検索、キャラクタリスティックの検索と処理が 続いていきます。

(3) キャラクタリスティックを取得後、データがNotifyされた際に呼ばれるイベントリスナcharacteristicvaluechangedにコールバックを指定します。BLEデバイスからデータが通知されたらonRecvSensorDataメソッドが呼ばれるようになります。

(4) startNotifications()メソッドでデバイスからの通知が開始されます。

WxBeacon2のデータの処理を行うonRecvSensorDataは以下のようになっています。

function onRecvSensorData(event) {//(1)

    let characteristic = event.target; //(2)
    let value = characteristic.value; //(3)

    let temp = decodeValue(value.getUint8(2), value.getUint8(1), 0.01);
    console.log(temp);
    let humid = decodeValue(value.getUint8(4),value.getUint8(3), 0.01);
    console.log(humid);
    let lumix = decodeValue(value.getUint8(6), value.getUint8(5));
    console.log(lumix);
    let uv = decodeValue(value.getUint8(8), value.getUint8(7), 0.01);
    console.log(uv);
    let atom = decodeValue(value.getUint8(10), value.getUint8(9), 0.1);
    console.log(atom);
    let noise = decodeValue(value.getUint8(12), value.getUint8(11), 0.01);
    console.log(noise);
    let disco = decodeValue(value.getUint8(14), value.getUint8(13), 0.01);
    console.log(disco);
    let heat = decodeValue(value.getUint8(16), value.getUint8(15), 0.01);
    console.log(heat);
    let battery = decodeValue(value.getUint8(18), value.getUint8(17), 0.001);
    console.log(battery);

}

function decodeValue(msb, lsb, gain){
        return ((msb << 8) + lsb) * gain
}

  • コード解説

(1) コールバックはデバイスからの通知結果を受け取るeventと言う引数を1つとります。 (2) eventからキャラクタリスティックのオブジェクトを取得します。 (3) キャラクタリスティックのvalueの値を取得します。

最終的に取得されるキャラクタリスティックの値はDataViewオブジェクトになっています。getUint8メソッドを利用することで1バイトづつデータを取得することができます。 WxBeacon2の設定を変更していなければ5分間隔でデータが出力されます。今回はコンソールログに出力しているため、開発者ツールなどから確認します。

まとめ

WEB Bluetooth APIは非常に簡単にデバイスへの接続とキャラクタリスティックに対するデータの読み書きができます。今回はNotificationの受け取りのみですが、もちろん通常のreadやwriteも可能です。プラットフォームに依存なく簡単にBLEデバイスにアクセスできます。また、WEBブラウザから実行できるという性格上、検索できるデバイスやデバイスのサービスをホワイトリスト形式で縛る、実行にはかならずユーザアクションが必要など、セキュリティ面にも気を使った仕様になっていると思いました。実際にWEBアプリケーションと組み合わせた使い方をする場合はセキュリティ含めてアプリケーションの実装上工夫が必要そうな気はしますが。  また今回Beaconの情報を取得できないか挑戦しました。WEB Bluetooth API 自体の仕様上、可能なようですが、必要な実装はChrome含めて未対応のようです。この辺りについては今後に期待でしょうか。 WEB USB API 含めてWEB ブラウザから直接ハードウェアにアクセスできるのは未来を感じます。