How to make a POST Request with MKRGSM/GSMSSLClient Library

Dear all

does enybody have an example of how to POST Data to a server with MKR GSM 1400 Board?

I have a Bearer authentification method and pass the token via client.print() function. If I pass wrong bearer token I get 401 http code.

So with correct token it's no more 401 and that is why I think I'm one step further. But then I crash against 400 - Bad Request. Using a REST Client I reproduce the issue with malformed or missing JSON request body.

It would be nice to have a look at a working example.
How do I pass the request body - still using the client.print() or client.write() function?

Thnx

I have had limited success sending the POST header and body information in smaller chunks.

Hi,

I am currently having the same error. The petition itself I know for sure that it does work, as I have tried on bash and works fine. I post bellow the code and the curl sentence which I try to replicate on the Arduino:

#include <ArduinoHttpClient.h>
#include <MKRGSM.h>

// PIN Number
const char PINNUMBER[]     = ""; //blank if no pin
// APN data: check settings on mobile for sim provider or contact carrier for network settings
const char GPRS_APN[]      = "<GPRS_APN>";
const char GPRS_LOGIN[]    = "<GPRS_LOGIN>";
const char GPRS_PASSWORD[] = "<GPRS_PASSWORD>";

// get this from the wia dashboard. it should start with `d_sk`

GSMClient client;
GPRS gprs;
GSM gsmAccess;

// Wia API parameters
char server[] = "<server>.servicebus.windows.net/<instance>/messages";
char path[] = "/";
int port = 443;


HttpClient httpClient = HttpClient(client, server, port);
//JsonObject& root = jsonBuffer.to<JsonObject>();
String response;
int statusCode = 0;
String dataStr;
void setup() {
  // initialize serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.println("Starting GSM connection to Wia!.");
  // connection state
  boolean connected = false;

  // After starting the modem with GSM.begin()
  // attach the shield to the GPRS network with the APN, login and password
  while (!connected) {
    if ((gsmAccess.begin(PINNUMBER) == GSM_READY) &&
        (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
      connected = true;
    } else {
      Serial.println("Not connected");
      delay(1000);
    }
  }

  Serial.println("connecting...");
  // if you get a connection, report back via serial:
  if (client.connect(server, port)) {
    Serial.println("connected");
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}

void loop() {
  //root["name"] = "temperature";
  //root["data"] = 21.5;

  // if you get a connection, report back via serial:
  if (client.connect(server, port)) {

    postToWia("{\"name\": \"adrian\"}");

  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }
  // read the status code and body of the response
  statusCode = httpClient.responseStatusCode();
  response = httpClient.responseBody();



  Serial.print("Status code: ");
  Serial.println(statusCode);
  Serial.print("Response: ");
  Serial.println(response);

  delay(3000); // Wait for 3 seconds to post again
}

void postToWia(String data) {

  httpClient.beginRequest();
  httpClient.post(path);
  httpClient.sendHeader("Authorization", "SharedAccessSignature sr=https%3A%2F%2F<server>.servicebus.windows.net%2F<instance>&sig=<sig>&se=1576319028&skn=RootManageSharedAccessKey");
  httpClient.beginBody();
  httpClient.print(data);
  httpClient.endRequest();

}

The curl operation is the following:

curl -X POST -k -H 'Authorization: SharedAccessSignature sr=https%3A%2F%2F<server>.servicebus.windows.net%2F<instance>&sig=<sig>&se=1576319028&skn=RootManageSharedAccessKey' -H -i 'https://<server>.servicebus.windows.net/<instance>/messages?timeout=60' --data "{\"name\": \"adrian\"}"

And according to Microsoft's documentation, I believe that I am posting the event in the Arduino following the right syntax.

Any guesses?

I have also seen that there is a possibility to make it work with the library SPI, but still does not work. I also attach the code, altough I¡m more confident with the previously attached solution.

#include <MKRGSM.h>
#include <SPI.h>

// PIN Number
const char PINNUMBER[]     = ""; //blank if no pin
// APN data: check settings on mobile for sim provider or contact carrier for network settings
const char GPRS_APN[]      = "<GPRS_APN>";
const char GPRS_LOGIN[]    = "<GPRS_LOGIN>";
const char GPRS_PASSWORD[] = "<GPRS_PASSWORD>";

// initialize the library instance
GSMClient client;
GPRS gprs;
GSM gsmAccess;

// URL, path and port (for example: arduino.cc)
char server[] = "https://<server>.servicebus.windows.net/<instance>/messages";
char path[] = "https://<server>.servicebus.windows.net/<instance>"; 
char sas[]= "Authorization: SharedAccessSignature sr=https%3A%2F%2F<server>.servicebus.windows.net%2F<instance>&sig=<sig>&se=1576319028&skn=RootManageSharedAccessKey";
int port = 443; // port 80 is the default for HTTP
char buffer[64];

int value = 465;

void setup() {

  // initialize serial communications and wait for port to open:
  Serial.begin(9600);
  //while (!Serial) {
    //; // wait for serial port to connect. Needed for native USB port only
  //}

  delay(1000);
  
  pinMode(LED_BUILTIN,OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);

  envioCloud();
}

void loop() {
 digitalWrite(LED_BUILTIN, HIGH); 
 delay(1000);  
 digitalWrite(LED_BUILTIN, LOW);
 delay(1000);
}


void envioCloud(){
  
  Serial.println("Starting Arduino web client.");
  // connection state
  boolean connected = false;
 
  // After starting the modem with GSM.begin()
  // attach the shield to the GPRS network with the APN, login and password
  while (!connected) {
    if ((gsmAccess.begin(PINNUMBER) == GSM_READY) &&
        (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
      connected = true;
    } else {
      Serial.println("Not connected");
      delay(1000);
    }
  }

  Serial.println("connecting...");

  // if you get a connection, report back via serial:
  if (client.connect(server, port)) {
    Serial.println("connected");
    // Make a HTTP request:
    client.print("POST ");
    client.println("/");
    client.print("Authorization: SharedAccessSignature sr=https%3A%2F%2F<server>.servicebus.windows.net%2F<instance>&sig=<sig>&se=1576319028&skn=RootManageSharedAccessKey");
    sprintf(buffer, "{\"value\": %s}", "Hello World");
    client.println();
    client.println(buffer);
    
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }

 // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }
  
  Serial.println("disconnecting.");
  client.stop();
    
}

Any ideas?

Updates:

  1. The library version I am using is the latest one, MKRGSM 1.2.1.
  2. After changing GSM gsmAccess for GSM gsmAccess(true) I start to get responses but they are unreadable and the HTTP POST never gets done:
AT

OK
AT+IPR=921600

OK
AT

OK
AT+UPSV=3

OK
AT+CPIN?

ERROR
AT+CPIN?

ERROR
AT+CPIN?

ERROR
AT+CPIN?

+CPIN: READY

OK
AT+CMGF=1

OK
AT+UDCONF=1,1

OK
AT+CTZU=1

OK
AT+UDTMFD=1,2

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK

+UMWI: 0,1

+UMWI: 0,2

+UMWI: 0,3

+UMWI: 0,4
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,1

OK
AT+UCALLSTAT=1

OK
AT+CGATT=1

OK
AT+UPSD=0,1,""

OK
AT+UPSD=0,6,3

OK
AT+UPSD=0,2,""

OK
AT+UPSD=0,3,""

OK
AT+UPSD=0,7,"0.0.0.0"

OK
AT+UPSDA=0,3

OK
AT+UPSND=0,8

+UPSND: 0,8,1

OK
AT+USOCR=6

+USOCR: 0

OK
AT+USOCO=0,"https://efor01.servicebus.windows.net/myeventhub/messages",443

ERROR

Two things off hand:

  1. the server must just be the domain
char server[] = "<server>.servicebus.windows.net";
  1. You HTTP request is invalid, missing the HTTP version
// Make a HTTP request:
client.print("POST ");
client.println("/ HTTP/1.1"); <- line modified
client.print("Authorization: SharedAccessSignature sr=https%3A%2F%2F<server>.servicebus.windows.net%2F<instance>&sig=<sig>&se=1576319028&skn=RootManageSharedAccessKey");
sprintf(buffer, "{\"value\": %s}", "Hello World");
client.println();
client.println(buffer);

Hi,

I have many those modifications and the response I get is unreadable. I attach it bellow:

⸮AT

OK
AT+IPR=921600

OK
AT

OK
AT+UPSV=3

OK
AT+CPIN?

ERROR
AT+CPIN?

ERROR
AT+CPIN?

ERROR
AT+CPIN?

+CPIN: READY

Also, I do not really know what this output is.

The output you attached in the last post appears cut off, btw do you have a lipo battery attached?

Sure, I thought the ouput did not make any sense, but as it does, I attach the whole execution output. And no, I have no Lippo attach to the Arduino.

AT

OK
AT+IPR=921600

OK
AT

OK
AT+UPSV=3

OK
AT+CPIN?

ERROR
AT+CPIN?

ERROR
AT+CPIN?

ERROR
AT+CPIN?

+CPIN: READY

OK
AT+CMGF=1

OK
AT+UDCONF=1,1

OK
AT+CTZU=1

OK
AT+UDTMFD=1,2

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK

+UMWI: 0,1

+UMWI: 0,2

+UMWI: 0,3

+UMWI: 0,4
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,1

OK
AT+UCALLSTAT=1

OK
AT+CGATT=1

OK
AT+UPSD=0,1,""

OK
AT+UPSD=0,6,3

OK
AT+UPSD=0,2,""

OK
AT+UPSD=0,3,""

OK
AT+UPSD=0,7,"0.0.0.0"

OK
AT+UPSDA=0,3

OK
AT+UPSND=0,8

+UPSND: 0,8,1

OK
AT+USOCR=6

+USOCR: 0

OK
AT+USOCO=0,"<server>.servicebus.windows.net",443

OK
connected
AT+USOWR=0,5,"504F535420"

+USOWR: 0,5

OK
AT+USOWR=0,60,"2F6D796576656E746875622F6D657373616765733F74696D656F75743D3630266170692D76657273696F6E3D323031342D303120485454502F312E31"

+USOWR: 0,60

OK
AT+USOWR=0,193,"417574686F72697A6174696F6E3A205368617265644163636573735369676E61747572652073723D687474707325334125324625324665666F7230312E736572766963656275732E77696E646F77732E6E65742532466D796576656E74687562267369673D683977624C78673467306E50764E6E347977696F462532426C623244446E6556306863353833757A496B7462302533442673653D3135373633313930323826736B6E3D526F6F744D616E6167655368617265644163636573734B6579"

+USOWR: 0,193

OK
AT+USOWR=0,59,"436F6E74656E742D547970653A206170706C69636174696F6E2F61746F6D2B786D6C3B747970653D656E7472793B636861727365743D7574662D38"

+USOWR: 0,59

OK
AT+USOWR=0,2,"0D0A"

+USOWR: 0,2

OK
AT+USOWR=0,35,"486F73743A2065666F7230312E736572766963656275732E77696E646F77732E6E6574"

+USOWR: 0,35

OK
AT+USOWR=0,2,"0D0A"

+USOWR: 0,2

OK
AT+USOWR=0,2,"0D0A"

+USOWR: 0,2

OK
AT+USOWR=0,2,"0D0A"

+USOWR: 0,2

OK
AT+USOWR=0,22,"7B2276616C7565223A2048656C6C6F20576F726C647D"

+USOWR: 0,22

OK
AT+USOWR=0,2,"0D0A"

+USOWR: 0,2

OK
disconnecting.
AT+USOCL=0

OK

It seems you didn't update the server value in the sketch:

AT+USOCO=0,".servicebus.windows.net",443

OK

Yes, I changed that by hand before publishing the answer on the forum. I also tried inserting delays between the different client.println() in case the whole string was not being put together on time, but it did not changed nothing.

BTW, is there any Arduino documentation that can be used to interpret the given output?

My project here does a POST, the sequence of headers and body text took a little bit of time to get right:

It took me a while to remember that the extra blank line after sending the header data through is required before you can send the body data, as it indicates that the header data is terminated.

Although my code uses JSON, you should be right copying the Syntax of the header section, and making your own section to send the Body data through.

Relevant code section of my "POST" of data through to Thingspeak is extracted here, for the full details and the declaration of all the variables such as the server and port etc, look at the full sketch at the link above. But maybe this Syntax will help you out in your project....

 Serial.println("connected to: ");
    Serial.println(server);
    Serial.println(port);
    Serial.println("Beginnning JSON Post Sequence");
    Serial.println();
    client.print("POST /channels/");
    client.print(secretChannelID);
    client.println("/bulk_update.json HTTP/1.1");
    Serial.print("POST /channels/");
    Serial.print(secretChannelID);
    Serial.println("/bulk_update.json HTTP/1.1");
    client.println("Host: api.thingspeak.com");
    Serial.println("Host: api.thingspeak.com");
    client.println("User-Agent: mw.doc.bulk-update (Arduino MKR GSM 1400)");
    Serial.println("User-Agent: mw.doc.bulk-update (Arduino MKR GSM 1400)");
    client.println("Connection: close");
    Serial.println("Connection: close");
    client.println("Content-Type: application/json");
    Serial.println("Content-Type: application/json");
    client.print("Content-Length: ");
    Serial.print("Content-Length: ");
    client.println(root.measurePrettyLength());
    Serial.println(root.measurePrettyLength());
    
    // Terminate headers
    client.println();
    Serial.println();

    // Send body
    root.prettyPrintTo(client);
    root.prettyPrintTo(Serial);

    delay(350); //Wait to receive the response
    client.parseFloat();
    cResp = String(client.parseInt());
    Serial.println();
    Serial.println("Response code: "+cResp); // Print the response code. 202 indicates that the server has accepted the response

If I get it right, root.prettyPrintTo(Serial); is the same as directly writing the JSON string to the Serial, no? I have tried using a similar format (code bellow) and I have obtained the following response:

if (client.connect("https://<server>.servicebus.windows.net/<eventhub>/messages", 443)) {
    // Make a HTTP request:
    client.print("POST https://<server>.servicebus.windows.net/<eventhub>/messages?timeout=60&api-version=2014-01 HTTP/1.1");
    delay(3);
    client.println("Authorization: SharedAccessSignature <signature>");
    delay(3);
    client.println("Content-Type: application/atom+xml;type=entry;charset=utf-8");
    delay(3);
    client.println();
    delay(3);
    sprintf(buffer, "{\"value\": %s}", "Hello World");
    client.println(buffer);

And the response:

AT

OK
AT+IPR=921600

OK
AT

OK
AT+UPSV=3

OK
AT+CPIN?

ERROR
AT+CPIN?

ERROR
AT+CPIN?

ERROR
AT+CPIN?

+CPIN: READY

OK
AT+CMGF=1

OK
AT+UDCONF=1,1

OK
AT+CTZU=1

OK
AT+UDTMFD=1,2

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK

+UMWI: 0,1

+UMWI: 0,2

+UMWI: 0,3

+UMWI: 0,4
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,0

OK
AT+CREG?

+CREG: 0,1

OK
AT+UCALLSTAT=1

OK
AT+CGATT=1

OK
AT+UPSD=0,1,""

OK
AT+UPSD=0,6,3

OK
AT+UPSD=0,2,""

OK
AT+UPSD=0,3,""

OK
AT+UPSD=0,7,"0.0.0.0"

OK
AT+UPSDA=0,3

OK
AT+UPSND=0,8

+UPSND: 0,8,1

OK
AT+USOCR=6

+USOCR: 0

OK
AT+USOCO=0,"https://<server>.servicebus.windows.net/<eventhub>/messages",443

ERROR

+UUSOCL: 0
AT+USOCL=-1

ERROR
connected
disconnecting.

Yes I believe you should be able to change the JSON Print Pretty commands to just send the body of your text through client.println. I changed mine to use the JSON Print Pretty as it formats the body correctly without the need to escape all the special characters and it saved me from needing to convert string's etc.

Why is your output echo'ing out the AT commands that are being sent?

Also your URL looks wrong, or is at least outputting wrongly on the serial monitor:

OK
AT+USOCO=0,"https://<server>.servicebus.windows.net/<eventhub>/messages",443

ERROR

no doubt you will have noted in my project on hackster, that I make a connection to the server and port, the values of which are as follows:

// Domain name and port that we will connect too (for example: api.thingspeak.com)
char server[] = "api.thingspeak.com";
int port = 443; // port 443 is the default for HTTPS

I don't believe you are following this format in your code, as it appears you connect to the entire URL, rather than just the server's domain namew, then you try to do a POST to the entire URL again, rather than just the portion of the URL after the domain name.... Make sense?

I suggest you look at the way you are making your connection to the server initially. Generally I believe you need to connect to the server, which won't be the whole URL, then do your POST connection to the URL on the server.

Like I said before, the formatting of the request is pretty picky. Suggest you just use the code I gave you earlier as a starting point and adapt it for your server and URL.

Also add some serial.println's to your code so that you can see what should be in the buffer and that the buffer result is what you are expecting.