Mio FUSE+Device Connectでリアルタイム心拍数の計測と受信

# 概要
![システム構成図](https://qiita-image-store.s3.amazonaws.com/0/133133/da96d430-74cc-afa3-405a-3ef8cdd513d3.jpeg)

ウェアラブルウォッチ「mio FUSE」が計測するリアルタイム心拍数を、Device Web API ManagerによってWebサーバー化したAndroidデバイスを介し、WebSocketで受信する。

Device Web API Managerは「Device Connectシステムをスマートフォン上で実現するアプリケーション[^1]」で、これ
を用いることで、APIが公開されていないスマートデバイスでも、REST API / WebSocketで簡単にデータを取得することができる。

# 環境
- [Mio Fuse](http://www.mioglobal.jp/mio.html)
- Android 8.0.0
- [Device Web API Manager](https://play.google.com/store/apps/details?id=org.deviceconnect.android.manager&hl=ja) 2.3.0
- macOS 10.13.6 High Sierra
- Node.js 7.9.0
- [websocket-client](https://github.com/websocket-client/websocket-client) 0.53.0

# Mio FUSEとは
ウェアラブルウォッチ。心拍数を測ることができる。

- [mioとは？](http://www.mioglobal.jp/mio.html)
- [Mio FUSE｜よくあるご質問｜Mio｜ミオ日本公式サイト｜光学式心拍計&アクティビティデバイス](http://www.mioglobal.jp/mio-fuse.html)

![Mio FUSE](http://www.mioglobal.jp/images/mio_fuse.png)

# Device Web API Managerとは
Device Web API Managerは「Device Connectシステムをスマートフォン上で実現するアプリケーション[^1]」。

- [Device Web API Manager](https://play.google.com/store/apps/details?id=org.deviceconnect.android.manager&hl=ja)

# Device Connectとは
> Device Connectはスマートフォン上に仮想のHTTPサーバを立てて、それを介してスマートデバイス（Pebble、THETA、Hue、スマートグラスなどなど）をWeb APIで操作できるGotAPIの一実装です。

[Device Connectとは？](https://qiita.com/DeviceConnectUsers/items/dde3a48e77dae8c31c7a)


>NTT docomo社が中心となって開発、啓蒙している技術で、各種デバイスへの接続をDeviceConnectが行い、さらにその操作するAPIをWeb APIとして提供してくれるものです。スマートフォンの中にアプリケーションサーバが立ち上がるので、Web APIを使ってデバイスにデータを送ったり、逆に取り出せるようになります。

[hifive x DeviceConnectによるWoT体験ハンズオン！](https://hifive.connpass.com/event/81276/)

## 何が便利なのか
- スマートデバイスへのアクセスを抽象化してくれる。
- APIが公開されていないスマートデバイスでも、REST API / WebSocketで簡単にデータを取得したり、デバイスの操作ができる。

## DeviceConnectの情報
- [DeviceConnect Users](http://deviceconnectusers.github.io) - DeviceConnect WebAPIに関するドキュメントをまとめたページ
- [DeviceConnect-Docs Wiki](https://github.com/DeviceConnect/DeviceConnect-Docs/wiki) - Wiki。Device Connectの仕様はここで確認できる
- [DeviceConnect](https://github.com/DeviceConnect) - GitHub

# やってみよう

# Device Web API Manager
## インストールとビルド
1. Androidデバイスに[Device Web API Manager](https://play.google.com/store/apps/details?id=org.deviceconnect.android.manager&hl=ja)をインストール
1. [ビルドマニュアル](https://github.com/DeviceConnect/DeviceConnect-Android/wiki/HeartRateDevice-Build)に沿って、[HeartRateプラグイン](https://github.com/DeviceConnect/DeviceConnect-Android/tree/master/dConnectDevicePlugin/dConnectDeviceHeartRate)をビルド

プラグインがビルドされると、「MIO GLOBAL-FUSEアイコン」がトップページに表示される。
![Screenshot_20181015-190905.jpg](https://qiita-image-store.s3.amazonaws.com/0/133133/2f19e104-cc18-d3d6-fa6f-e6225b6a07ac.jpeg)

# Mio FUSEとAndroidデバイスをBluetooth接続
Androidデバイスに[Mio Go](https://play.google.com/store/apps/details?id=com.mioglobal.android.miogo&hl=ja)をインストールし、MioFuseとAndroidデバイスをBluetooth接続する。
接続に成功すると、「MIO GLOBAL-FUSEアイコン」が明るくなる。
![Screenshot_20181016-145437.jpg](https://qiita-image-store.s3.amazonaws.com/0/133133/6d153800-c86a-a26b-b0f8-f6c2e2916da4.jpeg)

## 設定
「トップページ」の右上から「設定」に進み、必要な設定をする。
一部の設定はDevice Web API Managerをオフにしないと変更できないので、オフにする。
変更を終えたら、再びオンにする。
![Screenshot_20181016-153736.jpg](https://qiita-image-store.s3.amazonaws.com/0/133133/72f09986-6792-ad47-976c-354e87fabf18.jpeg)

### 認証
「外部IPを許可」にチェック
「Local OAuth認証」「Origin有効化」のチェックを外し、無効にする(手順を簡略化するための、本記事固有の設定です)。
![](https://qiita-image-store.s3.amazonaws.com/0/133133/40952fb6-1c81-4f51-18bc-cc2930a7214e.jpeg)

## Host
「設定」に表示されたHostを控えておく。
![Screenshot_20181015-191131.jpg](https://qiita-image-store.s3.amazonaws.com/0/133133/ee6ef8db-230c-8b9e-fc6a-b7f1892ea6bd.jpeg)

## serviceId
「トップページ」→「MIO GLOBAL-FUSE」→「serviceinfomation」→「GET /gotapi/serviceinfomation/」
と進み、表示されたserviceIdを控えておく。
![Screenshot_20181015-193109.jpg](https://qiita-image-store.s3.amazonaws.com/0/133133/6b991147-5dae-d564-62a4-089dc67f6a83.jpeg)

# WebSocketで受信する
macOSデバイスからWebSocketでリアルタイム心拍数を取得する。
macOSデバイスとAndroidデバイスを、あらかじめ同じネットワークに接続しておく。

## 手順
[WebSocketについて - DeviceConnect Users](http://deviceconnectusers.github.io/websocket/)

上記ページにある手順を、簡潔にまとめた。

1. 接続
1. sessionKeyを送信
1. Web APIをコール
1. イベントの受信

これをNode.jsで実装したのが下のコードになる。

## Node.jsでの実装
[a-r-i/deviceconnect_websocket_nodejs](https://github.com/a-r-i/deviceconnect_websocket_nodejs) - GitHub

### WebSocket受信部分

```javascript:app.js
const WebSocket = require('ws');

const hostname = ''; //控えておいたHost
const ws = new WebSocket('ws://'+ hostname +':4035/websocket');
const sessionKey = 'test'; //sessionKeyはなんでもよい

ws.onopen = function () { //1.接続
    ws.send('{"sessionKey": "' + sessionKey+ '"}'); //2.sessionKeyを送信
    callWebAPI(sessionKey); //3.Web APIをコール
};

ws.onerror = function (error) {
    console.log(error);
};

ws.onmessage = function (message) { //4.イベントの受信

    try {
        var json = JSON.parse(message.data);
        var bpm = json['heart']['rate']['value'];
        console.log('BPM:' + bpm);
    } catch (e) {
        console.log('This doesn\'t look like a valid JSON: ',
            message.data);
        return;
    }

};
```

### WebAPIコール部分

```javascript:main.js
const http = require('http');

function callWebAPI(sessionKey) {
    const resource = 'health/onheart'; //心拍数APIのパス
    const serviceId = ''; //控えたserviceId

    const options = {
        host: hostname,
        port: '4035',
        path: '/gotapi/' + resource + '?serviceId=' + serviceId + '&sessionKey=' + sessionKey,
        method: 'PUT',
        headers: {
            'Content-Type': 'application/json'
        }
    };

    const req = http.request(options, function (res) {
        var responseString = '';

        res.on('data', function (data) {
            responseString += data;

            try {
                var json = JSON.parse(data);
            } catch (e) {
                console.log('This doesn\'t look like a valid JSON: ',
                    data);
                return;
            }

        });
        res.on('end', function () {
            return responseString;
        });
    });

    req.on('error', function (error) {
        console.log(error);
    });

    req.end();
}
```

### 参考文献
- [Node.js & WebSocket — Simple chat tutorial](https://medium.com/@martin.sikora/node-js-websocket-simple-chat-tutorial-2def3a841b61)
- [Send HTTP Requests To a Server with Node.js](http://shiya.io/send-http-requests-to-a-server-with-node-js/)

## 結果
![bpm.gif](https://media.giphy.com/media/jlrJDmSh1nWXwkjlpN/giphy.gif)

[^1]: [1. Term Definition · DeviceConnect/DeviceConnect-Docs Wiki](https://github.com/DeviceConnect/DeviceConnect-Docs/wiki/1.-Term-Definition)