Help us understand the problem. What is going on with this article?

Nefry BTからブラウザにWeb Bluetoothでデータを表示する方法

IoTLT Advent Calendar 2018の10日目担当の蔵下です。普段はIoTな会社でWeb系の開発を行っています。

のびすけさんの記事「Nefry BT(ESP32)からBLEでNode.jsにデータを送ってみよう」で、Nefry BTもいい感じにBLE使えるやん!:clap: ということで、 Nefry BT ↔ ブラウザ でデータを表示する方法をまとめてみました。

web.gif

▲クリスマスっぽさを少しだけ:christmas_tree:

Nefry BT(BLEデバイス)とブラウザの通信はWeb Bluetoothでできる

Nefry BTとブラウザでのデータ通信は Web Bluetooth で実現できます。普段の仕事でもゴニョゴニョ使っているので、詳細は他記事でまとめていますので良かったら見てみてください。

Web Bluetoothは、現在(2018/12/10)Windows、Mac、AndroidのChromeで使えます(詳細はこちら)。そうです、 スマホでも使えます! IoTなデモ作る幅も広がると思うので、ぜひ触ってみてください。

https://dotstud.io/blog/nefrybt-ble-bluetooth-peripheral/

ソースコード

今回のデモはのびすけさんの記事「Nefry BT(ESP32)からBLEでNode.jsにデータを送ってみよう」をベースに一部変更を加えながら進めました(ありがとうございます!)。Nefry BTは初期のR1を使っています。

スケッチ(Nefry BT側のコード)

sketch.ino
#include <Nefry.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
uint8_t value = 0;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "d5875408-fa51-4763-a75d-7d33cecebc31"
#define CHARACTERISTIC_UUID "a4f01d8c-a037-43b6-9050-1876a8c23584"

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

void setup() {
  Serial.begin(115200);

  // Create the BLE Device
  BLEDevice::init("NefryBT");

  // Create the BLE Server
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );

  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
  // Create a BLE Descriptor
  pCharacteristic->addDescriptor(new BLE2902());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {

  if (deviceConnected) {
    Serial.printf("*** NOTIFY: %d ***\n", value);
    char buffer[32];
    sprintf(buffer, "{\"val\":%d}", value);
    Serial.printf(buffer);
    pCharacteristic->setValue(buffer);
    pCharacteristic->notify();
    //pCharacteristic->indicate();
    value++;
  }
  delay(2000);
}

JavaScript(ブラウザ側のコード)

main.js
const SERVICE_UUID = 'd5875408-fa51-4763-a75d-7d33cecebc31'
const CHARACTERISTIC_UUID = 'a4f01d8c-a037-43b6-9050-1876a8c23584'

const btn = document.getElementById('btn')
const text = document.getElementById('text')

// Web Bluetoothはユーザーアクションをトリガーに処理を始める必要がある
btn.addEventListener('click', (event) => {
  connect()
})

const connect = () => {
  // Scan
  navigator.bluetooth.requestDevice({
    // 'Nefry'というデバイス名でフィルタリング
    acceptAllDevices: false,
    filters: [
      {namePrefix: 'Nefry'}
    ],
    optionalServices: [
      // 使用したいServiceを登録しておく
      SERVICE_UUID
    ]
  })
    // 接続
    .then(device => device.gatt.connect())
    // Service取得
    .then(server => server.getPrimaryService(SERVICE_UUID))
    // Characteristic取得
    .then(service => service.getCharacteristic(CHARACTERISTIC_UUID))
    // Notificationsを開始
    .then(characteristic => setNotifications(characteristic))
    // Errorはこちら
    .catch(error => console.log(error))
}

// Notification設定
const setNotifications = (characteristic) => {

  // Add Event
  characteristic.addEventListener('characteristicvaluechanged', (event) => {
    const value = event.target.value

    // データをパース
    const decoder = new TextDecoder('utf-8')
    const str = decoder.decode(value)
    const json = JSON.parse(str)
    // Nefry BTからのデータを表示
    if (text) text.innerHTML = json.val
  })

  // Notifications開始
  characteristic.startNotifications()
}

HTML(ブラウザ側のコード)

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Web Bluetooth API</title>
  <script src="main.js" defer></script>
  <!-- CSSは省略 -->
</head>
<body>
<button id="btn">Connect</button>
<div id="text"></div>
</body>
</html>

まとめ

特に面白みのないネタになってしまいました(笑)。ですが、みなさんの面白いIoT作品の新たな選択肢になればいいなと思いまとめてみました。最近IoTLT参加できていなかったので、来年からまたちょこちょこ参加したいと思います! 良いお年を~

umi_kappa
週4で阿佐ヶ谷の飲み屋で芋飲んでます。いつもいるねって言われるけど、ちゃんと仕事してますよ。JSとかアプリとかでIoTなコンテンツを作るお仕事やってます。
http://umikappa.main.jp/
iotlt
IoT縛りの勉強会です。 毎月イベントを実施しているので是非遊びに来てください! 登壇者を中心にQiitaでも情報発信していきます。 https://iotlt.connpass.com
https://iotlt.connpass.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away