#UIFlow の BLE UART を使った #M5Stack_Core2 （ #M5Stack ）からブラウザへのデータ送信とグラフ化

これまで、UIFlow の BLE UART を試して以下の記事を書いてきました。

* [#UIFlow の BLE UART を使った文字のやりとりを #M5Stack_Core2 で試してみた（ #M5Stack ） - Qiita](https://qiita.com/youtoy/items/0aeac01927d60c33f421)
* [【JavaScript 2020】 #UIFlow の BLE UART を使ったブラウザから #M5Stack_Core2 （ #M5Stack ）への文字の送信 - Qiita](https://qiita.com/youtoy/items/3da58570972803134f6c)
* [#UIFlow の BLE UART を使った #M5Stack_Core2 （ #M5Stack ）とブラウザとの双方向無線通信 - Qiita](https://qiita.com/youtoy/items/d581d4e756656c68a8b7)

この記事は、上記で試してきた流れと、以下の記事で使ったグラフ化とを組み合わせた内容になります。

●【JavaScript 2020】 MQTT で受信したデータを Smoothie Charts（smoothie.js）以外でリアルタイムにグラフ化： Chart.js とプラグインを利用 - Qiita
　https://qiita.com/youtoy/items/252f255c9d794bf3d964

## 概要
まず、今回試した内容が動作している様子をご覧ください。
M5Stack Core2 のタッチスクリーン上に触れると、その x座標か y座標の値を取得し（どちらを取得するかは、Bボタン押下で変更できる仕組みあり）、それが BLE経由でブラウザに送られます。ブラウザ側では、受け取った値を使ってリアルタイムにグラフを描いています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/UIFlow?src=hash&amp;ref_src=twsrc%5Etfw">#UIFlow</a> の BLE UART を引き続きお試し。<a href="https://twitter.com/hashtag/M5Stack_Core2?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack_Core2</a> の画面上でタッチされた座標を BLE でブラウザに送り、リアルタイムにグラフとして描画してみた。<br><br>送る値を途中で 、x座標にするか y座標にするか、入れ替えてます。<a href="https://twitter.com/hashtag/M5Stack?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack</a> <a href="https://t.co/wHvN4vdoB8">pic.twitter.com/wHvN4vdoB8</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1351836708703113217?ref_src=twsrc%5Etfw">January 20, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## プログラム

M5Stack Core2 で動作している UIFlow のプログラムと、ブラウザ側で動いている HTML＋JavaScript のソースをそれぞれ記載します。

### UIFlow
UIFlow側は、以下のような仕組みにしてます。

![UIFlowのプログラム.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/8412c98c-7a35-5a9a-a205-6d368f2be3dc.jpeg)

* Aボタン押下 ⇒ 300ミリ秒間隔で動くタイマーを開始
* Bボタン押下 ⇒ 取得する値（タッチスクリーン上で触れられた位置の座標）を x/y のどちらにするか切り替え
* Cボタン押下 ⇒ タイマーを止める
* タイマーの処理 ⇒ タッチスクリーン上で触れられた位置の座標 x/y を BLE で送信しつつ、画面上にも表示

タイマーの処理の最後のブロック、「テキストに変換する」を入れないとうまく動かなかったので入れたものです。
その1つ上のブロック、画面のラベルでの表示のほうはそれが不要だったのですが、テキストのプログラムに切り替えてそれぞれを見てみると、画面表示のほうはテキストに変換する処理が裏で入ってました。

### HTML＋JavaScript
ブラウザ側の処理（BLE関連の処理やグラフ描画の処理）は以下のように実装しています。
利用する際には、こちらを HTMLファイルにしてブラウザで開き、最初に画面上の「接続」ボタンを押してペアリングから始めてください。その後は、M5Stack Core2側を操作していく流れです。

```JavaScript
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>UIFlow と BLE</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
    <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@1.8.0/dist/chartjs-plugin-streaming.min.js"></script>
  </head>

  <body>
    <h1>UIFlow と BLE ＋ グラフ描画</h1>
    <button onclick="onStartButtonClick()">接続</button>
    <br />
    <canvas id="myChart"></canvas>

    <script>
      const UUID_1 = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
      const UUID_2 = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"; // Write、今回は使わない
      const UUID_3 = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"; // Notify

      let bluetoothDevice;
      let characteristic;

      async function onStartButtonClick() {
        try {
          console.log("Requesting Bluetooth Device...");
          const device = await navigator.bluetooth.requestDevice({
            filters: [{ namePrefix: "m5ble" }],
            optionalServices: [UUID_1],
          });
          console.log("Connecting to GATT Server...");
          const server = await device.gatt.connect();
          console.log("Getting Service...");
          const service = await server.getPrimaryService(UUID_1);
          console.log("Getting Characteristic...");
          characteristic = await service.getCharacteristic(UUID_3);
          await characteristic.startNotifications();
          console.log("> Notifications started");
          characteristic.addEventListener(
            "characteristicvaluechanged",
            handleNotifications
          );
        } catch (error) {
          console.log("Argh! " + error);
        }
      }

      const ctx = document.getElementById("myChart").getContext("2d");

      let chart = new Chart(ctx, {
        type: "line",
        data: {
          datasets: [
            {
              data: [],
            },
            {
              data: [],
            },
          ],
        },
        options: {
          scales: {
            xAxes: [
              {
                type: "realtime",
                realtime: {
                  delay: 200,
                },
              },
            ],
          },
        },
      });

      async function handleNotifications(event) {
        if (characteristic) {
          try {
            const value = event.target.value;
            const inputValue = new TextDecoder().decode(value);
            console.log(inputValue);

            chart.data.datasets[0].data.push({
              x: Date.now(),
              y: inputValue,
            });
            chart.update({
              preservation: true,
            });
          } catch (error) {
            console.log("Argh! " + error);
          }
        }
      }
    </script>
  </body>
</html>
```

グラフ描画まわりの処理の説明は、記事の上のほうでも掲載した以下の記事のほうをご覧ください。

●【JavaScript 2020】 MQTT で受信したデータを Smoothie Charts（smoothie.js）以外でリアルタイムにグラフ化： Chart.js とプラグインを利用 - Qiita
　https://qiita.com/youtoy/items/252f255c9d794bf3d964