3000円の Bluetooth 対応体重計を Raspberry Pi を使って Google Fit に対応させてみた その2

![fatscale--raspi--googleFit.png](https://qiita-image-store.s3.amazonaws.com/0/38169/d3b00425-e6ac-ee22-1751-1763296fd9d4.png)

## 概要

[3000円の Bluetooth 対応体重計を Raspberry Pi を使って Google Fit に対応させてみた その1](http://qiita.com/ynakajima/items/261e53c8b4ecad7ec0df) の続き。

###前回までのおさらい

1. ３０００円で買ってきた Bluetooth（BLE）対応体重計を Google Fit に対応させたい
2. Node.js の BLE モジュール [noble](https://www.npmjs.com/package/noble) をつかって接続を試みる
3. どうやら「000FatScale01」という名前を名乗っているデバイスが該当の体重計らしい
4. [Device Information サービス](https://www.bluetooth.com/ja-jp/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.device_information.xml)をみつけたので特性の一覧を出力してみた

###今回の内容

* Device Information サービスの特性（characteristic）を探査してその値を読む
* 「00FatScale01」の独自サービス（0xFFF0）の特性を探査
* 探査した特性を購読(subscribe)して体重の値を受信する


## Device Information サービスの特性の値を読む

###パーミッションについて

[前回](http://qiita.com/ynakajima/items/261e53c8b4ecad7ec0df#device-information-%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E4%B8%AD%E8%BA%AB%E3%82%92%E8%AA%AD%E3%82%93%E3%81%A7%E3%81%BF%E3%82%8B) noble を使って取得した Device Information サービスの特性(Characteristic)は、このような構造になっていた。

```bash
Characteristic {
  _serviceUuid: '180a',
  uuid: '2a29',
  name: 'Manufacturer Name String',
  type: 'org.bluetooth.characteristic.manufacturer_name_string',
  properties: [ 'read' ],
  descriptors: null }
```

`uuid`、`name`,`type`はわかるが、`properties`とはなにものだろうか。

調べてみたところ、 `properties` は特性に対して許可されている操作のリストになっているとのこと。

###properties 属性の主な値

| Property | 内容 |
|-----------|----|
| read | 読み込み可能 |
| write | 書き込み可能 |
| notify |送信側からの値変更通知(notify)を、購読(subscribe)できる |

ここでは `read` のみが許可されているので読み込みが可能ということになる。


###各々の値を読んでみた

各特性が読み込み可能だということがわかったので、さっそく値を読んでみたい。

[read-device-information-characteristics.js](https://gist.github.com/ynakajima/06822682535defbf3f63d676d742ddbb#file-discover-0xfff0-characteristics-js)

```javascript:read-device-information-characteristics.js
const noble = require('noble')
const FAT_SCALE = '000FatScale01'

// Bluetooth のステータスを監視
noble.on('stateChange', (state) => {
  console.log(`\nstateChange: ${state}\n`)

  if (state === 'poweredOn') {
    // Bluetooth がオンの場合は周辺機器のスキャンを開始
    noble.startScanning()
  } else {
    // Bluetooth がオフの場合は周辺機器のスキャンを停止
    noble.stopScanning()
  }
})

// 周辺機器が見つかったら、接続後サービスを探査
noble.on('discover', (peripheral) => {
  const localName = peripheral.advertisement.localName
  if (localName === FAT_SCALE) {
    console.log(`discover peripheral: ${FAT_SCALE}\n`)

    // スキャンを停止
    noble.stopScanning()

    // 接続後 Device Information サービス(0x180a)を探査
    peripheral.once('connect', () => {
      peripheral.discoverServices(['180a'])
    })

    // 探査されたサービスを出力
    peripheral.once('servicesDiscover', onServiceDiscover)

    // 見つかった 000FatScale01 に接続
    peripheral.connect()
  }
})

// 探査されたサービスの特性を探査
function onServiceDiscover (services) {
  services
    .forEach((service) => {
      console.log('Discover Service: Device Information\n')
      service.once('characteristicsDiscover', onCharacteristicsDiscover)
      service.discoverCharacteristics()
    })
}

// 探査された特性の値を出力
function onCharacteristicsDiscover (characteristics) {
  console.log('Discover Characteristics:\n')
  characteristics
    .forEach(characteristic => {
      characteristic.read((err, data) => {
        if (err) throw err

        // type に _string を含む場合は文字列として値を取得
        // その他の場合は16進数として取得
        let value = (characteristic.type.indexOf('_string') !== -1)
          ? data.toString() : data.toString('hex')
        console.log(`(${characteristic.uuid}) ${characteristic.name} : ${value}`)
      })
    })
}
```

その結果がこちら（※シリアルナンバーの一部は念のため伏せ字にした）。

```bash
$ node read-device-information-characteristics.js
stateChange: poweredOn

discover peripheral: 000FatScale01

Discover Service: Device Information

Discover Characteristics:

(2a29) Manufacturer Name String : FSRK
(2a24) Model Number String : BT 4.0
(2a25) Serial Number String : Xqm2017****
(2a26) Firmware Revision String : sdkv37-no32k
(2a27) Hardware Revision String : FSRK-34-32-S
(2a28) Software Revision String : V003-noupdate
(2a23) System ID : 0000000000000000
(2a2a) IEEE 11073-20601 Regulatory Certification Data List : fe006578706572696d656e74616c
(2a50) PnP ID : 010e0012340167
```

Bluetoothデバイスから初めて読み込んだなにかしらの具体的なデータなので、なんか感動した。

##「000FatScale01」 の独自サービス(0xfff0)の調査

無事、Device Information サービスの特性の値を読むことができたので、続いて本丸である「000FatScale01」の独自サービスだと思われる 0xfff0 を見ていくことにしたい。

###0xfff0 の特性を探査

まずはどんな特性があるか見てみた。

[discover-0xfff0-characteristics.js](https://gist.github.com/ynakajima/06822682535defbf3f63d676d742ddbb#file-discover-0xfff0-characteristics-js)

```javascript:discover-0xfff0-characteristics.js
const noble = require('noble')
const FAT_SCALE = '000FatScale01'

// Bluetooth のステータスを監視
noble.on('stateChange', (state) => {
  console.log(`\nstateChange: ${state}\n`)

  if (state === 'poweredOn') {
    // Bluetooth がオンの場合は周辺機器のスキャンを開始
    noble.startScanning()
  } else {
    // Bluetooth がオフの場合は周辺機器のスキャンを停止
    noble.stopScanning()
  }
})

// 周辺機器が見つかったら、接続後サービスを探査
noble.on('discover', (peripheral) => {
  const localName = peripheral.advertisement.localName
  if (localName === FAT_SCALE) {
    console.log(`discover peripheral: ${FAT_SCALE}\n`)

    // スキャンを停止
    noble.stopScanning()

    // 接続後サービス(0xfff0)を探査
    peripheral.once('connect', () => {
      peripheral.discoverServices(['fff0'])
    })

    // 探査されたサービスを出力
    peripheral.once('servicesDiscover', onServiceDiscover)

    // 見つかった 000FatScale01 に接続
    peripheral.connect()
  }
})

// 探査されたサービスの特性を探査
function onServiceDiscover (services) {
  services
    .forEach((service) => {
      console.log('Discover Service: Device Information\n')
      service.once('characteristicsDiscover', onCharacteristicsDiscover)
      service.discoverCharacteristics()
    })
}

// 探査された特性の内容を出力
function onCharacteristicsDiscover (characteristics) {
  console.log('Discover Characteristics:\n')
  characteristics
    .forEach(characteristic => {
      // 不要なデータを削除
      delete characteristic._noble
      delete characteristic._peripheralId
      delete characteristic._serviceUuid
      console.dir(characteristic)
      console.log()
    })
}

```

その結果がこちら。

```bash
$ node discover-0xfff0-characteristics.js

stateChange: poweredOn

discover peripheral: 000FatScale01

Discover Service: Device Information

Discover Characteristics:

Characteristic {
  uuid: 'fff2',
  name: null,
  type: null,
  properties: [ 'read', 'write' ],
  descriptors: null }

Characteristic {
  uuid: 'fff6',
  name: null,
  type: null,
  properties: [ 'read', 'write', 'notify' ],
  descriptors: null }

Characteristic {
  uuid: 'fff1',
  name: null,
  type: null,
  properties: [ 'read', 'write', 'notify' ],
  descriptors: null }
```

`fff1`,`fff2`,`fff6` という３つの特性が探査できた。

`fff1` は **読み込み・書き込み**が可能、`fff2` と `fff6` は、**読み込み・書き込み・通知の購読**が可能のようだ。


###とりあえず特性を読む

とりあえず、３つとも読み込みが可能ということなので、値を読んでみた。

[read-0xfff0-characteristics.js](https://gist.github.com/ynakajima/06822682535defbf3f63d676d742ddbb#file-discover-0xfff0-characteristics-js)

```javascript:read-0xfff0-characteristics.js
// (中略）

// 探査された特性の値を出力
function onCharacteristicsDiscover (characteristics) {
  console.log('Discover Characteristics:\n')
  characteristics
    .forEach(characteristic => {
      characteristic.read((err, data) => {
        if (err) throw err
        console.log(`(${characteristic.uuid}): ${data.toString('hex')}`)
      })
    })
}
```

```bash
$ node read-0xfff0-characteristics.js

stateChange: poweredOn

discover peripheral: 000FatScale01

Discover Service: Device Information

Discover Characteristics:

(fff2): 0000000000000000000000000000000000000000
(fff6): 0000000000000000000000000000000000000000
(fff1): 0000000000000000000000000000000000000000
```
ものの見事にスッカラカンだった。


###特性を購読（subscribe）してみる

値をいきなり読み込むのはあきらめて、購読可能な `fff2` と `fff6` を購読してみることにする。

[subscribe-0xfff0-characteristics.js](https://gist.github.com/ynakajima/06822682535defbf3f63d676d742ddbb#file-subscribe-0xfff0-characteristics-js)

```javascript:subscribe-0xfff0-characteristics.js
// (中略)

// 探査された購読可能な特性を購読して
// 通知が来たらつど出力
function onCharacteristicsDiscover (characteristics) {
  console.log('Discover Characteristics:\n')
  characteristics
    .forEach(characteristic => {
      // notify が許可されている場合
      if (characteristic.properties.includes('notify')) {
        // 通知を受信したら値を出力
        characteristic.on('data', (data) => {
          console.log(`(${characteristic.uuid}):`)
          console.dir(data)
        })

        // 通知を購読
        characteristic.subscribe((err) => {
          if (err) throw err
          console.log(`(${characteristic.uuid}): start subscribe`)
        })
      }
    })
}
```

結果がこちら。

```bash
$ node subscribe-0xfff0-characteristics.js

stateChange: poweredOn

discover peripheral: 000FatScale01

disconnect: 000FatScale01
Discover Service: Device Information

Discover Characteristics:

(fff6): start subscribe
(fff1): start subscribe
(fff1):
Buffer [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
(fff1):
Buffer [ 0, 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170, 2, 216, 0, 172, 0 ]
(fff1):
Buffer [ 0, 0, 0, 0, 0, 0, 0, 116, 170, 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0 ]
(fff1):
Buffer [ 0, 116, 170, 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170, 2, 216, 0 ]
(fff1):
Buffer [ 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170, 2, 216, 0, 172, 0, 0, 0, 0, 0 ]
(fff1):
Buffer [ 0, 0, 0, 116, 170, 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 216, 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, 117, 170 ]
(fff1):
Buffer [ 2, 216, 0, 172, 0, 0, 0, 0, 0, 0, 0, 0, 116, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 170 ]
```

おぉ、なんかズラズラとデータがでてきた！

ちなみに何回かやってみた結果、このような傾向があることがわかった。

```bash
# 体重計の液晶に表示されている数値が 17.2kg の場合（※計測は座りながら行っていた）
.
.
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
(fff1):
Buffer [ 2, 221, 0, 172, 0, 168, 230, 233, 1, 123, 20, 128, 56, 170 ]
.
.

# 体重計の数値が 10.8kg の場合
.
.
Buffer [ 2, 221, 0, 108, 0, 162, 230, 228, 1, 130, 21, 128, 7, 170 ]
(fff1):
Buffer [ 2, 221, 0, 108, 0, 162, 230, 228, 1, 130, 21, 128, 7, 170 ]
(fff1):
Buffer [ 2, 221, 0, 108, 0, 162, 230, 228, 1, 130, 21, 128, 7, 170 ]
.
.

# 体重計の数値が 18.1kg の場合
.
.
Buffer [ 2, 221, 0, 181, 0, 156, 230, 229, 1, 125, 24, 128, 19, 170 ]
(fff1):
Buffer [ 2, 221, 0, 181, 0, 156, 230, 229, 1, 125, 24, 128, 19, 170 ]
(fff1):
Buffer [ 2, 221, 0, 181, 0, 156, 230, 229, 1, 125, 24, 128, 19, 170 ]
(fff1):
Buffer [ 2, 221, 0, 181, 0, 156, 230, 229, 1, 125, 24, 128, 19, 170 ]
.
.
```

おわかりだろうか。

受信したデータの先頭から数えて3byte目（先頭は0byte目と数える）の値を10で割った数値がどうやら体重の値である可能性が高そうだ。

ちなみに1byteだと最大で255までの数値しか扱えない（この場合25.5kgまでしか扱えない）ので、おそらく2byte目と3byte目の合計16bitで体重の値を表しているのではないかと思われる。

その仮説を検討する為に、今まで横着して座って計測していたのをちゃんと立って計測してみることにした。[^1]

```bash
# 体重計の数値が 93.6kg の場合の受信データ
.
.
(fff1):
Buffer [ 2, 221, 3, 168, 0, 213, 214, 222, 1, 168, 25, 128, 155, 170 ]
(fff1):
Buffer [ 2, 221, 3, 168, 0, 213, 214, 222, 1, 168, 25, 128, 155, 170 ]
(fff1):
Buffer [ 2, 221, 3, 168, 0, 213, 214, 222, 1, 168, 25, 128, 155, 170 ]
.
.
```

2byte目の数値が　`3`、3byte目の数値が `168` である。これを16進数でつなげて表すと　`0x03a8` となり、10進数だと `936` になる。これを10で割ると `93.6` だ。

どうやら、仮説は運良くあたっていたようである。

##取得した体重データを REST API で Google Fit へ記録する

どうにかこうにか無事に Bluetooth 対応体重計「00FatScale01」と BLE で通信して体重のデータを取得することに成功した。

[その１](http://qiita.com/ynakajima/items/261e53c8b4ecad7ec0df)に続き長くなってしまったので、取得した体重を Goole Fit へ自動的に登録するのは次の記事にて。


## 関連記事

* [3000円の Bluetooth 対応体重計を Raspberry Pi を使って Google Fit に対応させてみた その1](http://qiita.com/ynakajima/items/261e53c8b4ecad7ec0df)
* 3000円の Bluetooth 対応体重計を Raspberry Pi を使って Google Fit に対応させてみた その2


## 参考

* [GATT 特性](https://www.bluetooth.com/ja-jp/specifications/gatt/characteristics)
* [【BLEを使う】GATT（Generic Attribute Profile）概要](http://yegang.hatenablog.com/entry/2014/08/09/195246)

[^1]: なぜ体重管理が必要なのか立位でのデータをみてお分かりいただけたと思う