概要

Web Bluetooth APIを使用してADBLE01Pに接続し、キャラクタリスティックの読み出し(read)を使用して電源電圧の取得・表示、キャラクタリスティックの書き込み(write)を使用してLEDインジケータの有効・無効の設定を行うサンプルアプリのソースファイルの説明を行います。

HTMLファイルの確認方法

ブラウザから電源電圧測定・LEDインジケータ設定アプリのリンクをクリックしてアプリ画面を開きます。Chromeの場合、Ctrl+Uを押すとHTMLのソースファイルが表示されます。

Webアプリのソースファイルの構成と各部の説明

ファイルの中身は、大きく2つの構成に分かれます。1つはGUIの表示の部分で、残りはJavascriptで主にbluetoothの制御を行う部分です。以下、順に説明します。

GUI表示部分の説明

ソースファイルの以下の部分でGUIの表示を行っています。ボタン・テキストボックス・ラジオボタンを配置して、グループ分けして見やすくしています。Javascriptの関数と対応を取るために、各GUI要素にidを付けてあります。

<h2>ADBLE01P バッテリー電圧測定・LEDインジケータ設定</h2>
<button id="connect">接続</button>
<button id="disconnect" disabled>切断</button><br>
<fieldset id="bas_group">
  <legend>バッテリー電圧</legend>
  <textarea id="message"></textarea>[mV]
  <button id="read_voltage" disabled>読み出し</button><br>
</fieldset>
<fieldset id="led_group">
  <legend>LEDインジケータ設定</legend>
  <select id="led_status">
    <option value="0x00" selected>無効</option>
    <option value="0x01">有効</option>
  </select>
  <button id="set_led" disabled>設定</button><br>
  有効にすると、切断時は赤点滅、接続時は緑点滅
</fieldset>

Webアプリの動作概要

「接続」ボタンを押し、周囲の接続可能なBLEデバイスを探し、接続します。接続が済んだら、今回のアプリで使用するファンクションに必要なサービスのUUIDとキャラクタリスティックのUUIDを取得します。
バッテリー電圧の「読み出し」ボタンを押すと測定された電圧がテキストボックスに表示されます。
LEDインジケータ設定を有効・無効のどちらか選択して、「設定」ボタンを押すと選択された状態に変更されます。デフォルトでは無効状態なので、有効を選択して「設定」ボタンを押すとLEDが点滅を始めます。

WebアプリのJavascriptの説明

初期設定

<script src="https://d3js.org/d3.v5.min.js"></script>
    
<script>
  var bluetoothDevice;
  var basCharacteristic;
  var ledIndicatorCharacteristic;
  //BLE UUID (Must be lower case)
  var APPSIDE_SERVICE_UUID                             = '78636976-0217-46c4-ae05-0b988b11da48';
  var APPSIDE_BAS_CHARACTERISTIC_UUID                  = '822cdcdc-98b2-4eb8-accb-a4b1fc08e3f3';
  var APPSIDE_LED_INDICATOR_CHARACTERISTIC_UUID        = '550a7e35-b0bb-421c-87ad-7cca450a3572';
  //UIイベントリスナー
  d3.select("#connect").on("click", connect);
  d3.select("#disconnect").on("click", disconnect);    
  d3.select("#read_voltage").on("click", readVoltage);
  d3.select("#set_led").on("click", setLedIndicator);

最初に必要な変数の定義をしています。
次に、サービスとキャラクタリスティックのUUIDの定義(UUIDは、小文字を使用しないとうまく動作しないようです。)をしています。
最後にGUIの部分で定義したボタンとJavascriptの関数とを対応させて、クリックしたら呼び出されるようにしています。

Connect関数の処理

  function connect() {
    let options = {};
    options.filters = [
      {services: [APPSIDE_SERVICE_UUID]},
      {namePrefix: "APSDSNS"}
    ];
    navigator.bluetooth.requestDevice(options)
    .then(device => {
      bluetoothDevice = device;
      console.log("device", device);
      return device.gatt.connect();
    })
    .then(server => {
      console.log("server", server);
      return server.getPrimaryService(APPSIDE_SERVICE_UUID);
    })
    .then(service => {
      console.log("service", service)
      return Promise.all([
        service.getCharacteristic(APPSIDE_BAS_CHARACTERISTIC_UUID),
        service.getCharacteristic(APPSIDE_LED_INDICATOR_CHARACTERISTIC_UUID),
      ]);
    })
    .then(([charaBas, charaLed]) => {
      console.log("characteristic", charaBas)
      basCharacteristic = charaBas;
      console.log("characteristic", charaLed)
      ledIndicatorCharacteristic = charaLed;
      alert("BLE接続が完了しました。");
      document.getElementById('connect').disabled = true;
      document.getElementById('disconnect').disabled = false;
      document.getElementById('read_voltage').disabled = false;
      document.getElementById('set_led').disabled = false;
    })
    .catch(error => {
      console.log(error);
      alert("Errorです。");
    });
  }

デバイス名(APSDSNSで始まる)とサービスのUUIDでフィルタをかけ、見つかったデバイスと接続します。フィルタの設定は、options.filtersで行っています。フィルタを設定しないと、周囲にあるBluetoothデバイスがたくさんある場合に、必要なデバイスを見つけにくくなります。
接続したら、そのあとサービスのUUIDを指定してプライマリサービスを取得(getPrimaryService)し、次にキャラクタリスティックのUUIDを指定してキャラクタリスティックを取得(getCharacteristic)します。すべて取得できたらメッセージを表示して、無効にしてあったボタンを有効にして、「接続」ボタンを無効にします。
問題がある場合はエラーメッセージを表示します。

readVoltage関数の処理

  //battery voltageを読み出し
  function readVoltage() {
    if (!bluetoothDevice || !bluetoothDevice.gatt.connected || !basCharacteristic) return ;
    basCharacteristic.readValue()
    .then(value => {
      let dataView = new DataView(value.buffer);
      let decimalValue = dataView.getUint16(0, false); // ビッグエンディアンで2バイトを10進数に変換
      document.getElementById('message').value = decimalValue.toString();
    });
  }

接続して必要なキャラクタリスティックを取得出来ていない場合は先へ進まず戻ります。
キャラクタリスティックに対しては、主に値の読み出し(read)・値の書き込み(write)・値の通知(notify)の処理が行えます。このreadVoltage関数では、キャラクタリスティックの読み出し(read)を行います。読み出した値はtextarea (id=”message”)に表示します。

ledIndicator関数の動作

  //LEDインジケータ状態を設定
  function setLedIndicator() {
    if (!bluetoothDevice || !bluetoothDevice.gatt.connected || !ledIndicatorCharacteristic) return ;
    var charLedStatus = document.getElementById('led_status').value;
    var data = new Uint8Array([parseInt(charLedStatus)]);
    var buffer = data.buffer;
    console.log("write led state", buffer);
    ledIndicatorCharacteristic.writeValue(buffer);
  }

接続して必要なキャラクタリスティックを取得出来ていない場合は先へ進まず戻ります。
キャラクタリスティックに対しては、主に値の読み出し(read)・値の書き込み(write)・値の通知(notify)の処理が行えます。このsetLedIndicator関数では、キャラクタリスティックの書き込み(write)を行います。

disconnect関数の動作

  //BLE切断処理
  function disconnect() {
    if (!bluetoothDevice || !bluetoothDevice.gatt.connected) return ;
    bluetoothDevice.gatt.disconnect();
    alert("BLE接続を切断しました。");
    document.getElementById('connect').disabled = false;
    document.getElementById('disconnect').disabled = true;
    document.getElementById('read_voltage').disabled = true;
    document.getElementById('set_led').disabled = true;
  }
</script>    

接続していない場合は先へ進まず戻ります。
切断してメッセージを表示し、「接続」ボタンを有効にして、残りのボタンを無効にします。