④ESP8266で取得したセンサ情報をM2xにアップロード

#はじめに
この記事は、電子工作の基礎からESP8266というWifi機能を持ったArduino互換の端末を使って取得した情報をM2Xという、センサ情報を受け取りグラフ表示してくれるクラウドサービスにセンサ情報をアップするところまでをカバーした記事です。
全部で４つの記事から構成されています。
①から順番にご覧ください。

①かんたんな回路を作って電子工作の基本を習得する 
http://qiita.com/windows222/private/6f11904f30ff540dcc37
②ESP8266(Arduino)に簡単なプログラムをアップする
http://qiita.com/windows222/private/c60d086a5909d2bff39e
③ESP8266で人感センサ情報を取得する
http://qiita.com/windows222/private/e6bcea0bef795c8cb30c
④ESP8266で取得したセンサ情報をM2xにアップロード （←本記事）
http://qiita.com/windows222/private/9d77cc3fe0094b78a4db

---

#記事概要
ここでは、前の記事で取得した人感センサの情報を、Wifiを通じてM2Xにアップします。
その後、アップされたM2Xの情報をグラフで確認してみます。

#M2xアカウント作成
##M2Xとは？
M2Xとは、IoT端末からRESTやMQTT等で送られる情報を受け取り、自動的にグラフを作成してくれるWEBサービスです。一日あたりのデータ受信件数に限りがありますが、無料で利用することができます。

##アカウント作成手順
アカウントの作成手順は下記の通りです。

**M2Xサイトにアクセス**
https://m2x.att.com/create-account

**必要情報を入力し、アカウントを作成**
画面右上のSign upをクリックし、必要情報を入力してアカウント情報を作成します。
(Githubアカウントがある場合は、情報の入力を省略できる）

**デバイスを作成**
アカウントの作成が完了したら、Create New > Create Deviceを選択し、必要情報を入力し、デバイスを作成します。
<img width="400" alt="rows_as_groups.png" src="https://qiita-image-store.s3.amazonaws.com/0/77722/5f783c62-1959-109e-06b3-c599f4441da3.png">

**（オプション）Curlでの動作確認**
実際にRESTリクエストを送信し、グラフが更新されることを確認します。RESTリクエストの送信は、curlが必要です（Linux)
作成が完了したら、ApicheetSheetというボタンをクリックします。表示された画面の中に``Updating a specific stream's current value``と書かれている箇所を探して、値をコピーします。
![image](https://qiita-image-store.s3.amazonaws.com/0/77722/cf6ba203-e5ea-9775-5ac4-fb7fd414f896.png)

コピーしたコマンドを実行して、結果を確認します。下記の様な文字列が返ってきたら成功です。

```:実行コマンド
curl -i -X PUT http://api-m2x.att.com/v2/devices/33d8824f9deee514852ee77258d74b42/streams/PIR_sensor/value -H "X-M2X-KEY: 7e7b47ba14a03597d6ad729c0313e4ae" -H "Content-Type: application/json" -d "{ \"value\": \"40\" }"
```


```:実行結果例
HTTP/1.1 202 Accepted
Content-Type: application/json; charset=UTF-8
Date: Sun, 18 Sep 2016 08:59:53 GMT
Server: nginx
Vary: Accept-Encoding
X-M2x-Version: v2.100.4
Content-Length: 21

{"status":"accepted"}192:~ nagase$ curl -i -X PUT http://api-m2x.att.com/v2/devi52ee77258d74b42/streams/PIR_sensor/value -H "X-M2X-KEY: 7e7b47ba14a03597d6ad729c0313e4ae" -H "Content-Type: application/json" -d "{ \"value\": \"40\" }"
HTTP/1.1 202 Accepted
Content-Type: application/json; charset=UTF-8
Date: Sun, 18 Sep 2016 08:59:58 GMT
Server: nginx
Vary: Accept-Encoding
X-M2x-Version: v2.100.4
Content-Length: 21
```


**デバイスIDの取得**
情報入力後、画面にデバイスIDが表示されるので、PRIMARY ENDPOINTとPREIMARY API KEYの２つを記録します。（後で再度表示することも可能）
<img width="400" alt="rows_as_groups.png" src="https://qiita-image-store.s3.amazonaws.com/0/77722/9596c427-568e-f032-7dc8-d35114e128f2.png">

#Wifi接続情報の入手
次に、ESP８２６６をWifiに接続するための環境の設定、情報を入手します。
必要となるのはwifiのSSIDとパスワードの２つです。
（Wifi環境がない場合、携帯のテザリングでも構いません。）

#プログラム修正
③で作成したプログラムに、---ここから----, ---ここまで----の間のプログラムを追加します。
最後に、loop()の中を同じように更新します。

```c:
#include <Arduino.h>
#include <stdio.h>
#include <string.h>

#include <ESP8266WiFi.h>

#define PIR_MOTION_SENSOR 4  //人感センサを示す番号
#define GREEN_LED  15  //緑のLEDを示す番号（１５番ピンに接続）

int loopCount = 0; //現在のループ数
int detectedCount = 0; //人感センサの検知回数


 //------ここから↓----------
// Use WiFiClient class to create TCP connections
WiFiClient client;
WiFiClient m2xClient;

int requestFreq = 10; //サーバへの更新頻度
const char* ssid     = "NAGA12345"; //★接続するWifiのSSID
const char* password = "nagase222"; //★接続するWifiのパスワード
const char* m2xHost = "api-m2x.att.com"; //接続するホストのアドレス
String m2xKey = "7e7b47ba14a03597d6ad729c0313e4ae";//★M2Xに接続する為のKey
String m2xURL =  "/v2/devices/33d8824f9deee514852ee77258d74b42/streams/PIR_sensor/value";//★デバイスを示すURL
const int httpPort = 80;//ポート番号

/*
 * Wifiに接続する
 */
void startWIFI() {
  Serial.println("starting wifi");
  WiFi.begin(ssid, password);

  int failedcount = 0;
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    failedcount++;
    Serial.println("Connection Failed! retriying.");
    delay(2000);
    if (failedcount >= 5) {
      Serial.println("Connection Failed! Rebooting...");
      ESP.restart();
    }
  }
  Serial.println("M2xに接続します");
  //M2Xサーバに接続する
  if (!client.connect(m2xHost, httpPort)) {
    Serial.println("接続に失敗しました。");
  }
}

/**
   M2xにデータを送信する
 * */
void submitToM2X(int PIRNumber, int returnValue) {

  if (returnValue >= 1) {  //検出数が０でない場合は送信対象とする
//m2xサーバーに接続する
    if (!m2xClient.connect(m2xHost, 80)) {
      Serial.println("connection failed 1");
      delay(1000);
   
    }
    //M2xにデータを送信する
    m2xClient.print("PUT " + m2xURL + " HTTP/1.1\r\n" +
                    "Host: " + m2xHost + "\r\n" +
                    "User-Agent: curl/7.43.0\r\n" +
                    "Accept: */*\r\n" +
                    "X-M2X-KEY: " + m2xKey + "\r\n" +
                    "Content-Type: application/json\r\n" +
                    // "Connection: close\r\n" +
                    "Content-Length: 17\r\n\r\n" +
                    "{ \"value\": \"" + returnValue + "\" }\r\n");

    Serial.printf("sent %d to the m2x server\n", returnValue);
    String response = m2xClient.readString();
    Serial.println(response);
  } else {
    Serial.println("値が0なのでM2xには送信しません");

  }
}
//-----↑ここまで-----------

/**
   LEDを点滅させる
*/
void blinkLED(int pinNo, int waitTime, int repertCount) {
  for (int i = 0; i <= repertCount; i++) {
    digitalWrite(pinNo, HIGH);
    delay(waitTime);
    digitalWrite(pinNo, LOW);
    delay(waitTime);
  }
}
/**
 * 人感センサの情報をチェックし、現在の検知状態を調べる。
 */
boolean isPeopleDetected(){
  int sensorValue = digitalRead(PIR_MOTION_SENSOR);
  if (sensorValue == HIGH){ //検知状態
    return true;  //yes,return ture
  }
  else if(sensorValue == LOW){  //未検知状態
    return false;  //no,return false
  }
}

/*
 * 人感センサをチェックし、結果をコンソールに出力
 */
void sensePIR() {
  loopCount++;
  int returnValue = 0;
  
  //センサの状態を調べて、周りに人がいるかをチェック
  if (isPeopleDetected()==true) { //人がいたら 
    digitalWrite(GREEN_LED, HIGH); //人感センサ検知したらLED点灯
    detectedCount++;
    Serial.printf("PIR1:find someone! loopCount=%d detectedCount=%d\n",loopCount,detectedCount);
  }
  else {        //人がいなかったら
    digitalWrite(GREEN_LED, LOW); //人感センサ検知なければLED消灯
    Serial.printf("PIR1:no one can find..loopCount=%d \n", loopCount);
  }
}

/**
 * 準備開始（最初に呼ばれる関数）
 */
void setup(){
  Serial.begin(115200);//シリアルポートを通信速度115200で開始
  Serial.println("start setup");
  
  pinMode(PIR_MOTION_SENSOR, INPUT); //ピンを入力状態にセット
  pinMode(GREEN_LED, OUTPUT); //ピンを出力状態にセット
  
  Serial.println("end of setup");
}

/**
 * セットアップの後に連続して呼ばれる
 */
void loop(){
  //人感センサの情報を取得
  sensePIR();
  delay(1000);

  if (loopCount >= requestFreq) { //送信頻度を超えたら実行
    //wifiに接続
    startWIFI();
    delay(1000);
    //m2xに検出数を送信
    submitToM2X(1, detectedCount);
    //ループカウントをリセット
    loopCount = 0;
    //検知数をリセット
    detectedCount = 0;
  }
}
```


#動作確認
書き換えが完了したら、プログラムを動かす。
下記のようなメッセージが表示されたら、情報のアップが成功している。
<img width="696" alt="6495AC35-8E1F-4755-9E18-BB87EE079841.png" src="https://qiita-image-store.s3.amazonaws.com/0/77722/ea0f7e3b-d793-2bc7-4cc3-f91b466d29d1.png">

#結果確認
M2Xにアクセスし、結果がグラフとして表示されることを確認する。
![image](https://qiita-image-store.s3.amazonaws.com/0/77722/8bbe36f5-b8e1-7469-39cb-3649c0bc4bb3.png)

#電池で動かす
これまでは、USBからの電源を使ってESP8266を動かしていましたが、電池で動作させることも可能です。
下記の手順で試してください。
・ESP８２６６をPCから外し、電池を接続する。
・スイッチをBootに切り替えてRESETボタンを押す。
・M2Xをみて、M2Xに情報がアップされていることを確認する。


#応用/参考情報

###単３電池２本使った場合の稼働時間はどのくらい？
単３電池２本で動かし続けた場合、どのぐらい連続動作が可能なのかを計算してみる。

***ESP8266の消費電力***
Wifi接続時 3v 80mA
Wifi切断時 3v 30mA
***単３電池２本の容量***
3v 2000mA
***持ち時間(答え）***
2000mA(x3v)÷80mA(x3v)=25時間

電池の持ち時間の計算方法について詳細に知りたい場合はコチラを参照してください。
http://qiita.com/windows222/items/1f4834cecb63f578877c


###単１電池で動かした場合は？

単１電池の容量は、単３電池の６．５倍
https://note.mu/a_hisano/n/na87bcca3f0c4
答え
25x6.5 = 162.5 = 約１週間

##もっと長く動かしたい場合は？
もっと長く動作させたい場合は、スリープモードを利用することで更に長く動作させることも可能です。
例えば気温や気圧を調べる場合、センサの情報は５分〜１０分に一度の情報で十分です。その場合、センサの情報を取得→データをサーバにアップ→スリープ（１０分）を繰り返せば、１ヶ月以上の連続動作が可能となります。
（スリープ中の消費電力は１０uAと非常に低い）
http://qiita.com/azusa9/items/65a5c3772c41631b5ca1

##センサを変える
本記事では人感センサを利用しましたが、光センサ、圧力センサ、音センサなど、センサを付け替えることで様々な情報の取得が可能です。取得したい情報に応じて、センサーを変えるだけで様々な情報の取得が可能となります。

#まとめ
・本日学んだことを応用することで、様々なセンサの情報をインターネットに保管し、グラフ化する仕組みを簡単につくれる
・ESP8266は安価で、高機能で、扱いやすい端末

#応用課題
・光センサを取り付け、取得した情報をM2Xにアップしてみましょう。（上級編）
　＞http://qiita.com/windows222/private/8649eb7c96a6429c4a9a