bblanchon / ArduinoJson

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

Send Json data from client to server #1245

Closed lcfelippe closed 4 years ago

lcfelippe commented 4 years ago

Hi bblanchon,

how can i send a serialized json data to a server(esp8266)?. Can you help me with it?

Thanks for the good job on ArduinoJson.

Regards,

lcfelippe.

bblanchon commented 4 years ago

Hi @lcfelippe,

Please look at:

Best regards, Benoit

lcfelippe commented 4 years ago

bblancon, Thank you for your reply...

I have already tried this examples, but in this case the server send json data to a client. I need that the client read all the sensors and send json to a server. Maybe it's easy to do, but I'm newbie on http protocols.

Can you help me, how to make this?

Regards,

lcfelippe.

bblanchon commented 4 years ago

Hi @lcfelippe,

Please see:

Best regards, Benoit

lcfelippe commented 4 years ago

Thank you for your patience.

I have no doubts about how to serialize or deserialize the json. My only problem is how to send it from client to server.

Regards,

lcfelippe.

bblanchon commented 4 years ago

@lcfelippe, the serialization tutorial shows how to POST the data to a Web service. What else do you need?

lcfelippe commented 4 years ago

@bblanchon, i need to know how can i prepare the server to receive the Json data. My project is a Weather Station that collect data and send it to wunderground. Now, i would like to serialize this data and send it to a Esp8266 (server) to display the weather information on ILI9341TFT Display.

Below a example of my serialized data:

{"Weather":"Sensors","Date":{"Day":165,"Month":165,"Year":2165,"Weekday":"Monday"},"Time":{"Hour":165,"Minute":165,"Second":85},"WiFi":{"WiFi Signal Strenght":45},"BME280":{"Temperature":0,"Humidity":0,"DewPoint":0,"Pressure":0,"Pressure Equivalent":0},"VEML-6075":{"UVA":0,"UVB":0,"UV Index":0},"PMS 5003":{"Last Read Sample":{"PM 1.0":0,"PM 2.5":0,"PM 10":0},"Total of 24hs PM 2.5":0,"Average of 24hs PM 2.5":0,"PM 2.5 AQI":0,"Air Quality PM 2.5":"","Total of 24hs PM 10":0,"Average of 24hs PM 10":0,"PM 10 AQI":0,"Air Quality PM 10":"","Air Quality Comparison":""},"Rain Bucket":{"Rain Rate":0,"Rain Total":0},"Wind":{"Speed":0,"Direction Cardinal":"","Direction Degrees":0},"Circuit Temperature":{"Circuit":0,"Battery 1":0,"Battery 2":0}}

bblanchon commented 4 years ago

Hi @lcfelippe,

I don't have a ready-made example of an HTTP server that deserializes a JSON document from the request body. However, you can easily build from the two following examples:

Combining the two programs should be fairly easy.

Best regards, Benoit

lcfelippe commented 4 years ago

Hi @bblanchon,

I don't have good skills with HTTP protocols, therefore the examples didn't help me to solve my necessity. I'll try to manage the data between the Esp8266 using a 433Mhz transmitter and send a structure instead of the Json data.

struct sensor { float temp; float pressure; float humidity; };

Thank you for the help. 👍

ewaldc commented 4 years ago

@lcfelippe, As your client will submit the data to your server you need to use HTTP POST (or PUT) requests from the client side, rather than GET commands. You can follow these examples:

First, you need to settle on an URI where the client will post the JSON data and the server will accept it e.g. "_/rest/postdata" Then on the client code change the line accordingly to the chosen URI http.begin(client, "http://"<SERVER_IP>"/postplain/"); //HTTP to http.begin(client, "http://<SERVER_IP>/rest/post_data"); //HTTP Change to your web server address

On the client side, also change the line of code int httpCode = http.POST("{\"hello\":\"world\"}"); to your serialized json. You can build your JSON data by simple string concatenation of keys and values.

On the server side, change these lines of code:

  server.on("/inline", []() {
    server.send(200, "text/plain", "this works as well");
  });

to

server.on("/rest/post_data", []() {
if (server.hasArg("plain")== false){ //Check if body received
    server.send(400, "text/plain", "Bad request: body not received");
} else { // we received a body, hopefully our JSON data
    String message = server.arg("plain");
    message += "\n";
    // Allocate the JSON document
    // Use arduinojson.org/v6/assistant to compute the capacity.
    const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60;
    DynamicJsonDocument doc(capacity);

    // Parse JSON object
    DeserializationError error = deserializeJson(doc, message);
    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.c_str());
      return;
    }
    // incorporate the parsing of your JSON data as per the [JsonHttpClient.ino](https://arduinojson.org/v6/example/http-client/) example
}
}

Get rid of other server.on() pieces of code, unless you want to extend your web server to serve more requests...

There is a good tutorial here

Good luck... Ewald

lcfelippe commented 4 years ago

Hi @ewaldc, Thank you for the examples, and for the instructions to modify the code.

The only issue is that the Client only send the Json data to a server once. To send it again i have to reboot the client.

After read all sensors i have the code below on void loop

buffer was declared as global variable (String).

Code:

void loop(){
.
.
.

DynamicJsonDocument weather(2048);

  weather["Weather"]= "Sensors";
  weather["Date"]["Day"] = now.day();
  weather["Date"]["Month"] = now.month();
  weather["Date"]["Year"] = now.year();
  weather["Date"]["Weekday"] = daysOfTheWeek[now.dayOfTheWeek()];
  weather["Time"]["Hour"] = now.hour();
  weather["Time"]["Minute"] = now.minute();
  weather["Time"]["Second"] = now.second();
  weather["WiFi"]["WiFi Signal Strenght"] = Signal_Strength;
  weather["BME280"]["Temperature"] = tempc;
  weather["BME280"]["Humidity"] = humidity;
  weather["BME280"]["DewPoint"] = dewpointc;
  weather["BME280"]["Pressure"] = pressure;
  weather["BME280"]["Pressure Equivalent"] = slpressure_mB;
  weather["BME280"]["Heat Index"] = Heat_Index;
  weather["VEML-6075"]["UVA"] = uvia;
  weather["VEML-6075"]["UVB"] = uvib;
  weather["VEML-6075"]["UV Index"] = uvi;
  weather["PMS 5003"]["Last Read Sample"]["PM 1.0"] = PM_1wu;
  weather["PMS 5003"]["Last Read Sample"]["PM 2.5"] = PM_2_5wu;
  weather["PMS 5003"]["Last Read Sample"]["PM 10"] = PM_10wu;
  weather["PMS 5003"]["Total of 24hs PM 2.5"] = total24hs_PM_2_5;
  weather["PMS 5003"]["Average of 24hs PM 2.5"] = media24hs_PM_2_5;
  weather["PMS 5003"]["PM 2.5 AQI"] = AQI_PM_2_5;
  weather["PMS 5003"]["Air Quality PM 2.5"] = air_quality_PM_2_5;
  weather["PMS 5003"]["Total of 24hs PM 10"] = total24hs_PM_10;
  weather["PMS 5003"]["Average of 24hs PM 10"] = media24hs_PM_10;
  weather["PMS 5003"]["PM 10 AQI"] = AQI_PM_10;
  weather["PMS 5003"]["Air Quality PM 10"] = air_quality_PM_10;
  weather["PMS 5003"]["Air Quality Comparison"] = range_index;
  weather["Rain Bucket"]["Rain Rate"] = rainrate;
  weather["Rain Bucket"]["Rain Total"] = raintotal;
  weather["Wind"]["Speed"]= wind_speed_kmh;
  weather["Wind"]["Direction Cardinal"]= wind_direction_cardinal;
  weather["Wind"]["Direction Degrees"]= wind_direction_degrees;
  weather["Wind"]["Chill"]= Wind_Chill;  
  weather["Circuit Temperature"]["Circuit"]= temperature;
  weather["Circuit Temperature"]["Battery 1"] = batt_temp1;
  weather["Circuit Temperature"]["Battery 2"] = batt_temp2;

  Serial.print(F("Sending: "));
  serializeJson(weather, Serial);
  Serial.println();

  WiFiClient client;
  HTTPClient http;
  serializeJson(weather, buffer);

    Serial.print("[HTTP] begin...\n");
    // configure traged server and url
    http.begin(client, "http://"SERVER_IP"/rest/post_data"); //HTTP
    http.addHeader("Content-Type", "application/json");

    Serial.print("[HTTP] POST...\n");
    // start connection and send HTTP header and body
    int httpCode = http.POST(buffer);

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

      // file found at server
      if (httpCode == HTTP_CODE_OK) {
        const String& payload = http.getString();
        Serial.print("Received Payload: ");
        Serial.println(payload);
        Serial.println();
      }
    } else {
      Serial.printf("[HTTP] POST... failed, error: %s\n", http.errorToString(httpCode).c_str());
    }

    http.end();
  }

  delay(500);
}

at the other side, on server:

.
.
.

const char* ssid = STASSID;
const char* password = STAPSK;

void handleRoot() {

  server.send(200, "text/plain", "Hello from ESP8266!");

}

void handleNotFound() {

  server.send(404, "text/plain", "File not found...");

}

void setup(void) {

  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
  }

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("esp8266")) {
    Serial.println("ESP8266 - MDNS responder started");
  }

  server.on("/", handleRoot);

  server.on("/rest/post_data", []() {

  if (server.hasArg("plain")== false){ //Check if body received

    server.send(400, "text/plain", "Bad request: body not received");

  } else { // we received a body, hopefully our JSON data

    String message = server.arg("plain");
    message += "\n";

    Serial.print("Server - Json Received: ");
    Serial.println(message);

    // Allocate the JSON document
    const size_t capacity = JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + 5*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 2*JSON_OBJECT_SIZE(10) + 610;
    DynamicJsonDocument doc(capacity);

   // Parse JSON object
    DeserializationError error = deserializeJson(doc, message);
    if (error) {
      Serial.print(F("deserializeJson() failed: "));
      Serial.println(error.c_str());
      return;
    }

JsonObject Date = doc["Date"];
int Date_Day = Date["Day"]; // 165
int Date_Month = Date["Month"]; // 165
int Date_Year = Date["Year"]; // 2165
const char* Date_Weekday = Date["Weekday"]; // "Monday"

JsonObject Time = doc["Time"];
int Time_Hour = Time["Hour"]; // 165
int Time_Minute = Time["Minute"]; // 165
int Time_Second = Time["Second"]; // 85

int WiFi_WiFi_Signal_Strenght = doc["WiFi"]["WiFi Signal Strenght"];

JsonObject BME280 = doc["BME280"];
int BME280_Temperature = BME280["Temperature"]; // 0
int BME280_Humidity = BME280["Humidity"]; // 0
int BME280_DewPoint = BME280["DewPoint"]; // 0
int BME280_Pressure = BME280["Pressure"]; // 0
int BME280_Pressure_Equivalent = BME280["Pressure Equivalent"]; // 0

JsonObject VEML_6075 = doc["VEML-6075"];
int VEML_6075_UVA = VEML_6075["UVA"]; // 0
int VEML_6075_UVB = VEML_6075["UVB"]; // 0
int VEML_6075_UV_Index = VEML_6075["UV Index"]; // 0

JsonObject PMS_5003 = doc["PMS 5003"];

JsonObject PMS_5003_Last_Read_Sample = PMS_5003["Last Read Sample"];
int PMS_5003_Last_Read_Sample_PM_1_0 = PMS_5003_Last_Read_Sample["PM 1.0"]; // 0
int PMS_5003_Last_Read_Sample_PM_2_5 = PMS_5003_Last_Read_Sample["PM 2.5"]; // 0
int PMS_5003_Last_Read_Sample_PM_10 = PMS_5003_Last_Read_Sample["PM 10"]; // 0

int PMS_5003_Total_of_24hs_PM_2_5 = PMS_5003["Total of 24hs PM 2.5"]; // 0
int PMS_5003_Average_of_24hs_PM_2_5 = PMS_5003["Average of 24hs PM 2.5"]; // 0
int PMS_5003_PM_2_5_AQI = PMS_5003["PM 2.5 AQI"]; // 0
const char* PMS_5003_Air_Quality_PM_2_5 = PMS_5003["Air Quality PM 2.5"]; // ""
int PMS_5003_Total_of_24hs_PM_10 = PMS_5003["Total of 24hs PM 10"]; // 0
int PMS_5003_Average_of_24hs_PM_10 = PMS_5003["Average of 24hs PM 10"]; // 0
int PMS_5003_PM_10_AQI = PMS_5003["PM 10 AQI"]; // 0
const char* PMS_5003_Air_Quality_PM_10 = PMS_5003["Air Quality PM 10"]; // ""
const char* PMS_5003_Air_Quality_Comparison = PMS_5003["Air Quality Comparison"]; // ""

int Rain_Bucket_Rain_Rate = doc["Rain Bucket"]["Rain Rate"]; // 0
int Rain_Bucket_Rain_Total = doc["Rain Bucket"]["Rain Total"]; // 0

JsonObject Wind = doc["Wind"];
int Wind_Speed = Wind["Speed"]; // 0
const char* Wind_Direction_Cardinal = Wind["Direction Cardinal"]; // ""
int Wind_Direction_Degrees = Wind["Direction Degrees"]; // 0

JsonObject Circuit_Temperature = doc["Circuit Temperature"];
int Circuit_Temperature_Circuit = Circuit_Temperature["Circuit"]; // 0
int Circuit_Temperature_Battery_1 = Circuit_Temperature["Battery 1"]; // 0
int Circuit_Temperature_Battery_2 = Circuit_Temperature["Battery 2"]; // 0

server.send(200, "text/plain", "Successfully Received...");

}
});

  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
  server.handleClient();
  MDNS.update();

}

what could be wrong?

Thanks,

lcfelippe.

bblanchon commented 4 years ago

Hi Icefelippe,

I don't know why you need to reboot; maybe you should try with a simpler example. Anyway, I don't think this issue is related to ArduinoJson.

Best regards, Benoit

lcfelippe commented 4 years ago

Hi @bblanchon,

I solved it cleaning the buffer variable every time before serialize the JSON on client.

void loop(){
buffer = "";
.
.
.
}

Regards,

lcfelippe.

bblanchon commented 4 years ago

Hi @lcfelippe,

Indeed, serializeJson() appends to String, just as it would do with a Stream. You didn't show the declaration of buffer, so I didn't realize you were (re-)using a String.

Best regards, Benoit