Edited at
IoTLTDay 10

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(ブラウザ側のコード)


app.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参加できていなかったので、来年からまたちょこちょこ参加したいと思います! 良いお年を~