Raspberry Pi 3 で BLE 機器 (mamorio) のアドバタイジング・パケットをスキャンしてみたので、メモ。

## 1. 利用機器

### 1.1. Raspberry Pi 3

- [Raspberry Pi 3 Model B - Raspberry Pi](https://www.raspberrypi.org/products/raspberry-pi-3-model-b/)
- OS: [Raspbian](https://www.raspberrypi.org/downloads/raspbian/)
- Language: Node.js v8.8.1

### 1.2. MAMORIO

[MAMORIO | あなたの大切なものを守る世界最小クラスの紛失防止デバイス](https://mamorio.jp/)

## 2. 利用ライブラリ

### 2.1. noble

- [noble](https://www.npmjs.com/package/noble) 
- Version: 1.8.1
- node で ble 使う時のデファクトスタンダード？

## 3. mamorio (ibeacon) のアドバタイジングパケットの中身

### 3.1. ibeacon

ibeacon のアドバタイジングパケットについては、クラスメソッドさんのブログが分かりやすかったので、引用させていただく。

> 下記は、iBeaconのアドバタイズパケットです。XX以外の部分は、固定です。

|値|内容|
|:--|:--|
|1A|AD Structureの長さ|
|FF|ADのタイプ
|4C 00|企業識別子 0x004C(Apple)|
|02|iBeacon 識別子|
|15|iBeacon 識別子|
|XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX|UUID|
|XXXX|major|
|XXXX|minor|
|XX|Power|

引用元： [iBeaconのスキャナーを作ってみた ｜ Developers.IO](https://dev.classmethod.jp/smartphone/ibeacon-scanner2/)

### 3.2. mamorio

mamorio のアドバタイジングパケットについては、もみあげあしめさんのブログが分かりやすかったので、引用させていただく。

> Advertising Packet は Length, Type, Data の形式になっている。
MAMORIOから取得できたAdvertising Packetは下記とおり。※0xは省略

|Length|Type|Data|
|:--|:--|:--|
|02|01|04|
|1A|FF|4C 00 02 15 B9 40 7F 30 F5 F8 46 6E AF F9 25 55 6B 57 FE 6E BE 49 F7 47 B5|

> Type の割り当ては [Generic Access Profile | Bluetooth Technology Website](https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile) によると下記とおり。

|Typeの値|割り当て内容|
|:--|:--|
|0x01|«Flags»|
|0xFF|«Manufacturer Specific Data»|

> «Manufacturer Specific Data»の中身

|値|割り当て内容|備考|
|:--|:--|:--|
|0x4C00|Company|Apple, Inc. Company Identifiers|
|0x02|Beacon|--|
|0x15|Length|21Byte|

> iBeacon本体のデータ構造

|値|割り当て内容|備考|
|:--|:--|:--|
|b9407f30-f5f8-466e-aff9-25556b57fe6e|UUID|企業・組織の識別|
|0xBE49|Major|iBeaconのグループ|
|0xF747|Minor|グループ内のID|
|0xB5|RSSI|1m 地点で -75dB|

> 参考：[iBeacon（2ページ目） - 日経テクノロジーオンライン](http://techon.nikkeibp.co.jp/article/COLUMN/20131218/323372/?P=2&rt=nocnt)

引用元： [MAMORIOが届いたので解析したかった - もみあげあしめ](http://shima-nigoro.hatenablog.jp/entry/2016/07/09/201953)

## 4. 実装

### 4.1. ソースコード

```js
'use strict';

const noble = require('noble');

noble.on('stateChange', function (state) {
  if (state === 'poweredOn') {
    console.log("noble.startScanning()");
    //noble.startScanning(); // any service UUID, no duplicates
    noble.startScanning([], true); // any service UUID, allow duplicates
  } else {
    console.log("noble.stopScanning()");
    noble.stopScanning();
  }
});

noble.on('discover', function (peripheral) {
  var rssi = peripheral.rssi;
  var buf = peripheral.advertisement.manufacturerData;
  if (typeof buf !== "undefined") {
    // mamorio (ibeacon) かどうかを判定するための値をセット。
    // 16進数の方がイメージしやすかったので下記実装にしている。
    var checkbuff = new Buffer([parseInt("4c", 16), parseInt("00", 16), parseInt("02", 16)]);
    if (0 == buf.compare(checkbuff, 0, 3, 0, 3)) {
      console.log(buf.toString('hex') + " " + rssi);
    }  
  }
});
```

### 4.2. 説明

#### 4.2.1. スキャン

noble のサンプルコードそのままだけど、前者だと、UUID は重複しないでスキャン、とのことなので、今回の期待動作ではない。実際に、はじめは理解せずに、前者にしていて、アドバタイズがバンバンされているはずなのになー、なんでだろう？と考え込む時間を浪費。。

後者の実装にしたら、バンバン、スキャンされだした！これだよ、これ、やりたかったのは。

```js
noble.startScanning(); // any service UUID, no duplicates
```

```js
noble.startScanning([], true); // any service UUID, allow duplicates
```

#### 4.2.2. mamorio の判定

Manufacturer Data が、 `4c00 02` かどうかしか見ていないので、 mamorio かどうかというより、ibeacon かどうかの実装か。

```js
// mamorio (ibeacon) かどうかを判定するための値をセット。
// 16進数の方がイメージしやすかったので下記実装にしている。
var checkbuff = new Buffer([parseInt("4c", 16), parseInt("00", 16), parseInt("02", 16)]);
if (0 == buf.compare(checkbuff, 0, 3, 0, 3)) {
  console.log(buf.toString('hex') + " " + rssi);
}  
```

以上。