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から加速度データを取得して表示します。
