I am attempting to make RESTful POST request using the WifiESP library (https://github.com/bportaluri/WiFiEsp). I'm able to successfully make the request with curl, but consistently get an error using the Arduino and ESP. I suspect the problem is related to the manual formatting of the POST request the library requires, but I don't see anything wrong. Here my sanitized code:
if (client.connect(server, 80)) {
Serial.println("Connected to server");
// Make a HTTP request
String content = "{'JSON_key': 2.5}"; // some arbitrary JSON
client.println("POST /some/uri HTTP/1.1");
client.println("Host: http://things.ubidots.com");
client.println("Accept: */*");
client.println("Content-Length: " + sizeof(content));
client.println("Content-Type: application/json");
client.println();
client.println(content);
}
The error I get (via serial monitor) is this:
Connected to server
[WiFiEsp] Data packet send error (2)
[WiFiEsp] Failed to write to socket 3
[WiFiEsp] Disconnecting 3
My successful curl requests looks like this:
curl -X POST -H "Content-Type: application/json" -d 'Some JSON' http://things.ubidots.com/some/uri
After some experimentation, here is the solution to the multiple problems.
- The JSON object was not correctly formatted. Single quotes were not accepted, so I needed to escape the double quotes.
- The host does not need "http://" in a POST request; POST is a HTTP method.
- The sizeof() method returns the size, in bytes, of the variable in memory rather than the length of the string. It needs to be replaced by .length().
- Appending an integer to a string requires a cast.
This is the corrected code:
if (client.connect(server, 80)) {
Serial.println("Connected to server");
// Make the HTTP request
int value = 2.5; // an arbitrary value for testing
String content = "{\"JSON_key\": " + String(value) + "}";
client.println("POST /some/uri HTTP/1.1");
client.println("Host: things.ubidots.com");
client.println("Accept: */*");
client.println("Content-Length: " + String(content.length()));
client.println("Content-Type: application/json");
client.println();
client.println(content);
}
The code explained by Troy D is right and it's working .I think the error in posting the data to the server is due to this line
client.println("Content-Length: " + sizeof(content));
and the correct way is
client.println("Content-Length: " + String(content.length()));
Now coming to this error
Connected to server
[WiFiEsp] Data packet send error (2)
[WiFiEsp] Failed to write to socket 3
[WiFiEsp] Disconnecting 3
This is the error of library you can ignore it.
The problem with "Data packet send error (2)", "Failed to write to socket 3" and "Disconnecting 3" is not a problem within the WifiEsp library as far as I can see, believe it's more likely to be within the AT firmware. By default the http headers contain a "Connection: close" parameter which in normal cases should be correct. However with this bug the server will get disconnected before the reply is received on the client side and any response from the server will be identified as garbage data. Using the value "Connection: keep-alive" as a workaround will make it possible to receive the acceptance from the server in a proper way.
I'm running my Arduino + ESP8266-07 against a MVC based Web Api that I created on one of my servers and in the controllers Post-method I use a single string as return value, the value I return if everything is ok is simply one of the strings that WifiEsp keeps track of (It will still include the http status code in the response header that it returns)
public async Task<string> Post([FromBody]JObject payload)
{
//Code to handle the data received, in my case I log unit ip, macaddress, datetime and sensordata into a db with entity framework
return "SEND OK";
}
So in your Arduino code try following instead:
String PostHeader = "POST http://" + server + ":" + String(port) + "/api/values HTTP/1.1\r\n";
PostHeader += "Connection: keep-alive\r\n";
PostHeader += "Content-Type: application/json; charset=utf-8\r\n";
PostHeader += "Host: " + server + ":" + String(port) + "\r\n";
PostHeader += "Content-Length: " + String(jsonString.length()) + "\r\n\r\n";
PostHeader += jsonString;
client.connect(server.c_str(), port);
client.println(PostHeader);
client.stop();
In the file debug.h located in the library source code you could alter a define and get more output to your serial console. Open the file and change
#define _ESPLOGLEVEL_ 3
to
#define _ESPLOGLEVEL_ 4
Save the file and recompile/deploy your source code to your Arduino and you will get extensive information about all AT commands the library sends and what the library receives in return.