Web Bluetooth API を使い micro:bit とブラウザの間で BLE通信【 #GWアドベントカレンダー 2021/4/30 】

この記事は、[2021年の GWアドベントカレンダー](https://gw-advent.9wick.com/calendars/2021/103)  4/30の分の記事です。

## はじめに
以前、Web Bluetooth API を使った BLE通信により、Chrome と micro:bit を連携させたことがありました。
　●Web Bluetooth API で BLE（Chrome と micro:bit をつなぐ） - Qiita
　　https://qiita.com/youtoy/items/cd2c3d4770d4ad75a321

この時は、ブラウザからテキストデータを送信し、そのテキストを micro:bit の LED に表示させる処理を行いました。その際、Bluetooth の LEDサービスを利用していたのですが、今回は Bluetooth の UARTサービスを使った通信を行います。また今回は、micro:bit側からブラウザへデータを送ります。

## 今回のプログラム
### micro:bit側のプログラム
micro:bit側のプログラムで、BLE経由でデータを送る仕組みを作ります。プログラムを作る際に、以下の記事の[「micro:bit側の準備」](https://qiita.com/youtoy/items/bb24dd9051f3eb8a33e2#microbit%E5%81%B4%E3%81%AE%E6%BA%96%E5%82%99)の部分書いたペアリング関連の設定を行ってください。
　●【micro:bit 2019】#obniz と micro:bit で obniz-noble を使った BLE通信 （26記事目） - Qiita
　　https://qiita.com/youtoy/items/bb24dd9051f3eb8a33e2#microbit%E5%81%B4%E3%81%AE%E6%BA%96%E5%82%99

プログラムの内容は以下のとおりです。
![micro:bitでBLE UART.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/44224d54-b807-cdd6-fc4f-cc1b8d2f3f11.jpeg)

micro:bit から送信されるデータと、そのきかっけは以下のとおりです。
 ・「buttonA/buttonB」 ⇒ A/Bボタン押下時
 ・「left/right」 ⇒ 左/右に傾けた時
 ・「（加速度 X の値）」 ⇒ 一定の時間間隔で送信

### ブラウザ側のプログラム
ブラウザ側で実装する処理は以下の通りです。
 ・micro:bit との接続処理
 ・BLE経由でのデータ受信処理
 ・受信したデータによる場合分けの処理
また、BLE通信を行うために用いる UUID は、「UART SERVICE」と「TX CHAR CHARACTERISTIC」の 2つです。

micro:bit から受信したイベント内容等に応じたブラウザの処理は、今回はとりあえずログで受信内容を出力するだけになっています。

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Web Bluetooth API による通信（micro:bit）</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.1/css/bulma.css"/>
  </head>
  <body>
    <section class="section">
      <div class="container">
        <h1 class="title">操作用ボタン</h1>
        <div class="buttons" style="margin-top: 1.5rem">
          <button class="button is-success is-light" type="button" onclick="onStartButtonClick()">micro:bit 接続</button>
        </div>
      </div>
    </section>

    <script>
      const UUID_UART_SERVICE = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
      const UUID_TX_CHAR_CHARACTERISTIC = "6e400002-b5a3-f393-e0a9-e50e24dcca9e";
      let myCharacteristics;

      async function onStartButtonClick() {
        try {
          console.log("Requesting Bluetooth Device...");
          const device = await navigator.bluetooth.requestDevice({
            filters: [
              { services: [UUID_UART_SERVICE] },
              { namePrefix: "BBC" },
            ],
          });

          console.log("Connecting to GATT Server...");
          const server = await device.gatt.connect();
          console.log("Getting Service...");
          const service = await server.getPrimaryService(UUID_UART_SERVICE);
          console.log("Getting Characteristic...");
          myCharacteristics = await service.getCharacteristic(UUID_TX_CHAR_CHARACTERISTIC);
          myCharacteristics.startNotifications();
          console.log("> Notifications started");
          myCharacteristics.addEventListener("characteristicvaluechanged", handleNotifications);
        } catch (error) {
          console.log("Argh! " + error);
        }
      }

      async function handleNotifications(event) {
        if (myCharacteristics) {
          try {
            const value = event.target.value;
            const inputValue = new TextDecoder().decode(value).replace(/\r?\n/g, '');
            switch (inputValue) {
              case "buttonA":
                console.log(`Aボタンが押されたよ`);
                break;
              case "buttonB":
                console.log(`Bボタンが押されたよ`);
                break;
              case "left":
                console.log(`左に傾いたよ`);
                break;
              case "right":
                console.log(`右に傾いたよ`);
                break;
              default:
                console.log(`センサの値 ${parseInt(inputValue)}`);
            }
          } catch (error) {
            console.log("Argh! " + error);
          }
        }
      }
    </script>
  </body>
</html>
```

上記を使って通信を行わせると、ブラウザのコンソールに micro:bit から送られたデータが表示されました。

## おわりに
今回、とりあえず micro:bit ＋ BLE UART の組み合わせを簡単に試しました。
今後は、BLE経由で得られたデータによる場合分けの処理の部分を、別デバイスとの連携などといった内容に発展させていければと思います。