HTTP POST JSON fails with two parameters, but works with only one

I have a piece of code that builds an HTTP Request and uses strlen(characterArray) to define Content Length. This works perfectly.

But my Content Length is made up of char and string data that Ive managed to put into a final String called finalDataString.

I thought I just had to replace strlen(characterArray) with strlen(finalDataString) but it doesnt work, presumably because strlen only works at runtime with char[]. How do I get the runtime value of a String?

Or how else should I approach this?

Thx

What is forcing you to use String, in addition to char[]? That brings in a lot of duplicate purpose functions thus sucking up a lot of memory and program space. Stick to one or the other.

strlen() will give you the length of a C style string (a zero terminated array of chars)
theString.length() will give you the length of a String (an object created using the String library)

Use a C string for preference in a small memory environment

Cool! I just logged into the forum using Face ID.

OK here is the thing. In code I use char dataString [200] to store my sensor data which at this moment is only a temp reading {"a":29.45}.

But I have to append this to a string composed of apikey, node and the variable for the data which for example is in my case, data. So in the end I must unite these in a String for a Post Request, taking the length of it and then using it to post. Here is the relevant code:

#define EMON_APIKEY F("a1b2c3d4e5f6g7")
char dataString[200];


void start_test () {
  //For DHT22 Grove Pro
  static char outstr1[15];
  static char outstr2[15];
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  dtostrf(t, 4, 2, dataString);  //convert flat to char
  Serial.println(dataString);
}

void httppost () {
  esp.println("AT+CIPSTART=\"TCP\",\"" + server + "\",80");//start a TCP connection.
  if( esp.find("OK")) {
    Serial.println("TCP connection ready");
  }
  
  delay(1000);
  String postRequest="POST " + uri + " HTTP/1.1\r\n"+"Host: " + server + "\r\n" + "Accept: *" + "/" + "*\r\n"+"Content-Length: " + strlen(dataString) + "\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"+"\r\n" + "&apikey=" + EMON_APIKEY + "&node=fortnite&data={" + "\"a\":" + dataString + "}";
  Serial.println(postRequest);
  String sendCmd = "AT+CIPSEND=";//determine the number of caracters to be sent.
//...
}

So the recommended route would be to convert the Strings into chars and just use char in the Post Request?

So in the end I must unite these in a String for a Post Request,

Is that really the case ?
Could you not combine them together into a C string and use that in the POST ?

Here is a portion of a Webserver program that uses a C string to do the POST

  sprintf(buffer, "<!DOCTYPE html>\
<html>\
<head>\
<style>\
.colourSquare {width: 300px; height: 300px; font-size: 80px; color: WHITE; font-weight:bold; display: inline-block;}\
</style>\
</head>\
<form action=\"/redLED\" method=\"POST\"><input type=\"submit\" class=\"colourSquare\" style=\"background-color:RED;\" value=\"%s\"></form>\
<form action=\"/greenLED\" method=\"POST\"><input type=\"submit\" class=\"colourSquare\" style=\"background-color:GREEN;\" value=\"%s\"></form>\
<form action=\"/blueLED\" method=\"POST\"><input type=\"submit\" class=\"colourSquare\" style=\"background-color:BLUE;\" value=\"%s\"></form>\
</html>", redText, greenText, blueText);
  server.send(200, "text/html", buffer );

The values of the char arrays redText, greenText and blueText are set elsewhere in the program depending on user input.

I tried this but its not working, postRequest comes up empty, so nothing gets posted. Here is my complete code and the SM results:

#include "SoftwareSerial.h"
//For DHT22 Grove Pro
#include "DHT.h"
#define DHTPIN A1     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE);

String ssid ="myssid";
String password="mypwd";
String server = "santiapps.com"; // www.example.com
String uri = "/emoncms/input/post";
#define EMON_APIKEY F("mykey")

byte dat [5];
String temp ,hum;
String data;
char dataString[200];

SoftwareSerial esp(6, 7);// RX, TX

void setup() {
  esp.begin(9600);
  Serial.begin(9600);
  Serial.println("setup");
  //esp.print("AT+UART_DEF=9600,8,1,0,0");
  reset();
  connectWifi();
}

void reset() {
  Serial.println("reset");
  esp.println("AT+RST");
  delay(1000);
  if(esp.find("OK") ) Serial.println("Module Reset");
}

void connectWifi() {
  Serial.println("connect to wifi");  
  String cmd = "AT+CWJAP=\"" +ssid+"\",\"" + password + "\"";
  esp.println(cmd);
  delay(400);
  while (esp.available()){
     String inData = esp.readStringUntil('\n');
     Serial.println("Got reponse from ESP8266: " + inData);
  }


  if(esp.find("OK")) {
    Serial.println("Connected!");
  } else {
    connectWifi();
    Serial.println("Cannot connect to wifi"); }
}


void start_test () {
  //For DHT22 Grove Pro
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  dtostrf(t, 4, 2, dataString);  //convert flat to char
  Serial.println(dataString);
}
void loop(){
  Serial.println("loop");
  start_test();
  httppost();
  delay(100000);
}

/* A POST contains a header block and then a single line of the data values, something like this:
 * 
 * POST /emoncms/input/post.json HTTP/1.1\r\n
 * Host: URL_OF_THE_SERVER\r\n
 * Content-Type: application/x-www-form-urlencoded\r\n
 * Content-Length: 100\r\n
 * \r\n
 * apikey=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&node=xx&csv=xx,xx,xx,xx\r\n
 * 
 * Most of the content is the same every time and simply hardcoded in here with print() direct to the 
 * ethernet stream client. Two things change every time, the data themselves and the length of the
 * string containing the data. 
 * 
 * The fixed strings are all written into the flash program space with F("") to prevent them filling
 * runtime RAM.
 */

void httppost () {
  esp.println("AT+CIPSTART=\"TCP\",\"" + server + "\",80");//start a TCP connection.
  if( esp.find("OK")) {
    Serial.println("TCP connection ready");
  }

//  //CODE USED TO BUILD COMPLETE STRING
  String nodeData="node=fortnite&data={\"a\":";
  String nodeWithJson=nodeData + dataString + "}"; //COMBINE STRING OBJECT WITH CHAR[]

  String apiKeyString="&apikey="; 
  apiKeyString.concat(EMON_APIKEY); //JOIN PARAMETER LITERAL STRING => String Object
  //Serial.println(apiKeyString); //THIS IS NOW A STRING OBJECT
  
  String finalData=nodeWithJson+apiKeyString; //COMBINE BOTH PREVIOUS STRING OBJECTS
  Serial.println("finalData");
  Serial.println(finalData); 
  
  delay(1000);
  String postRequest="POST " + uri + " HTTP/1.1\r\n"+"Host: " + server + "\r\n" + "Accept: *" + "/" + "*\r\n"+"Content-Length: " + finalData.length() + "\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"+"\r\n" + finalData;
  Serial.println("postRequest");
  Serial.println(postRequest);
  String sendCmd = "AT+CIPSEND=";//determine the number of caracters to be sent.
  esp.print(sendCmd);
  esp.println(postRequest.length());
  delay(500);
  if(esp.find(">")) { 
    Serial.println("Sending.."); 
    esp.print(postRequest);
    if(esp.find("SEND OK")) { 
      Serial.println("Packet sent");
      while (esp.available()) {
        String tmpResp = esp.readString();
        Serial.println(tmpResp);
      }
      // close the connection
      esp.println("AT+CIPCLOSE");
    }
  }
}

Ok I finally got it working with that code, but now that im trying to post 2 variables it fails to send again.

So this old code works:

void start_test () {
  //For DHT22 Grove Pro
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  dtostrf(t, 4, 2, dataString);  //convert flat to char  
  Serial.println(dataString);
}


void httppost () {
  esp.println("AT+CIPSTART=\"TCP\",\"" + server + "\",80");//start a TCP connection.
  if( esp.find("OK")) {
    Serial.println("TCP connection ready");
  }

//  //CODE USED TO BUILD COMPLETE STRING
  String nodeData="node=fortnite&data={\"a\":";
  String nodeWithJson=nodeData + dataString + "}"; //COMBINE STRING OBJECT WITH CHAR[]

  String apiKeyString="&apikey="; 
  apiKeyString.concat(EMON_APIKEY); //JOIN PARAMETER LITERAL STRING => String Object
  
  String finalData=nodeWithJson+apiKeyString; //COMBINE BOTH PREVIOUS STRING OBJECTS
  Serial.println("finalData");
  Serial.println(finalData); 
  
  delay(1000);
  String postRequest="POST " + uri + " HTTP/1.1\r\n"+"Host: " + server + "\r\n" + "Accept: *" + "/" + "*\r\n"+"Content-Length: " + finalData.length() + "\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"+"\r\n" + finalData;
  Serial.println("postRequest");
  Serial.println(postRequest);
...
}
&node=fortnite&data={"a":28.00}&apikey=mykey

My new code fails:

void start_test () {
  //For DHT22 Grove Pro
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  dtostrf(t, 4, 2, tempString);  //convert flat to char  
  dtostrf(h, 4, 2, humString);  //convert flat to char
  strcpy(dataString,tempString);
  strcat(dataString,humString);
  Serial.println(dataString);
}

void httppost () {
  esp.println("AT+CIPSTART=\"TCP\",\"" + server + "\",80");//start a TCP connection.
  if( esp.find("OK")) {
    Serial.println("TCP connection ready");
  }

//  //CODE USED TO BUILD COMPLETE STRING
  String nodeData1="&node=fortnite&data={\"t\":";
  String nodeData2=nodeData1 + tempString;
  String nodeData3=nodeData2 + ",\"h\":";
  String nodeData4=nodeData3 + humString;
  String nodeData5=nodeData4 + "}";
  
  String apiKeyString="&apikey="; 
  apiKeyString.concat(EMON_APIKEY); //JOIN PARAMETER LITERAL STRING => String Object
  
  String finalData=nodeData5+apiKeyString; //COMBINE BOTH PREVIOUS STRING OBJECTS
  Serial.println(finalData.length());
  Serial.println(finalData); 
  
  delay(1000);
  String postRequest="POST " + uri + " HTTP/1.1\r\n"+"Host: " + server + "\r\n" + "Accept: *" + "/" + "*\r\n"+"Content-Length: " + finalData.length() + "\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n"+"\r\n" + finalData;
  Serial.println("postRequest");
  Serial.println(postRequest);
...
}
&node=fortnite&data={"t":28.40,"h":69.20}&apikey=mykey

I just tried this and it doesnt work either:

//  //CODE USED TO BUILD COMPLETE STRING
  String nodeData1="&node=fortnite&data={t:";
  String nodeData2=nodeData1 + tempString;
  String nodeData3=nodeData2 + ",h:";
  String nodeData4=nodeData3 + humString;
  String nodeData5=nodeData4 + "}";
&node=fortnite&data={t:26.60,h:49.70}&apikey=mykey

But ok, this is not the correct json format.

I dont know why it would work like this:

&node=fortnite&data={"t":26.60}&apikey=mykey

but not like this:

&node=fortnite&data={"t":26.60,"h":49.70}&apikey=mykey

I even tried posting directly via the web browser url:

http://santiapps.com/emoncms/input/post?node=fortnite&data={"t":26.60,"h":49.70}&apikey=mykey

and it works, here it is in my browser history: