WebBluetoothでブラウザからNefry BTに文字を表示させてみる


WebBluetoothでNefry BTと繋げてディスプレイ表示させてみたのでまとめます。

## 作ったデモ

* ブラウザ -> Nefry BTに表示

<img src="https://i.gyazo.com/502ff23429d898cbad8b779afed52d45.gif" width="400">
https://www.instagram.com/p/BrunzVCjWtq/

## 環境

* Nefry BTライブラリ v1.4.1
* Google Chrome v71 (macOS)
* Vue.js

1.4.1が重要で、内部でESP32のライブラリが1系にアップデートされています。
1.4.0と比べるとBLEが格段に安定します。

## ブラウザ側(HTML + Vue.js)

### html

```index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <button id="connect" @click="init">{{bleStatus}}</button>
        <input v-model="message" placeholder="edit me" v-on:keyup="write">
        <p>Message is: {{ message }}</p>
    </div>
    <script src="https://jp.vuejs.org/js/vue.min.js"></script>
    <script src="app.js"></script>
</body>
</html>
```

キー入力があるたびにBLEを発火させたいので`v-on:keyup`を指定します。

### JavaScript


`SERVICE_UUID`と`CHARACTERISTIC_UUID`に[ジェネレータ](https://www.uuidgenerator.net/)や自身で取得したUUIDを記載します。

```app.js
'use strict';

var app = new Vue({
    el: '#app',
    data: {
        SERVICE_UUID: 'サービスUUIDを記載',
        CHARACTERISTIC_UUID: 'キャラクタリスティックUUIDを記載',
        characteristic: {},
        message: '',
        bleStatus: 'Nefry BTと接続する'
    },

    methods: {
        init: async function(){
            try {
                const device = await navigator.bluetooth.requestDevice({
                    acceptAllDevices: false,
                    filters: [{namePrefix: 'Nefry'}], // 'Nefry'というデバイス名でフィルタリング
                    optionalServices: [this.SERVICE_UUID] // 使用したいServiceを登録しておく
                });
                const server = await device.gatt.connect();
                const service = await server.getPrimaryService(this.SERVICE_UUID); //サービスに接続
                this.characteristic = await service.getCharacteristic(this.CHARACTERISTIC_UUID);   //キャラクタリスティックに接続
                alert('接続しました。');
                this.bleStatus = 'Nefry BTと接続されています。';
            } catch (error) {
                console.log('エラー',error);
            }
        },

        write: function(){
            try {
                const text = this.message;
                const arrayBuffe = new TextEncoder().encode(text);
                this.characteristic.writeValue(arrayBuffe);    
            } catch (error) {
                console.log(error);
                alert('先にデバイスと接続してください。');
            }
        }
    }
});
```

DOM周りのコードがないのでシンプルにかけますね。

## NefryBT(Arduino)側コード

こちらも先ほど取得/生成したUUIDを`SERVICE_UUID`と`CHARACTERISTIC_UUID`に記載します。

```nefrybt.ino
#include <Nefry.h>
#include <NefryDisplay.h>

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// from https://www.uuidgenerator.net/
#define SERVICE_UUID        "サービスUUIDを記載"
#define CHARACTERISTIC_UUID "キャラクタリスティックUUIDを記載"

//3行目だけにPrint
void nfDisplay3Print(String mes){
  NefryDisplay.print("");
  NefryDisplay.print("");
  NefryDisplay.print(mes);
}

// コールバック
// ブラウザ側からwriteValue()されたら実行
class MyCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    std::string value = pCharacteristic->getValue();
    
    // シリアルにデバッグ出力(受信した文字列)
    String message = "";
    if (value.length() > 0) {
      Nefry.print("Received: ");
      // 1文字ずつ取得
      for (int i = 0; i < value.length(); i++) {
        Nefry.print(value[i]);
        message += String(value[i]);
      }
    }
    Nefry.println((char)value[0]);
    nfDisplay3Print(message);
  }
};

void setup() {
  Nefry.disableWifi();
  Nefry.setLed(0, 0, 0);
  NefryDisplay.setTitle("from Web Bluetooth");
    
  BLEDevice::init("NefryBT WebBluetooth test");
  Nefry.println("NefryBT WebBluetooth test");
  
  BLEServer *pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );
  pCharacteristic->setCallbacks(new MyCallbacks());
  pCharacteristic->setValue("Merry X'mas!");
  pService->start();
  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
}

void loop() {
  Nefry.ndelay(1000);  // 待ちループ
}
```

## 所感

WebBluetoothもだんだん使えるようになってきているし、NefryBTのBLEがすごく安定するようになったのでNefry BTに入力できる専用サイトみたいなものを作れそうですね。

Wi-Fi設定をBLE経由で書き込み出来るようになる「Nefry BT専用Webページ」てきなものを作れないか考えています。

対応できたら楽しそうですね！

## 参考にさせてもらいました

* [Web Bluetooth API を使ってブラウザだけでMicro:bitとBLE通信してみる。](https://shimz.me/blog/microbit/5456)
* [LINE Things StarterをNefry BTで動かしてみよう #linethings](https://qiita.com/n0bisuke/items/aaf204528a07c0ef248b)
* [Nefry BTからブラウザにWeb Bluetoothでデータを表示する方法](https://qiita.com/umi_kappa/items/dd3d7a27cf714971406e)
* [話題のWebBluetoothでGenuino101をブラウザからリモートコントロールしてみよう](https://dotstud.io/blog/web-bluetooth-remote-blink/)