IoTLT Advent Calendar 2018の10日目担当の蔵下です。普段はIoTな会社でWeb系の開発を行っています。
のびすけさんの記事「Nefry BT(ESP32)からBLEでNode.jsにデータを送ってみよう」で、Nefry BTもいい感じにBLE使えるやん! ということで、 Nefry BT ↔ ブラウザ
でデータを表示する方法をまとめてみました。
▲クリスマスっぽさを少しだけ
Nefry BT(BLEデバイス)とブラウザの通信はWeb Bluetoothでできる
Nefry BTとブラウザでのデータ通信は Web Bluetooth
で実現できます。普段の仕事でもゴニョゴニョ使っているので、詳細は他記事でまとめていますので良かったら見てみてください。
Web Bluetoothは、現在(2018/12/10)Windows、Mac、AndroidのChromeで使えます(詳細はこちら)。そうです、 スマホでも使えます!
IoTなデモ作る幅も広がると思うので、ぜひ触ってみてください。
ソースコード
今回のデモはのびすけさんの記事「Nefry BT(ESP32)からBLEでNode.jsにデータを送ってみよう」をベースに一部変更を加えながら進めました(ありがとうございます!)。Nefry BTは初期のR1を使っています。
スケッチ(Nefry BT側のコード)
#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(ブラウザ側のコード)
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(ブラウザ側のコード)
<!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参加できていなかったので、来年からまたちょこちょこ参加したいと思います! 良いお年を~