Xivelyでセンサデータなどのリアルタイムなチャートを作る

  • 40
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

概要

センサデータと天気APIのデータを集積してリアルタイムチャートを作る。

Xively

Xivelyはデバイスデータなどを集約管理するためのプラットフォーム。

  1. ユーザー登録する。
  2. DevelopからAdd Deviceする。
  3. API KeyFeed IDをメモる。

無料だとデバイス数などに制約があった気がするが、今回は1デバイスにまとめてデータ送信しているのでとりあえず足りている。

センサ

回路はそれぞれ簡単なので割愛(気になる人は聞いてください)。

無線

XBee Wi-Fiを使う場合は以下の設定を行う。

  • destination : nslookup api.xively.comして64.94.18.120
  • port : 0x50(=80)

センサデータの送信

Arduinoのスケッチを書く。C++苦手…
温湿度センサーは以前使ったがややデータの読み取りが難しい。DHTのライブラリを使う。

sensors.ino

#include <DHT.h>

#define DHTTYPE DHT22
#define DHT22_PIN 7
DHT dht(DHT22_PIN, DHTTYPE);


int napionAnalogPin = A0;
int illuminancePin  = A1;
int microphonePin   = A2;
int napion10mPin    = 6;
int interval        = 3; //sec
int loopCount       = 100;

String moduleId = "0001";

String feedId = "YOUR_XIVELY_FEED_ID";
String apiKey = "YOUR_XIVELY_API_KEY";
String reqHeader;

void setup() {
  Serial.begin(9600);
  pinMode(napionAnalogPin,    INPUT);
  pinMode(illuminancePin, INPUT);
  pinMode(microphonePin,  INPUT);  
  pinMode(DHT22_PIN,      INPUT);      
  pinMode(napion10mPin,      INPUT);      

  reqHeader = "PUT /v2/feeds/" + feedId +" HTTP/1.1\r\n" + "X-ApiKey: " + apiKey + "\r\n"+"host: api.xively.com\r\n";

}

int illuminanceValue = 0;
int microphoneValue = 0;

void loop() {
  int illuminanceValueMax = 0;
  int microphoneValueMax = 0;

  long napionAnalogValue = 0;
  long napion10mValue = 0;

  for (int sec=0; sec<interval; sec++) {
    for (int j=0; j<loopCount ; j++) {
      delay(10);
      illuminanceValue = analogRead(illuminancePin);
      if (illuminanceValueMax < illuminanceValue) {
        illuminanceValueMax = illuminanceValue;
      }
      microphoneValue = analogRead(microphonePin);
      if (microphoneValueMax  < microphoneValue) {
        microphoneValueMax  = microphoneValue;
      }

      napion10mValue += digitalRead(napion10mPin);
      napionAnalogValue += analogRead(napionAnalogPin);
    }
  }
  float napion10mValueAvg    = 1.0*napion10mValue   /interval/loopCount;
  float napionAnalogValueAvg = 1.0*napionAnalogValue/interval/loopCount;
  char napion10mValueAvgChar[10];
  char napionAnalogValueAvgChar[10];
  dtostrf(napion10mValueAvg,    6, 2, napion10mValueAvgChar);
  dtostrf(napionAnalogValueAvg, 6, 2, napionAnalogValueAvgChar);


  float h  = dht.readHumidity() ;
  float t  = 5.0/9.0*(dht.readTemperature(true)-32.0); // fahrenheit -> celsius
  char ch[10];
  char ct[10];
  dtostrf(h, 6, 2, ch);
  dtostrf(t, 6, 2, ct);

  // HTTP request
  Serial.print(reqHeader);

  String httpBody =  "{\"version\":\"1.0.0\",\"datastreams\" : [  \r\n";
  httpBody.concat(  tuple("napion10m",       String(napion10mValueAvgChar))        + ","        );
  httpBody.concat(  tuple("napionAnalog",    String(napionAnalogValueAvgChar))     + ","        );
  httpBody.concat(  tuple("microphone",      String(microphoneValueMax))    + ","        );
  httpBody.concat(  tuple("humidity",        String(ch))                    + ","        );
  httpBody.concat(  tuple("temperature",     String(ct))                    + ","        );
  httpBody.concat(  tuple("illuminance",     String(illuminanceValueMax))   + " ] }" );

  Serial.print("Content-Length: " + String(httpBody.length()) + "\r\n\r\n");
  Serial.print(httpBody);  

}

String tuple(String channel, String value) {
  return "{\"id\":\"" + channel + moduleId + "\",  \"current_value\" : \"" + value + "\"}";
}

APIデータの送信

センサを室内に設置したが、公開されている外気温もpostしてみる。
World Weather OnlineのAPIを使う。API keyを取得したら以下のようなコマンドをサーバーのcronにでも登録する。データの更新間隔は30分程度なので実行間隔もそれくらいでよいだろう。
ちょっとダサいがpost内容を1回ファイルに吐いている。
JSONの整形はjqを使っている。

curl "api.worldweatheronline.com/free/v1/weather.ashx?q=Tokyo&format=json&num_of_days=1&key=YOUR_WEATHER_API_KEY" | ~/bin/jq  ' { "datastreams": [ { "id": "temp_tokyo", "current_value": ( .data.current_condition[0].temp_C ) } ] }' > /tmp/temp_tokyo; curl https://api.xively.com/v2/feeds/YOUR_XIVELY_FEED_ID -X PUT -H "X-ApiKey: YOUR_XIVELY_API_KEY" --data @/tmp/temp_tokyo

結果

XivelyでFeedをクリックすると送られているJSONを確認することができる。

{
  "version": "1.0.0",
  "datastreams": [
    {
      "id": "napion10m0001",
      "current_value": "  0.37"
    },
    {
      "id": "napionAnalog0001",
      "current_value": "497.49"
    },
    {
      "id": "microphone0001",
      "current_value": "396"
    },
    {
      "id": "humidity0001",
      "current_value": " 52.60"
    },
    {
      "id": "temperature0001",
      "current_value": " 27.60"
    },
    {
      "id": "illuminance0001",
      "current_value": "225"
    }
  ]
}

idごとに以下のようなグラフが勝手にできてリアルタイムに更新されていく。とりあえずのトレンド確認としては便利。

外気温

更新間隔が粗いが人のデータなので仕方ない。

室温

人の出入りがある間は動きが激しい。あと空調のon/offも現れている。

室内湿度

冷房を切った時に湿度も上がっている気がするが、換気が切れたからか発汗によるものか。

明るさ

暗いほうが値が高い(後々回路を直したい)。夜に段階的に照明が落ちるのと、朝日の日照が徐々に増えていくのが現れている。

人の出入りや会話に反応。

赤外線(アナログ)

人の動きに反応。

赤外線(デジタル)

3秒間の平均をとっている。デジタルのデータでもアナログっぽく使える気がする。高価なアナログ型を使う理由は減る。

感想

データ送信頻度

Xivelyのrequest間隔をどの程度にしようか迷ったが、1デバイスでかつ3秒程度なら全く問題ない。デバイスが増えた場合は分からない。

時刻

センサ取得したデータをすぐに送っているが、タイムスタンプをつけて後でまとめて送るとなるとNTPからの現在時刻の取得が必要。エラー処理や再送など総合的に考えるとRaspberry Piなどのほうが有利かも?

展望

いったん蓄積したデータのAPIによる取得もできそうなので別のフロントエンドや分析プラットフォームにつなぐなどやってみたら面白そう。

参考