RESTでMySQLを操作する

ESP8266でJSONをパースする


ArduinoでJSONを扱うライブラリ(ArduinoJson)がこちらで公開されています。
このライブラリはArduino-IDEのライブラリマネージャーでインストールすることができます。


このライブラリはV5とV6で大きく仕様が変わりました。
使用したライブラリのバージョンはV6でAPIはこちらに 公開されていますが結構難解です。
JsonObject、JsonArray、JsonVariantの各オブジェクトの使い方を理解しないと使いこなせません。

[
  {
    "id": 1,
    "title": "JSON ServerでダミーAPIを作成",
    "time": 1351824120,
    "data": [
      1,
      2,
      3
    ]
  },
  {
    "id": 2,
    "title": "Vue.jsで基本機能を実装",
    "time": 1351824240,
    "data": [
      1.11,
      2.22
    ]
  }
]

この様なJSON文字列を解析する場合、ざっくり書くと以下の手順です。
・deserializeJson()で、JSON文字列をDynamicJsonDocumentに変換する
・doc.as<JsonObject>()で、DynamicJsonDocumentをJsonObjectに変換する
・リストの場合はJsonObjectからJsonArrayを取り出し、JsonArrayのn番目からJsonVariantを取り出す。
JsonVariantの中身は以下の構造になります。
  {
    "id": 1,
    "title": "JSON ServerでダミーAPIを作成",
    "time": 1351824120,
    "data": [
      1,
      2,
      3
    ]
  }

・非リストの場合は、JsonObjectからいきなりJsonVariantを取り出す。
JsonVariantの中身は上と同じです。
・取り出したJsonVariantから、項目ごとのJsonVariantを取り出し、変数の型に従って値を取り出す。
項目ごとのJsonVariantは例えばidの場合、以下の内容となります。
    "id": 1,

以下の部分は可変個数のリストアイテムになります。
こ ちらに解決方法が公開されていました。
    "data": [
      1,
      2,
      3
    ]



ESP8266を使ってJSON ServerからJSONフォーマットのデータを受信し、以下のコードでこのライブラリの動作を確認してみました。
/**
 * BasicHTTPClient.ino
 * HTTPClient+http.getStringでGetしたJSONデータを解析する
 */

#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h> // https://github.com/bblanchon/ArduinoJson

const char* ssid = "アクセスポイントのSSID";
const char* password = "アクセスポイントのパスワード";
const char* host = "JSON Serverが動いているホスト";

WiFiClient client;
HTTPClient http;

void httpPrint(int len, char buff) {
  char ch[2];
  ch[1] = 0;
  for(int i=0; i<len; i++) {
    ch[0] = buff;
    if (isAlphaNumeric(ch[0])) {
      Serial.printf("%c",ch[0]);
    } else if (strstr("\"!#$%&'()=-<> ;:/,.@[]+*{}",ch)) {
      Serial.printf("%c",ch[0]);
    } else if (ch[0] == 0x0a) {
      Serial.printf("\n");
    } else {
//      Serial.printf("0x%02x",ch[0]);
      Serial.printf("*");
    }
  }
}

void parseVariant(JsonVariant variant) {
  JsonVariant val_id = variant.getMember("id");
  int id = val_id.as<int>();
  Serial.print("id=");
  Serial.println(id);

  JsonVariant val_title = variant.getMember("title");
  const char * title = val_title.as<char*>();
  Serial.print("title=");
  Serial.println(title);

  JsonVariant val_time = variant.getMember("time");
  long time = val_time.as<long>();
  Serial.print("time=");
  Serial.println(time);

  JsonArray val_data = variant.getMember("data");
  //int arraySize =  val_data.size();
  Serial.print("val_data.size()=");
  Serial.println(val_data.size());
  for (int i = 0; i< val_data.size(); i++){
    double data = val_data[i];
    Serial.print("data[");
    Serial.print(i);
    Serial.print("]=");
    Serial.println(data);
  }
}



int parseJSON(String input) {
  DynamicJsonDocument doc(1024);
 
  //deserializeJson(doc, input);
  DeserializationError error = deserializeJson(doc, input);
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.c_str());
    return 0;
  }  
     
  Serial.print("measureJson=");
  Serial.println(measureJson(doc));

 
  JsonObject root = doc.as<JsonObject>();

  JsonArray array  = doc.as<JsonArray>();
  Serial.print("array.size()=");
  Serial.println(array.size());
  if (array.size() == 0) {
    JsonVariant variant = doc.as<JsonVariant>();
    parseVariant(variant);
  } else {
    for(int i=0; i<array.size(); i++) {
      JsonVariant variant = array[i];
      parseVariant(variant);
    }
  }
  return measureJson(doc);
}


void setup() {
  delay(1000);
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  DynamicJsonDocument doc(1024);
  Serial.println("[HTTP] begin...");
  http.begin(host, 3000, "/todos"); // list item
  //http.begin(host, 3000, "/todos/2"); // non list item

  Serial.println("[HTTP] GET...");
  // start connection and send HTTP header
  int httpCode = http.GET();

  // httpCode will be negative on error
  if(httpCode > 0) {
    // HTTP header has been send and Server response header has been handled
    Serial.printf("[HTTP] GET... code: %d\n", httpCode);

    // file found at server
    if(httpCode == HTTP_CODE_OK) {
      String input = http.getString();
      Serial.print("input.length()=");
      Serial.println(input.length());
      for(int i=0;i<input.length();i++) {
        httpPrint(1, (char)input[i]);
        delay(1);
      }
      Serial.println();
      parseJSON(input);
    }
  } else {
    Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
  }
  http.end();
}

void loop() {

}

JSON Serverから読み込んだリスト構造が正しく解析できています。
WiFi connected
IP address: 192.168.10.165
[HTTP] begin...
[HTTP] GET...
[HTTP] GET... code: 200
input.length()=282
[
  {
    "id": 1,
    "title": "JSON Server************API*********",
    "time": 1351824120,
    "data": [
      1,
      2,
      3
    ]
  },
  {
    "id": 2,
    "title": "Vue.js************************",
    "time": 1351824240,
    "data": [
      1.11,
      2.22
    ]
  }
]
measureJson=176
array.size()=2
id=1
title=JSON ServerでダミーAPIを作成
time=1351824120
val_data.size()=3
data[0]=1.00
data[1]=2.00
data[2]=3.00
id=2
title=Vue.jsで基本機能を実装
time=1351824240
val_data.size()=2
data[0]=1.11
data[1]=2.22

非リスト構造も正しく解析できています。
WiFi connected
IP address: 192.168.10.165
[HTTP] begin...
[HTTP] GET...
[HTTP] GET... code: 200
input.length()=116
{
  "id": 2,
  "title": "Vue.js************************",
  "time": 1351824240,
  "data": [
    1.11,
    2.22
  ]
}
measureJson=86
array.size()=0
id=2
title=Vue.jsで基本機能を実装
time=1351824240
val_data.size()=2
data[0]=1.11
data[1]=2.22

続く...