【IoT入門】スマホで加速度センサ値、位置情報を取得してクラウドに保存する

# マイコンとかセンサとかよく分からなくても楽しめるIoTを目指して・・・
最近[ニフティクラウドmobile backend](http://mb.cloud.nifty.com/about.htm)のハンズオンでIoTを扱うことが増えており、マイコン(Raspberry piやEdison)の使用したハンズオン検討していましたが難易度が高すぎ、初心者の方がついてこれなさそうで困っていました。
「マイコンやGPIOの配線などなど、電子工作と縁遠い人でもIoTを身近に感じ楽しめる内容を・・・」と考えたところ、多くの人が持っているスマホの「センサ」の値をクラウドに保存するコンテンツがよいのではないかと思いつき、今回のコンテンツを作りました。
内容をなるべく簡単にするため「HTML5」と「JavaScript」でスマホアプリの開発ができる「Monaca」を利用し「Andoridユーザー」でも「iPhoneユーザー」でも楽しめる内容としました。

# 完成物

今回の完成物は下記のような画面のもの「Start」を押下すると計測をスタートして空欄部分にセンサ値が表示される
「Stop」を押すと計測をやめ[ニフティクラウドmobile backend](http://mb.cloud.nifty.com/about.htm)にデータを保存する
![12178230_926433850768591_29557693_n.jpg](https://qiita-image-store.s3.amazonaws.com/0/55227/9e5a7d42-5707-4910-9edd-4881c859642a.jpeg)

# 完成物を作るまでの流れ
 ・monacaの利用登録
 ・プラグインの設定
 ・UIの作成
 ・加速度センサの値を取得コードの実装
 ・位置情報の値の取得コードの実装
 ・クラウドへ保存するコードの実装
 ・実装したコードを組み合わせる

# monacaの利用登録

下記の記事をご覧ください
[【IoTを実感しよう！】取得した温度センサのグラフをスマホでみよう！](http://qiita.com/fumishitan/items/cb4153a5fca8af1d49a7#monaca%E3%81%AE%E5%88%A9%E7%94%A8%E7%99%BB%E9%8C%B2)

# プラグインの設定

センサ値や[ニフティクラウドmobile backend](http://mb.cloud.nifty.com/about.htm)を簡単に使えるようにするため、プラグインを導入します。
monaca開発環境のヘッダーメニューの「設定」をクリックすると下記のようなメニューが出てくるのでその中でさらに赤丸部分をクリックします。
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/55227/32cd2142-3df0-d1d5-e842-213571b0aaa9.png)

すると下のようなプラグインの設定画面に移るのでその中で
　・DeviceMotion
　・Splashscreen
　・MonacaPlugin
  ・NiftyMB
の4つのプラグインを有効化します。

![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/55227/8602ca15-0127-d861-0b92-443acfc25d80.png)

以上でプラグインの設定は終了になります。

# UIの作成

それではUIを作成しましょう。UIはHMTLで下記のように記述します。

```html:index.html
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <link rel="stylesheet" href="components/loader.css">
    <link rel="stylesheet" href="css/style.css">
    <script src="components/loader.js"></script>
    <script src="js/ncmb.min.js"></script>
    <script src="js/app.js"></script>
</head>
<body>
    <p>Sensing Test</p>
    <form name="js">
    <table>
        <tr><td>acce_x:</td><td><INPUT type="text" size="80%" name="x"></td></tr>
        <tr><td>acce_y:</td><td><INPUT type="text" size="80%" name="y"></td></tr>
        <tr><td>acce_z:</td><td><INPUT type="text" size="0%" name="z"></td></tr>
        <tr><td>lat:</td><td><INPUT type="text" size="80%" name="lat"></td></tr>
        <tr><td>lng:</td><td><INPUT type="text" size="80%" name="lng"></td></tr>
    </table>
    </form>
<input id="start-button" type="button" value="Start" onclick="start()">
<input id="stop_button" type="button" value="Stop" onclick="stop()">
</body>
</html>
```

# 加速度センサの値を取得コードの実装

加速度センサの値を取得するには下記のコードを書きます。
また引数にあるonAcceSuccess, onAcceError, acceOptionsの3つのロジックを実装します

```js
var watchID = navigator.accelerometer.watchAcceleration(onAcceSuccess, onAcceError, acceOptions);
```
 
onAcceSuccessは値の取得が成功したときに実行されるロジックです
今回はUIの更新と、取得した加速度センサの配列化を行います。

```js
function onAcceSuccess(acceleration) {
        document.js.x.value=acceleration.x;
        document.js.y.value=acceleration.y;
        document.js.z.value=acceleration.z;
        var acce = [acceleration.x,acceleration.y,acceleration.z];
        acce_array.push(acce);
};
```

onAcceErrorは何らかの理由でセンサのデータが取得できなかったときに実行されるロジックです。
今回はメッセージをログとして出させます。

```js
function onAcceError() {
    console.log('onAcceError!');
};

```

acceOptions はオプション的に設定を行えるものです、今回は1秒間に1回センサデータを取得できるようするため、下記のように定義します。

```js
var acceOptions = { 
        frequency: 1000
};
```

# 位置情報の値の取得コードの実装

位置情報を取得するには下記のコードを書きます。
また引数にあるonGeoSuccess, onGeoError, geoOptionの3つのロジックを実装します

```js
navigator.geolocation.getCurrentPosition(onGeoSuccess, onGeoError, geoOption);
```

onGeoSuccessは値の取得が成功したときに実行されるロジックです
今回はUIの更新を行います。

```js
var onGeoSuccess = function(position){
    current = new CurrentPoint();
    current.distance = CurrentPoint.distance;   //検索範囲の半径を保持する    
    current.geopoint = position.coords; //位置情報を保存する
    document.js.lat.value=current.geopoint.latitude;
    document.js.lng.value=current.geopoint.longitude;
};
```

onGeoError は何らかの理由でセンサのデータが取得できなかったときに実行されるロジックです。
今回はメッセージをログとして出させます。

```js
var onGeoError = function(error){
    console.log("現在位置を取得できませんでした");
};
```

geoOptions はオプション的に設定を行えるものです、今回は1秒間に1回センサデータを取得、60秒でのタイムアウトを指定するため、下記のように定義します。

```
var geoOption = {
    frequency: 1000,
    timeout: 6000
};
```

なお、位置情報の取得では現在地を保持するクラスを作成する必要があるので下記のようにコーディングしておく

```js
function CurrentPoint(){
    geopoint=null;  //端末の位置情報を保持する
    distance=0;     //位置情報検索に利用するための検索距離を指定する
}
```

# クラウドへ保存するコードの実装

クラウドは[ニフティクラウドmobile backend(mBaaS)](http://mb.cloud.nifty.com/about.htm)を利用します、[この記事](http://qiita.com/fumishitan/items/8abae38db286138f23bf#mbaas%E3%81%AE%E5%88%A9%E7%94%A8%E7%99%BB%E9%8C%B2%E3%82%92%E8%A1%8C%E3%81%86)を参考に利用登録からアプリの作成までを行ってください

[ニフティクラウドmobile backend(mBaaS)](http://mb.cloud.nifty.com/about.htm)のJSSDKを利用するにはSDKを初期化する必要があります。それが下記のコードで行えます。

```js
 $(function(){
  //起動時にmobile backend APIキーを設定
    ncmb = new NCMB("YOUR_APP_KEY","YOUR_CLIENT_KEY");
});
```

実際にDBに保存するコードは下記になります。

```js
function save_ncmb(acce, lat, lng){
var Data = ncmb.DataStore("AcceleroMeter");
var data = new Data();

data.set("accelerometer", acce)
         .set("latitude",lat)
         .set("longitude",lng)
         .save();

}
```

# 実装したコードを組み合わせる

それでは実際に上記のコードたちを組み合わせましょう、それが下記になります。

```js:app.js
var YOUR_APP_KEY = "YOUR_APP_KEY";
var YOUR_CLIENT_KEY = "YOUR_CLIENT_KEY";
var ncmb;
var acce_array;
var flag;
var current;

 $(function(){
  //起動時にmobile backend APIキーを設定
    ncmb = new NCMB(YOUR_APP_KEY,YOUR_CLIENT_KEY);
    acce_array = new Array();
    acce_flag = new Boolean(false);

});

function start(){
    flag = true ; 
    var watchID = navigator.accelerometer.watchAcceleration(onAcceSuccess, onAcceError, acceOptions);
    navigator.geolocation.getCurrentPosition(onGeoSuccess, onGeoError, geoOption);
}

function stop(){
    flag = false;
    save_ncmb(acce_array,current.geopoint.latitude,current.geopoint.longitude);
    document.js.x.value=null;
    document.js.y.value=null;
    document.js.z.value=null;
    document.js.lat.value=null;
    document.js.lng.value=null;
}

function save_ncmb(acce, lat, lng){
var Data = ncmb.DataStore("AcceleroMeter");
var data = new Data();

data.set("accelerometer", acce)
         .set("latitude",lat)
         .set("longitude",lng)
         .save();

}

function onAcceSuccess(acceleration) {
    if(flag){
        document.js.x.value=acceleration.x;
        document.js.y.value=acceleration.y;
        document.js.z.value=acceleration.z;
        
        var acce = [acceleration.x,acceleration.y,acceleration.z];
        acce_array.push(acce);
    }
};

function onAcceError() {
    console.log('onAcceError!');
};

var acceOptions = { 
        frequency: 1000
};

var onGeoSuccess = function(position){
    if(flag){
    current = new CurrentPoint();
    current.distance = CurrentPoint.distance;   //検索範囲の半径を保持する    
    current.geopoint = position.coords; //位置情報を保存する
    document.js.lat.value=current.geopoint.latitude;
    document.js.lng.value=current.geopoint.longitude;
    }
};

var onGeoError = function(error){
    console.log("現在位置を取得できませんでした");
};

geoOption = {
    frequency: 1000,
    timeout: 6000
};


function CurrentPoint(){
    geopoint=null;  //端末の位置情報を保持する
    distance=0;     //位置情報検索に利用するための検索距離を指定する
}

```

これにて終了です。
今後グラフ化とか検討した方がいいかもな・・・
でも加速度と位置情報とかどうやって同じグラフにするか・・・