HTTP Post from web page vs ArduinoHttpClient not working

Hello all - I am trying to implement IP Control of a Sony TV. The Sony rest IP is well documented and using their nice example web page I was able to code web pages to POST a request and control the TV as intended.

All my attempts to send the POST request to the TV -- using essentially identical code as that in the web page -- using an Arduino wifi board have failed - except one. Aa a debugging exercise, if I use the Arduino web server to create an html page that runs a java script onload event, and then open that web page, the TV does what it supposed to do.

I am trying to understand the difference between a browser JS XMLHttpRequest and an Arduino ArduinoHttpClient request.

The Arduino code [snipet] that I just can not get to work to decrease volume -1:

#include <SPI.h>
#include <WiFiNINA.h>
#include <ArduinoHttpClient.h>

WiFiServer server(80);
int port = 80;
char serverAddress[] = "192.168.1.20"; 

WiFiClient wifi;
HttpClient client = HttpClient(wifi, serverAddress, port);
//---

//STANDARD WIFI AND CLIENT CONNECT CODE

//-------
  String postData = "'{\"method\":\"setAudioVolume\",\"version\":\"1.0\",\"id\":1,\"params\":[{\"target\":\"speaker\",\"volume\":\"-1\"}]}'";
  
  //Following alternative gives the same result
  //String postData = "'{""method"":""setAudioVolume"",""version"":""1.0"",""id"":1,""params"":[{""target"":""speaker"",""volume"":""-1""}]}'";

  client.beginRequest();
  client.post("/sony/audio");
  client.sendHeader("X-Auth-PSK:", "1234");
  client.sendHeader("HOST:", "192.168.1.26");  //wifi address.  excluding results in a JSON format error returned
  client.sendHeader("Content-Type:", "application/json; charset=UTF-8");
  client.beginBody();
  client.print(postData);
  
  client.endRequest();


  int statusCode = client.responseStatusCode();
  String response = client.responseBody();

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

The return messages from the TV are

POST Status code: 400
POST Response: <html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx</center>
</body>
</html>

The Arudino code [snipet] that works (when I open the web page) by calling the send() function when the document body loads. Note, all other code besides the snipets are identical:

client.println("<script>");
client.println("function send(){");
client.println("var xhr = new XMLHttpRequest();");
client.println("xhr.open('POST', 'http://192.168.1.20/sony/audio');");
 
client.println("xhr.setRequestHeader('X-Auth-PSK', '1234');");
client.println("xhr.send('{\"method\":\"setAudioVolume\",\"version\":\"1.0\",\"id\":1,\"params\":[{\"target\":\"speaker\",\"volume\":\"-1\"}]}');");
client.println("}");

client.println("</script>");
client.println("<body onload=\"send()\">");
client.println("Hello world");
client.println("</body>");

I have run out of ideas on what to change or google next so am posting here. I have sure learned a lot in this project, and feel I am so close....

Cheers

the IP in the Host header doesn't match. let the library set the Host header.

Thanks for the rapid response :slight_smile:

In my many iterations, I had set the HOST to both the IP of the TV, and the IP of the web server - neither worked. In the example I gave unfortunately they don't match - a good catch!!. But I confirmed that when I change the line to match I get the same error.

Taking out the client.sendHeader("HOST:", "192.168.1.26"); line entirely results in a JSON format error, if this is what your response was referring to (viz, the library setting the host).

googling about the only things related I found useful was that a similar library, HTTPclient strips out a HOST header silently. No indication of a HOST command in the arduinohttpclient library, but there was a HTTP_HEADER_HOST const in the library documentation, but using various permutations of:

client.sendHeader("HOST", HTTP_HEADER_HOST);

resulted in a 'HTTP_HEADER_HOST' was not declared in this scope error.

A little more direction please...

400 Bad request is before JSON is processed so a JSON error is progress

So if the host header is sent to the TV by the httpclient library, and I am getting a JSON error, I guess that brings us back to my original question - why is the request working when structured from a web browser (JS) and not working went sent from the Arduino?

FWIW I did modify what I think is the offending line by changing the "" to ", and the variable type from String to uint8_t with no success

remove ' from the JSON string

Its awesome having additional brain power on this :slight_smile:

Removing the ' from the JSON string results in the same 400 JSON error ("" and "permutations). Moreover, removing them breaks the web browser version!

The template for me was the TV manufacturer's example on IP control using a web browser. It uses a json.stringify() command to format the xhr.send POST, and figuring out how to mimic this for the Arduino was a huge hurdle. Couldn't get web version to work until I added the apostrophes to the literal JSON string. Thus, from the example web page:

xhr.send(JSON.stringify({
    method: 'setAudioVolume',
    version: '1.0',
    id: 1,
    params: [{"target":"speaker","volume":"-1"}]
  }));

to my generated page :

client.println("xhr.send('{"method":"setAudioVolume","version":"1.0","id":1,"params":[{"target":"speaker","volume":"-1"}]}');");

I thought adding them to Arduino -> TV IP would finally work....not so much.

in Arduino we use " not ' for strings. ' inside string is part of the string and makes the json invalid.
in Java Script you can use " or ' for string. but you will still not use "'{ for json format

Thanks to your last comment I started looking at other issues, as I thought the JSON was now correct. Always good to take a step back -- getting rid of the arduinohttpclient library and using classic commands, got it to work!

wifi.connect("192.168.1.20",80);

String request = String("POST") + " /sony/audio HTTP/1.1" + "\r\n" +
        "Host: 192.168.1.20" + "\r\n" + 
        "Content-Type: application/json; charset=UTF-8" + "\r\n" +
        "X-Auth-PSK: 1234" + "\r\n" +
        "Content-Length: 96" + "\r\n\r\n" +
        "{\"method\":\"setAudioVolume\",\"version\":\"1.0\",\"id\":1,\"params\":[{\"target\":\"speaker\",\"volume\":\"+1\"}]}" + "\r\n\r\n";    
        
wifi.print(request);

...adding the Content-Length header

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.