Simple HTTP POST to Wifi Thermostat. HELP NEEDED

When i said "simple" in the subject I'm hopping it simple for you, as I have found it difficult.

I've search high and low for a good (simple) example for http post.

I need to post a temperature reading from my arduino uno to my wifi thermostat.

My thermostat allows me to post a remote temperature to it (i've sucessfuly don't it with my android phone and the app tasker). The thermostat will then turn the A/C or heater on based on the temperature I've sent to it rather than the built-in temp sensor.

The address to post the temperature to is: 192.168.1.101/tstat/remote_temp

it accepts one decimal place, increments of a half degree (e.g. 68.5)

Here is the api for the thermostat http://radiothermostat.com/documents/RTCOAWiFIAPIV1_3.pdf

I really have tried for about 3 weeks on this and am such a noob with this Ethernet shield. I was able to get the temperature on cosm.com which has HTTP POSTING from their site. Problem is the post has to be sent from my local LAN as the wifi thermostat doesn't allow HTTPS and i'm not about to open my port 80.

ANY HELP WOULD BE VERY MUCH APPRECIATED.

Here is my code in the playground. The second example shows how to send a POST request with the ethernet shield.
http://playground.arduino.cc/Code/WebClient

Are you connected to one of the ethernet ports on the router and the wireless AP is in the same router?

Thanks for your reply.

Yes i am connected to the network via a switch which is connected directly to the router all via Ethernet.

I honestly am not good enough to alter this example (spent hours trying). Don't know how to get it so it accepts a simple temperature as the posting element.

The thermostat accepts JSON formatting which I assume is what the example is.

Not sure if this helps but the documentation has this in it:

"The HTTP operation POST updates the resource and assumes a JSON representation of the resource as the values to be updated."

Maybe i'm being naive but this code seems excessive for what i'm trying to accomplish. Is sprintf the only method for http post's?

Thanks again for your help.

Per your thermostat link "Further, the HTTP GET APIs can be exercised using a browser." Perhaps you should start out using a GET request instead of a POST request. What part in the project is the arduino to play?

haha, you going to wish you hadn't tried to help me.

After failing time and time again with the POST I had that same thought process. "let see if i can even get info (current settings) from thermostat with GET". Didn't work so well, I'm sure i'm trying something way over my pay grade, however this is kinda the reason I went with arduino.

I love learning new thing but at this point in my life I don't have a ton of time to learn C programming language. I guess i was hoping I could find my way though it with other examples.

Problem is there doesn't appear to be very many http post examples, especially ones that are simplified.

The Arduino is playing the roll of sending the temperature from out bedroom upstairs down to the thermostat so its basing decisions to the the AC or Heater on from the temperature upstairs not at the thermostat itself.

Much as it pains me to agree with zoomkat, he's right. You need to figure out to make a browser send data to the thermostat, first. Then, you can write the Arduino code to do the same thing.

You still haven't told us squat about the thermostat. A brand name and model number is a distant second to a link, but better than nothing. Of course, a link is better.

Have a look at Section 2.5 of the .pdf at the link. That section provides examples using the gold-standard "curl" command line http tool.

The thermostat expects the data for the POST command to be in JSON format in the body of the post. See Section 2.5.2 for a very clear example.

Unfortunately you can't do that from the browser command line for easy testing, but if you have or can get curl on your system you would find it helpful.

In the browser, GET of the various API urls should work fine to see the current settings, and should be your basic "is it up" test.

-br

ok i'm very frustrated. i tried for 4 hours to get this to work, trying to use the GET method to even return something.

It seems that it connects to the thermostat but almost immediately disconnects. I'm not sure if this is because the data that is on the site is so small that it sends it and the disconnects. or if this is a bug. I though i read somewhere people were having trouble with connecting to Linux servers.

Also, not sure if this is a factor but when viewing one of the web pages that contains setting info from the browser, it appears to only be returning TEXT. the text on the web pages is as follows:

{"temp":66.00,"tmode":1,"fmode":0,"override":1,"hold":1,"t_heat":66.00,"tstate":0,"fstate":0,"time":{"day":2,"hour":23,"minute":16},"t_type_post":0}

When i went to view the source to see the HTML it didn't have any HTML. the source page looks the same as the web page.

In answer to your questions i have had success communicating (GET & POST) with the thermostat via my android phone and an app called "tasker". I tell this app the address i'd like to post ( 192.168.1.101/tstat/remote_temp ) and the data i'd like to send is this:

{"rem_temp":72}

The link to the api i send in my first post says the data can be added to responses of GET and POST methods.

Also, I have used cURL successfully from windows command prompt (with curl installed). This is the the .bat file I use with cURL.

ECHO OFF
curl -d "{\"rem_temp\":65}" http://192.168.1.101/tstat/remote_temp --silent -o "results.txt"

::| CLIP

::ECHO OFF

I know its hard to troubleshoot problems without being able to fiddle with them yourself. I appreciate you helping me though.

i tried for 4 hours to get this to work, trying to use the GET method to even return something.

And the code to do that looks like?

Also, not sure if this is a factor but when viewing one of the web pages that contains setting info from the browser, it appears to only be returning TEXT. the text on the web pages is as follows:

{"temp":66.00,"tmode":1,"fmode":0,"override":1,"hold":1,"t_heat":66.00,"tstate":0,"fstate":0,"time":{"day":2,"hour":23,"minute":16},"t_type_post":0}

This is as expected; it's what a JSON response body looks like. Your POST body will look similar but simpler since it only contains the one parameter you want to change.

The link to the api i send in my first post says the data can be added to responses of GET and POST methods.

Yes. Your POST will consist of three lines:

  1. POST /tstat/remote_temp HTTP/1.1
  2. A blank line
  3. The POST body containing your JSON-encoded parameter data: {"destruct_time":72}

As Paul says, posting your code will get better help.

-br

SUCCESS!! Well partially anyway.

I was able to get a response from the thermostat with a GET request. here is the code that worked.

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress server(192,168,1,101); // Thermostats IP
EthernetClient client;

void setup()
{
 Ethernet.begin(mac);
  Serial.begin(9600);

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

  if (client.connect(server, 80)) {
    Serial.println("connected");
 
    delay(1000);
    client.println("GET /tstat HTTP/1.1");
    client.println();

  } else {
    Serial.println("connection failed");
  }
}

void loop()
{
  if (client.available()) {


    char c = client.read();
    Serial.print(c);
  }

  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    for(;;)
	;
  }


}

Not sure why that was so difficult, i'm sure you all are thinking the same thing, lol.

Ok so for what i hope to be the easier question. I'm sure i can figure out the POST except for how to format the data i need to send. As mentioned in an earlier post the data i need to send in the response line looks like this:

{"rem_temp":72}

now how do I put that into:

client.println("");

When I try to add it into the quotations it doesn't like the braces or quotation that are apart of my data string.

I know with windows command prompt and cURL I had to alter it alittle like this:

"{\"rem_temp\":65}"

i'm sure there is something I can do to tell it that this is part of my data and not code.

your help is great guys!

Thanks!

Below is some code showing how the " in the html line is escaped using the \ backslash.

          client.println("<HTML>");
          client.println("<HEAD>");
          client.println("<TITLE>Arduino GET test page</TITLE>");
          client.println("</HEAD>");
          client.println("<BODY>");

          client.println("<H1>HTML form GET example</H1>");

          client.println("<FORM ACTION=\"http://192.168.1.102:84\" method=get >");

          client.println("Pin 5 \"on\" or \"off\": <INPUT TYPE=TEXT NAME=\"LED\" VALUE=\"\" SIZE=\"25\" MAXLENGTH=\"50\">
");

          client.println("<INPUT TYPE=SUBMIT NAME=\"submit\" VALUE=\"Change Pin 5!\">");

          client.println("</FORM>");

          client.println("
");

          client.println("</BODY>");
          client.println("</HTML>");

Thank for the quick reply.

That took care of putting quotes inside of my data but didn't work for the { } symbol's (braces I believe is what there called).

Any tricks for including these inside of my client.println(" "); ?

That took care of putting quotes inside of my data but didn't work for the { } symbol's (braces I believe is what there called).

Any tricks for including these inside of my client.println(" "); ?

The curly braces are not special characters. You should simply be able to have them as part of the string. Show the code that does, and describe whatever problems you have with the code.

My mistake, the braces didn't effect it was just putting it after the "

I can connect to the page i need to post to with a GET using the following code:

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress server(192,168,1,101); // Thermostats IP
EthernetClient client;

void setup()
{
 Ethernet.begin(mac);
  Serial.begin(9600);

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

  if (client.connect(server, 80)) {
    Serial.println("connected");
 
    delay(1000);
    client.println("GET /tstat/remote_temp HTTP/1.1");
    client.println();
    //client.println("{\"rem_temp\":62}");

  } else {
    Serial.println("connection failed");
  }
}

void loop()
{
  if (client.available()) {


    char c = client.read();
    Serial.print(c);
  }

  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    for(;;)
	;
  }


}

Which gives the the expected return over the serial monitor of:

connecting...
connected
HTTP/1.1 200 OK
Server: Marvell 8688WM
Connection: close
Transfer-Encoding: chunked
Content-Type: application/json
Cache-Control: no-store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
Pragma: no-cache

e
{"rem_mode":0}
0

When I try and change it to a POST with the following code:

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress server(192,168,1,101); // Thermostats IP
EthernetClient client;

void setup()
{
 Ethernet.begin(mac);
  Serial.begin(9600);

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

  if (client.connect(server, 80)) {
    Serial.println("connected");
 
    delay(1000);
    client.println("POST /tstat/remote_temp HTTP/1.1");
    client.println();
    client.println("{\"rem_temp\":62}");

  } else {
    Serial.println("connection failed");
  }
}

void loop()
{
  if (client.available()) {


    char c = client.read();
    Serial.print(c);
  }

  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    for(;;)
	;
  }


}

I Get This Response:

connected
HTTP/1.1 200 OK
Server: Marvell 8688WM
Connection: close
Transfer-Encoding: chunked
Content-Type: application/json
Cache-Control: no-store, no-cache, must-revalidate
Cache-Control: post-check=0, pre-check=0
Pragma: no-cache

HTTP/1.1 500 Internal Server Error
Server: Marvell 8688WM
Connection: close
Transfer-Encoding: chunked
Content-Type: text/plain

13
wsgi handler failed
0

HTTP/1.1 404 Not Found
Server: Marvell 8688WM
Connection: close
Transfer-Encoding: chunked
Content-Type: application/octet-stream

181
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head><title>Wireless Thermostat - 404</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
</head>
<body>
Whoops!  This page doesn't exist.  You probably meant to go to <a href="home.shtml">the main page.</a>
</body>
</html>

0

Not sure what i'm doing wrong....

When using the POST method, the length of the data being posted should be included in the return header like below.

client.println("POST hxxp://yourdomain.com/SMSSite/XMLInterface/Postxml.aspx HTTP/1.0");
// add a header indicating you have content-data to send.  If you set this too low, the server won't see it.  If it is too high, the server may wait, or report an error.
client.print("content-length: ");
client.println(strlen(big_string));
// tell the server you are done with the header.
client.println();
// send the posted data.
client.print(big_string);

Thank you everyone for your help. Finally working now....

In the interest of someone else stumbling onto this question, here is my working code:

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress server(192,168,1,101); // Thermostats IP
EthernetClient client;

int temp = 64;

void setup()
{
 Ethernet.begin(mac);
  Serial.begin(9600);

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

  if (client.connect(server, 80)) 
  {
    Serial.println("connected");
    delay(2500);
    client.println("POST /tstat/remote_temp HTTP/1.1");
    client.println("Content-length: 15");
    client.println("Connection: Close");
    client.println();
    client.print("\"rem_temp\":");     //Set Remote temperture to ___
    client.print(temp);
    client.println("}");
  } 
    else 
    {
    Serial.println("connection failed");
    }
}
void loop()
{
  if (client.available()) {
    char c = client.read();
    Serial.print(c);  
  }
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    for(;;)
	;
  }
}

Hoping for a little HELP here, I know I'm jumping into the middle of a thread but here similar to my problem.
I have a system running where data are placed in the csvdata directory and it works fine
if I write in my browser xxx.yyyyyyy.dk:8000/invput?id=kim&data=1,2,3,4,5

I get a file:kim-20130218.csv ( 2013--> yer 0218 --> date )
in the library: csvdata directory
how it works I do not know!

is there anyone who can help me here.

kimjessen:
I have a system running
how it works I do not know!
is there anyone who can help me here.

Are you asking for somebody to explain how your solution works? If not, what are you asking?

No No ...
I have seemingly expressed me wrong, I'm sorry ...
what I'm trying to say is ..
I have access to a server where I can send data to.
I have used in different situations where I have used the browser as I mention.
after I have on the server been able to use the data in a SQL data base.
So now I would do it a little more automatic.
I wanted to do a few experiments with some temperature sensing.
what I know is that I can use: "xxxxxx.yyyyyyy.dk: 8000/invput? id = kim & data = 1,2,3,4,5" in an http browser, but how do I get it to work on a arduino.
I have tried to do something in this style:

/*
   Web client sketch for IDE v1.0.1 and w5100/w5200
   Uses POST method.
   Posted November 2012 by SurferTim
*/

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = {  
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

//Change to your server domain
char serverName[] = "xxxx.yyyyyyyy.dk";

// change to the page on that server
char pageName[] = "/invput";

EthernetClient client;
int totalCount = 0; 
int loopCount = 0;
// insure params is big enough to hold your variables
char params[32];

void setup() {
  Serial.begin(9600);

  // disable SD SPI
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

  Serial.print("Starting ethernet...");
  if(!Ethernet.begin(mac)) Serial.println("failed");
  else Serial.println(Ethernet.localIP());

  delay(2000);
  Serial.println("Ready");
}

void loop()
{
  if(loopCount < 30)
  {
    delay(1000);
  }
  else
  {
    loopCount = 0;
    // params must be url encoded.
    sprintf(params,"id=kim&data=1,2,3,4,5,6,7,8,9",totalCount);//"id=kim&data=1,2,3,4,5,6,7,8,9"-> This I change to a variable when things run.  
    if(!postPage(serverName,pageName,params)) Serial.print("Fail ");
    else Serial.print("Pass ");
    totalCount++;
    Serial.println(totalCount,DEC);
  }    

  loopCount++;
}


byte postPage(char* domainBuffer,char* page,char* thisData)
{
  int inChar;
  char outBuf[64];

  Serial.print("connecting...");

  if(client.connect(domainBuffer,8000))
  {
    Serial.println("connected");

    // send the header
    sprintf(outBuf,"POST %s HTTP/1.1",page);
    client.println(outBuf);
    sprintf(outBuf,"Host: %s",domainBuffer);
    client.println(outBuf);
    client.println("Connection: close\r\nContent-Type: application/x-www-form-urlencoded");
    sprintf(outBuf,"Content-Length: %u\r\n",strlen(thisData));
    client.println(outBuf);

    // send the body (variables)
    client.print(thisData);
  } 
  else
  {
    Serial.println("failed");
    return 0;
  }

  int connectLoop = 0;

  while(client.connected())
  {
    while(client.available())
    {
      inChar = client.read();
      Serial.write(inChar);
      connectLoop = 0;
    }

    delay(1);
    connectLoop++;
    if(connectLoop > 10000)
    {
      Serial.println();
      Serial.println("Timeout");
      client.stop();
    }
  }

  Serial.println();
  Serial.println("disconnecting.");
  client.stop();
  return 1;
}

but it does not work. I get a 405 error see below:

Starting ethernet...192.168.10.150
Ready
connecting...connected
HTTP/1.1 405 Method Not Allowed
Date: Mon, 18 Feb 2013 13:24:36 GMT
Server: Apache/2.2.22 (Ubuntu)
Allow: GET,HEAD
Content-Length: 742
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=UTF-8


    <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
    <html>
        <head>
            <title>Error: 405 Method Not Allowed</title>
            <style type="text/css">
              html {background-color: #eee; font-family: sans;}
              body {background-color: #fff; border: 1px solid #ddd;
                    padding: 15px; margin: 15px;}
              pre {background-color: #eee; border: 1px solid #ddd; padding: 5px;}
            </style>
        </head>
        <body>
            <h1>Error: 405 Method Not Allowed</h1>
            <p>Sorry, the requested URL <tt>&#039;http://xxxx.yyyyyyy.dk/invput&#039;</tt>
               caused an error:</p>
            <pre>Method not allowed.</pre>
        </body>
    </html>

disconnecting.
Pass 1

I hope that you now understand my problem.