bblanchon / ArduinoJson

📟 JSON library for Arduino and embedded C++. Simple and efficient.
https://arduinojson.org
MIT License
6.72k stars 1.12k forks source link

Slow deserialization with the ESP8266 on wifi #1301

Closed BenJSKM closed 4 years ago

BenJSKM commented 4 years ago

Hello Benoît, Thank you very much for your great library and very good book! I'm trying to use the ESP8266 to control the ADF4351 (VCO with integrated PLL). The following code compiles without errors and works. But the deserialization is very slow, the steps before happen instantly. It takes about 4 seconds to deserialize. This is to slow because I like to process multiple requests per second. I can't figure out what I'm doing wrong. I hope you help with this issue. Best regards, Ben

#include <ESP8266WiFi.h> // 2.7.1
#define ARDUINOJSON_USE_LONG_LONG 1
#include <ArduinoJson.h> // 6.15.2
#include <StreamUtils.h> // 1.4.0

const char* ssid = "test";
const char* password = "test";

WiFiServer server(80);
IPAddress ip(192, 168, 1, 99); // where xx is the desired IP Address
IPAddress gateway(192, 168, 1, 1); // set gateway to match your network

void setup() {
  Serial.begin(115200);
  delay(10);

  // Connect to WiFi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  IPAddress subnet(255, 255, 255, 0); // set subnet mask to match your network
  WiFi.config(ip, gateway, subnet); 
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // Start the server
  server.begin();
  Serial.println("Server started");

  // Print the IP address
  Serial.print("Use this URL : ");
  Serial.print("http://");
  Serial.print(WiFi.localIP());
  Serial.println("/");
}

void loop() {
  // Check if a client has connected
  WiFiClient client = server.available();
  if (!client) {
    return;
  }

  // Wait until the client sends some data
  Serial.println("New client");
  while(!client.available()){
    delay(1);
  }

  // Skip HTTP headers
  char endOfHeaders[] = "\r\n\r\n";
  if (!client.find(endOfHeaders)) {
    Serial.println(F("Invalid response"));
    return;
  }
  Serial.println("Skip headers");

  // {"Reg0": 4294967295,"Reg1": 4194338,"Reg2": 9502736,"Reg3": 0,"Reg4": 1,"Reg5": 253,"GIO1": 1}
  const size_t capacity = JSON_OBJECT_SIZE(7) + 40;
  StaticJsonDocument<capacity> doc;
  Serial.println("JSON doc");

  ReadBufferingStream bufferedFile{client, 32};
  Serial.println("Buffering");
  deserializeJson(doc, bufferedFile);
  Serial.println("Deserialize");

  unsigned long Reg0 = doc["Reg0"];
  unsigned long Reg1 = doc["Reg1"];
  unsigned long Reg2 = doc["Reg2"];
  unsigned long Reg3 = doc["Reg3"];
  unsigned long Reg4 = doc["Reg4"];
  unsigned long Reg5 = doc["Reg5"];
  unsigned long GIO1 = doc["GIO1"];

  Serial.print("Register 0: "); Serial.println(Reg0);
  Serial.print("Register 1: "); Serial.println(Reg1);
  Serial.print("Register 2: "); Serial.println(Reg2);
  Serial.print("Register 3: "); Serial.println(Reg3);
  Serial.print("Register 4: "); Serial.println(Reg4);
  Serial.print("Register 5: "); Serial.println(Reg5);
  Serial.print("GIO-port 1: "); Serial.println(GIO1);

  client.flush();
}
bblanchon commented 4 years ago

Hi @BenJSKM,

I was going to recommend the ReadBufferingStream, but I see that you're already using it. Did you notice an improvement when using the ReadBufferingStream? Did you try to increase the size of the buffer?

We need to know if the slowness comes from the Wifi connection or ArduinoJson. Can you try to read the entire response and then call deserializeJson()? Make sure to measure the duration of each operation.

Best regards, Benoit

BenJSKM commented 4 years ago

Hi Benoît, Thanks for your suggestion. First I read the entire reponse and then call deserialization. This solves the problem. The code I added is:

  char json[100];
  int i = 0;
  while (client.available()) {
    json[i] = client.read();
    i++;
  }
  i++;
  json[i] = '\0';

I don't know if this is the best way to do it, but it works. Best regards, Ben

bblanchon commented 4 years ago

Hi Ben,

You made me realize that ReadBufferingStream sometimes waits for a timeout when it shouldn't. I fixed it in this branch. It should now give a performance equivalent to the code above.

Please give it a try! I'm waiting for your feedback before merging the branch.

Best regards, Benoit

BenJSKM commented 4 years ago

Hi Benoît, It works very good. Thank you, Best regards, Ben