スポンサーリンク

ESP32 Arduinoで Ambientからデータを取得して得られたJSONをパースして値を抽出する方法

スポンサーリンク

スポンサーリンク

Ambientからデータを取得する

Ambientは、ネットワークにつながったセンサ端末からの情報を受けとり、グラフ化してくれるクラウドサービスです。

見守りをするため、M5StickCでベッドの重量を測定し、Ambientに送信するハードとソフトを作りました。

次のステップに進むために、逆にAmbientにあるデータを端末側から参照したくなったので、Arduinoでプログラムを作ってみました。

仕組み

ambientからデータを取得するには、次のURLをambientのサーバに送ります。するとデータがJSON形式で返ってきます。

http://ambidata.io/api/v2/channels/チャネルID/data?&readKey=リードキー&n=行数

「チャネルID」と「リードキー」はMyチャネルのページで確認できます。

行数は1以上の数字を指定します。1を指定すると直近のデータが1セット、nを指定すると直近から過去へn番目までデータ、nセット分が返ってきます。

ちなみに、上記のURLをブラウザで開くと、データが返ってくることが事前にわかります。

上記はn=1とした場合の結果です。直近のデータが1つ表示されます。

n=2にすると、以下のように2セットデータが返ってきます。

さて、仕組みがわかったところで、これをコードにします。

データを取得するプログラム

...
#include <HTTPClient.h>
const unsigned int channelId = xxxxx; // AmbientのチャネルID
const char* readKey = "xxxxxxxxxxxxx"; // リードキー
...

void setup() {
  ...
  Serial.begin(115200);
  ...
  // ...WiFiに接続する...

}

void loop() {
  ...
  String response = readFromAmbient( channelId, readKey, 1 );
  delay(10000);
  ...
}

//Ambientからデータを受信する
String readFromAmbient( unsigned int channelId, const char* readKey, int n )
{
  const String host ="ambidata.io";

  String url = "http://";
  url += host;
  url += "/api/v2/channels/";
  url += channelId;
  url += "/data?&readKey=";
  url += readKey;
  url += "&n=";
  url += n;
  Serial.print("Requesting URL ");
  Serial.println(url);

  HTTPClient httpClient;
  httpClient.begin(url);
  int httpCode = httpClient.GET();
  String httpResponse = httpClient.getString();
  httpClient.end();

  Serial.printf("httpCode:%d\n",httpCode);
  Serial.println(httpResponse);

  return httpResponse;
}

上記は、必要な部分を抜き出したコードです。これの他に、WiFiにつなぐコードが必要です。

Ambientのサーバからデータを受信するための、readFromAmbient()という関数を作りました。チャンネルIDとリードキー、行数nを指定すると、JSON形式のStringが得られます。

スポンサーリンク

M5StickCで受信してみる

サンプルプログラム

先ほどのコードを、M5SticCで動くようプログラムしました。こちら↓↓がそのプログラムです。

m5stick_readDataFromAmbient

//Wifi
const char* WifiSSID = "SSID"; //アクセスポイントのSSID
const char* WifiPassword = "POSSWORD"; //アクセスポイントのパスワード
WiFiClient client;

//Ambient
unsigned int channelId = CHANNEL_ID; // AmbientのチャネルID
const char* writeKey = "WRITE_KEY"; // ライトキー
const char* readKey = "READ_KEY"; // リードキー
Ambient ambient;

上記の部分の、WifiSSID、WifiPasswordに、ご自宅のWiFiのSSIDとパスワードを指定し、channelId、writeKey、readKeyはAmbientのそれぞれのID、キーを指定します。

コンパイルしてM5StickCに書き込むと、プログラムが実行されます。Aボタンを押すと、Ambientからデータを受信し、ボタンBを押すと、Ambientに予め設定されているValue1,2,3のデータが送信されるようになっています。

実行結果

WiFiに接続された後に、Aボタンを押すとシリアルモニタに結果が表示されます。

[{“d1″:1,”d2″:2,”d3″:10,”created”:”2019-10-09T04:52:08.689Z”}]

n=1としたので、1行分のデータが返ってきました。

M5Stickの画面にも、シリアルで出力したデータが表示されます。

スポンサーリンク

ArduinoJSONでパース

Ambientからデータを受信できるようになりました。この結果をArduinoJSONを使ってパースして、パラメータを取り出してみたいと思います。

ArduinoJSONは、ライブラリマネージャで検索すると出てきます。これをインストールしておきます。

私が使ったのは現時点で最新のバージョン6.12.0です。

先ほどのコードに、ArduinoJSONでパースして、値を取り出すコードを追加します。

...
#include <ArduinoJson.h>
...

void setup() {
  ...
}

void loop() {
  ...
  //Aボタンを押されたら
  ...
    String response = readFromAmbient( channelId, readKey, 1 );
  
    //jsonドキュメントの作成 make JSON document
    const size_t capacity = 500;
    DynamicJsonDocument doc(capacity);
    DeserializationError err = deserializeJson(doc, response);
    Serial.printf("DeserializationError:%s\n",err.c_str());
  
    //抽出
    int value[3] = { 0, 0 ,0 };
    value[0] = doc[0]["d1"];
    value[1] = doc[0]["d2"];
    value[2] = doc[0]["d3"];
  
    //結果を出力
    Serial.printf("Result:%d, %d, %d\n",value[0],value[1],value[2]);
    M5.Lcd.print("Value1:"); M5.Lcd.println(value[0]);
    M5.Lcd.print("Value2:"); M5.Lcd.println(value[1]);
    M5.Lcd.print("Value3:"); M5.Lcd.println(value[2]);    
  ...
}

JSONドキュメントを作るときのcapacityは、ArduinoJson Assistantに受信したJSONのデータ列をペーストして、計算された容量を使用します。

今回はn=2の受信結果で244だったので、さらに余裕をみて500にしてみました。

M5Stickで実行してみましょう。

Value1:1
Value2:2
Value10:10

と、JSONフォーマットから正しく値が抽出できています。

プログラムはこちらm5stick_readDataFromAmbient2にあります。

スポンサーリンク

まとめ

M5StickCでAmbientからデータを取得できるようになりました。取得したJSONフォーマットから、データを抽出できるようになりました。

これで、センサ端末からでもデータにアクセスできるようになりました。

つづく

2019.10.10 追加 つづきはこちらです↓↓

追加終わり

コメント

  1. 初めまして。コメント失礼します。
    ESP32 ArduinoでAmbientからデータを読み込む方法を調べていてこちらにたどり着きました。
    このコメント欄で質問をさせていただいてもよろしいでしょうか?
    Ambientからデータを読み込むときに、直近のデータからではなく古いものから読み込むことはできますか?
    不躾な質問で申し訳ありませんが、もしご存知でしたら教えていただけますでしょうか?

    • 310suzuki様
      コメントありがとうございます。
      新しい順にしかデータは取り出せないようです。
      あまり現実的では無いかもしれませんが、保存されているデータ数がわかっているとすると、skip=mを使うことで、m個前のデータを取り出すことができます。
      http://ambidata.io/api/v2/channels/チャネルID/data?&readKey=リードキー&n=1&skip=10
      とすると、10個前のデータを1セット取り出すことができます。ブラウザにペーストして試してみてください。

      • kohapepe様
        急な問い合わせにもかかわらず、早急にご返信いただきありがとうございます。
        何度も質問してすみません。まだAmbientにデータを送れていないため確認することができないのですが、リードキー&の後ろをdate=’YYYY-mm-dd’にすれば日付を指定することもできますか?(Ambient公式サイトのPythonライブラリーを参照しました)

        • http://ambidata.io/api/v2/channels/***/data?&readKey=***&date=%27YYYY-MM-DD%27
          で試したところ、その日のデータが取得できました。ただn=1とデータ数を指定しても無視され、その日に記録された全てのデータが返ってきてしまいますね。
          データに含まれる記録時の日時はGMTなので日本時間にするには+9時間する必要があります。
          また、開始日時と終了日時と指定してデータを取得するstartとendというコマンドもあるみたいなので試してみましたが、私の環境の場合タイムアウトしてしまい、正常にデータを取得できませんでした。

          • ありがとうございます。とても参考になりました。
            何度も質問に答えていただきありがとうございました。

          • こちらこそ参考にして頂き嬉しいです。ぜひ楽しんでさい。

  2. Ambientへの送信は出来ましたが、受信の方法がわからずにいました。
    大変有益な情報が得られました。
    どうもありがとうございます。

    • コメントありがとうございました。
      お役に立てて嬉しいです。

  3. こんにちは。いつも読ん勉強しているものです。なかなか勉強しても自分なりのアイデアを
    プログラムに展開して、実用的な活用までには、まだまだ時間がかかりそうです、そこで先生にアイデアをm5stickc用にプログラム書いてもらいたい。その様な事は、可能でしょうか?内容はえぶちゃんわんちゃんの記述とほぼ同じです。可能でしたら、料金はどの位になるのでしょうか?
    宜しくお願い申し上げます。

    • 市村様 ブログを読んで頂き、またありがたいコメントを頂きましてありがとうございます。しかしながら、ただいま立て込んでおりまして、しっかりとシステムを構築するお時間を割くことが難しい状況です。もしよろしければ今回のM5StickCのプログラムを、無保証ですがお渡しすることができます。また、これをベースに多少修正することであれば、有償でお手伝いすることは可能です。少しでもお役に立てれれば幸いです。
      今後ともよろしくお願いいたします。