Web Bluetooth APIを使って、アルプスのセンサネットワークモジュールから加速度データを取得します。「Web BluetoothによるSensorTagのScan」でWeb Bluetooth APIを使って、SensorTagをScanするスクリプトを作成しました。また「C# .NET Frameworkを使ってアルプスのセンサネットワークモジュールからモーションデータの取得」では、C# .NET Frameworkのコンソールアプリを作成しました。
センサネットワークモジュール加速度データ取得プログラムの作成
3つのファイル「alps.html」「alps.js」「alps_ble.js」で構成し、Web Bluetooth APIで作成したセンサネットワークモジュール加速度データ取得プログラムを次に示します。プログラムは、クラス設計により、PromiseでなくAsync/Awaitを使用して非同期で処理します。
alps.html
<html> <head> <meta charset="utf-8"> <title>Sensor Network Module</title> <script type="module" src="./alps.js"></script> </head> <body> <h2>Sensor Network Module</h2> <div> <button class="scanBtn"> Connect </button> </div><br> <div> <button class="commandBtn"> Command </button> </div><br> <div> <button class="notifyBtn"> Notify Start </button> </div><br> <div> <button class="readdataBtn"> Read Data </button> </div><br> <div> <button class="resetBtn"> Disconnect </button> </div><br> <hr> <div> <div id="device_name">Device Name : </div> <div id="connect_status">Status : Disconnect</div> <div id="read_data">Data :</div><br> <div id="error">Error : </div> </div> </body> </html>
- 1行目で、alps_ble.jsに作成したクラスをimport します。
- 3行目でimportしたクラスをインスタンス化します。
alps.js
import Alps_ble from './alps_ble.js'; let alps_ble = new Alps_ble(); //Connectボタンの処理 const scanBtn = document.querySelector('.scanBtn'); scanBtn.addEventListener('click', function (clickEvent) { //this.EGRequest = 0; //暫定的に記載 alps_ble.Blecan(); }) //コマンド書き込み const onBtn = document.querySelector('.commandBtn'); onBtn.addEventListener('click', function (clickEvent) { //セットしたコマンドを送信 alps_ble.Write(alps_ble.Custom3_Characteristic_UUID, alps_ble.Command); }) //データ読み込み const battBtn = document.querySelector('.readdataBtn'); battBtn.addEventListener('click', function (clickEvent) { alps_ble.Read(alps_ble.Custom1_Characteristic_UUID); }) //データ通知 const notifyBtn = document.querySelector('.notifyBtn'); notifyBtn.addEventListener('click', function (clickEvent) { alps_ble.StartNotify(alps_ble.Custom1_Characteristic_UUID); }) //Disconnectボタンの処理 const resetBtn = document.querySelector('.resetBtn'); resetBtn.addEventListener('click', function (clickEvent) { alps_ble.Reset(); }) //HTMLに値を表示 alps_ble.onScan = function (deviceName) { document.getElementById('device_name').innerHTML = 'Device Name : ' + deviceName; document.getElementById('error').innerHTML = "Error : "; } alps_ble.onConnectGATT = function () { document.getElementById('connect_status').innerHTML = 'Status : Connected'; document.getElementById('error').innerHTML = "Error : "; }; alps_ble.onWrite = function () { document.getElementById('connect_status').innerHTML = 'Status : Sended command' document.getElementById('error').innerHTML = "Error : "; } alps_ble.onData = function (data) { document.getElementById('read_data').innerHTML = 'Data : ' + data; document.getElementById('error').innerHTML = "Error : "; } alps_ble.onError = function (error) { document.getElementById('error').innerHTML = 'Error : ' + error; }
- 29行目の「navigator.bluetooth.requestDevice」メソッドで、センサネットワークモジュールを検索します。
- 33行目の「device.gatt.connect」メソッドで、センサネットワークモジュールと接続します。
- 35行目の「getPrimaryService」メソッドで、PrimaryUUIDからPrimaryServiceを取得します。
- 46行目の「getCharacteristic」メソッドで、書き込みUUIDからCharacteristicを取得します。
- 53行目で、作成したUint8Array(char型バッファ)にコマンドを設定します。
- 56行目の「writeValue」メソッドで、コマンドを書き込みます。
- 70行目の「getCharacteristic」メソッドで、読み込みUUIDからCharacteristicを取得します。
- 71行目の「readValue」メソッドで、データを読み込みます。
- 72行目で、読み込んだデータを表示します。
- 96行目の「DataChanged」メソッドで、イベントにより通知されたデータを処理します。
- 125行目の「ConvertAcceleration」メソッドで、読み込んだデータから加速度を計算します。
- 151行目の「getCharacteristic」メソッドで、読み込みUUIDからCharacteristicを取得します。
- 152行目の「addEventListener」メソッドで、EventListenerとして「DataChanged」メソッドを設定します。その時にクラス内のメソッドを読み出せるように「.bind(this)」を付与します。
- 153行目の「startNotifications」メソッドで、Notificationを開始します。
- 164行目の「stopNotifications」メソッドで、Notificationを終了します。
- 184行目の「gatt.disconnect」メソッドで、接続を切断します。
alps_ble.js
export default class { //constructor constructor() { this.device = null; this.server = null; this.service = null; this.Commanduuid = null; this.Readuuid = null; this.Notifyuuid = null; this.Service1_UUID = "47fe55d8-447f-43ef-9ad9-fe6325e17c47"; this.Custom1_Characteristic_UUID = "686a9a3b-4c2c-4231-b871-9cfe92cc6b1e"; this.Custom2_Characteristic_UUID = "078ff5d6-3c93-47f5-a30c-05563b8d831e"; this.Custom3_Characteristic_UUID = "b962bdd1-5a77-4797-93a1-ede8d0ff74bd"; // モーション(動き)検知 100ms間隔(モーション系センサのみ) this.Command = [[0x2F, 0x03, 0x03], [0x01, 0x03, 0x03], [0x04, 0x03, 0x01], [0x06, 0x04, 0x64, 0x00], [0x2F, 0x03, 0x01], [0x20, 0x03, 0x01]]; this.alpsoptions = { acceptAllDevices: true, optionalServices: [this.Service1_UUID] }; } async Blecan() { try { console.log('Requesting Bluetooth Device...'); this.device = await navigator.bluetooth.requestDevice(this.alpsoptions); this.onScan(this.device.name); this.onConnectGATT(); this.server = await this.device.gatt.connect(); console.log('Getting GAP Service...'); this.service = await this.server.getPrimaryService(this.Service1_UUID); console.log('Got Service'); } catch (error) { this.onError(error); console.log('Argh! ' + error); } } async Write(uuid, moveCommand) { try { console.log('Execute : Write'); this.Commanduuid = await this.service.getCharacteristic(uuid); //this.Readuuid = await this.service.getCharacteristic(this.Custom1_Characteristic_UUID); for (let i = 0; i < moveCommand.length; i++) { //console.log(moveCommand[i]); let uint8array = new Uint8Array(moveCommand[i].length); for (let Offset = 0; Offset < moveCommand[i].length; Offset++) { uint8array[Offset] = moveCommand[i][Offset]; } //console.log(uint8array); await this.Commanduuid.writeValue(uint8array, true); } this.onWrite(); } catch (error) { this.onError(error); console.log('Argh! ' + error); } } async Read(uuid) { try { let x = 0, y = 0, z = 0; console.log('Execute : read'); this.Readuuid = await this.service.getCharacteristic(uuid); let value = await this.Readuuid.readValue(); console.log("read :" + value.getUint32(0, false).toString(16) + value.getUint32(4, false).toString(16) + value.getUint32(8, false).toString(16) + value.getUint32(12, false).toString(16) + value.getUint32(16, false).toString(16) ); if (value.getUint8(0, false) == 0xf2) { [x, y, z] = this.ConvertAcceleration( value.getUint8(8, false), value.getUint8(9, false), value.getUint8(10, false), value.getUint8(11, false), value.getUint8(12, false), value.getUint8(13, false) ); console.log("Acceleration :" + " " + x.toFixed(3) + " " + y.toFixed(3) + " " + z.toFixed(3)); this.onData(x.toFixed(3) + " " + y.toFixed(3) + " " + z.toFixed(3)); } } catch (error) { this.onError(error); console.log('Argh! ' + error); } } DataChanged(event) { try { let x = 0, y = 0, z = 0; console.log('Execute : DataChanged'); let value = event.target.value; if (value.getUint8(0, false) == 0xf2) { [x, y, z] = this.ConvertAcceleration( value.getUint8(8, false), value.getUint8(9, false), value.getUint8(10, false), value.getUint8(11, false), value.getUint8(12, false), value.getUint8(13, false) ); } console.log("DataChanged :" + value.getUint32(0, false).toString(16) + value.getUint32(4, false).toString(16) + value.getUint32(8, false).toString(16) + value.getUint32(12, false).toString(16) + value.getUint32(16, false).toString(16) ); console.log("Acceleration :" + " " + x.toFixed(3) + " " + y.toFixed(3) + " " + z.toFixed(3)); this.onData(x.toFixed(3) + " " + y.toFixed(3) + " " + z.toFixed(3)); } catch (error) { this.onError(error); console.log('Argh! ' + error); } } ConvertAcceleration(x_l, x_m, y_l, y_m, z_l, z_m) { let x = 0, y = 0, z = 0; x = (x_l + x_m * 256); if (x >= 0x8000) { x = -1 * (0x10000 - x); } x = x / 4096; y = y_l + y_m * 256; if (y >= 0x8000) { y = -1 * (0x10000 - y); } y = y / 4096; z = z_l + z_m * 256; if (z >= 0x8000) { z = -1 * (0x10000 - z); } z = z / 4096; return [x, y, z]; } async StartNotify(uuid) { try { console.log('Execute : StartNotify'); this.Notifyuuid = await this.service.getCharacteristic(uuid); this.Notifyuuid.addEventListener('characteristicvaluechanged', this.DataChanged.bind(this)); await this.Notifyuuid.startNotifications(); } catch (error) { this.onError(error); console.log('Argh! ' + error); } } async StopNotify() { try { console.log('Execute : StopNotify'); await this.Notifyuuid.stopNotifications(); } catch (error) { this.onError(error); console.log('Argh! ' + error); } } async Disconnect() { if (!this.device) { var error = "No Bluetooth Device"; console.log('Error : ' + error); this.onError(error); return; } if (this.device.gatt.connected) { console.log('Execute : disconnect'); this.isNotify = false; this.device.gatt.disconnect(); } else { var error = "Bluetooth Device is already disconnected"; console.log('Error : ' + error); this.onError(error); return; } } Clear() { console.log('Excute : Clear Device and Characteristic'); this.device = null; } //reset Reset() { console.log('Excute : reset'); this.Disconnect(); //GNDisconnect() is not Promise Object this.Clear(); } }
センサネットワークモジュール加速度データ取得プログラムの実行
センサネットワークモジュールモーションデータ取得プログラムを実行し、アルプスのセンサネットワークモジュールとペアリングできると、次のように受信されたモーションデータを16進表示します。データの最初のバイト「Event Code」が「E0」が ステータス通知、「F2」がデータパケット 1となります。データパケット 1から加速度データを取得して表示します。