Can't get at HTTP POST to work, any ideas?

A colleague an I are trying to get a datacollect mechanism to work. Right now we are stranded at a HTTP POST issue. We have used the sample code from Arduino Playground - WebClient and our code looks like this:

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

// this must be unique
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// change to your network settings
IPAddress ip(10,0,0,100);
IPAddress gateway(10,0,0,1);
IPAddress subnet(255, 255, 255, 0);

// change to your server
IPAddress server(123,456,789,000); // our servers ip address goes here

EthernetClient client;
int totalCount = 0;
int loopCount = 0;
char pageAdd[32];

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

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

  // Start ethernet
  Serial.println("Starting ethernet...");
  // Ethernet.begin(mac, ip, gateway, gateway, subnet);

  // If using dhcp, comment out the line above 
  // and uncomment the next 2 lines

  if(!Ethernet.begin(mac)) Serial.println("failed");
  else Serial.println("ok");
  digitalWrite(10,HIGH);

  Serial.println(Ethernet.localIP());

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

void loop()
{
  if(loopCount < 30)
  {
    // if loopCount is less than 30, just delay a second
    delay(1000);
  }
  else
  {
    // every thirty seconds this runs
    loopCount = 0;

    // Modify next line to load different page
    // or pass values to server
    // sprintf(pageAdd,"/",totalCount);

    sprintf(pageAdd,"/insert.php?systemID=12345&data=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16"); // The 'systemID' and 'data' is to be sendt as a HTTP POST to the file insert.php, which grabs the data and puts it in a database

    if(!getPage(server,pageAdd)) Serial.print("Fail ");
    else Serial.print("Pass ");
    totalCount++;
    Serial.println(totalCount,DEC);
  }    

  loopCount++;
}

byte getPage(IPAddress ipBuf,char *page)
{
  int inChar;
  char outBuf[128];

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

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

    sprintf(outBuf,"POST %s HTTP/1.0\r\n\r\n",page);
    client.write(outBuf);
  } 
  else
  {
    Serial.println("failed");
    return 0;
  }

  // connectLoop controls the hardware fail timeout
  int connectLoop = 0;

  while(client.connected())
  {
    while(client.available())
    {
      inChar = client.read();
      Serial.write(inChar);
      // set connectLoop to zero if a packet arrives
      connectLoop = 0;
    }

    connectLoop++;

    // if more than 10000 milliseconds since the last packet
    if(connectLoop > 10000)
    {
      // then close the connection from this end.
      Serial.println();
      Serial.println("Timeout");
      client.stop();
    }
    // this is a delay for the connectLoop timing
    delay(1);
  }

  Serial.println();

  Serial.println("disconnecting.");
  // close client end
  client.stop();

  return 1;
}

The Arduino connects with the server just fine, but the data isn't posted. What are we doing wrong?

/Carl

char pageAdd[32];

...

   sprintf(pageAdd,"/insert.php?systemID=12345&data=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16");

That's 70 bytes plus a terminating null at the end. It won't fit.

The WebClient code was written for a GET, not a POST request, but can be accomplished with minor mods to the code. Is it the POST and not GET that you are after?

Why are you using sprintf to do formatted output of nothing? The strcpy() function has far less overhead.

This would be the way a POST is sent. This does need sprintf, but in the example, PaulS is correct. The strcpy function would be better. I left sprintf there because most will send parameters.

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

// change network to yours
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,2,2);
IPAddress gateway(192, 168, 2, 1);
IPAddress subnet(255, 255, 255, 0);

// Change to your server ip
IPAddress server(1,2,3,4);

EthernetClient client;
int totalCount = 0; 
int loopCount = 0;
char params[32];

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

  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  delay(2000);
  Serial.println("Ready");
}

void loop()
{
  if(loopCount < 30)
  {
    delay(1000);
  }
  else
  {
    loopCount = 0;
    sprintf(params,"temp1=%i",totalCount);     
    if(!postPage(server,"/arduino.php",params)) Serial.print("Fail ");
    else Serial.print("Pass ");
    totalCount++;
    Serial.println(totalCount,DEC);
  }    

  loopCount++;
}


byte postPage(IPAddress ipBuf,char *page,char* thisData)
{
  int inChar;
  char outBuf[128];

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

  if(client.connect(ipBuf,80))
  {
    Serial.println("connected");

    client.println("POST /arduino.php HTTP/1.0");
    client.println("Content-Type: application/x-www-form-urlencoded");

    sprintf(outBuf,"Content-Length: %u\r\n",strlen(thisData));
    
    client.println(outBuf);
    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;
}

Let me know if this works for you, and I will put it in the playground also.

Please forgive me. I'm a total newbe at this. My programming skills are at the server side, not the Arduino. I have a colleague that is a C programmer, and he's working with the Arduino board. My role is the HTTP protocol and server.

We'll try SurferTim's suggestion, and I'll be back as soon as we've tested.

Thanks!!!

This worked:

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

// change network to yours
byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,207);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

// Change to your server ip
IPAddress server(192, 168, 1, 21);

EthernetClient client;
int totalCount = 0; 
int loopCount = 0;
char params[32];

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

  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

  Ethernet.begin(mac, ip, gateway, gateway, subnet);
  delay(2000);
  Serial.println("Ready");
}

void loop()
{
  if(loopCount < 30)
  {
    delay(1000);
  }
  else
  {
    loopCount = 0;
    sprintf(params,"systemID=12345&data=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16",totalCount);     
    if(!postPage(server,"/insert.php",params)) Serial.print("Fail ");
    else Serial.print("Pass ");
    totalCount++;
    Serial.println(totalCount,DEC);
  }    

  loopCount++;
}


byte postPage(IPAddress ipBuf,char *page,char* thisData)
{
  int inChar;
  char outBuf[128];

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

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

    client.println("POST /insert.php HTTP/1.0");
    client.println("Content-Type: application/x-www-form-urlencoded");

    sprintf(outBuf,"Content-Length: %u\r\n",strlen(thisData));
    
    client.println(outBuf);
    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;
}

Now I have some additional questions:

  1. How can it be run with DHCP instead of static IP?
  2. How can I use domain name instead of an IP addres (DNS)?

Thanks in advance!

/Carl

This has both changes you requested. DHCP ip and domain name. I posted the entire code because I included the Host parameter in the request header in the event your server uses virtual hosting.

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

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

//Change to your server domain
char serverName[] = "www.mydomain.com";

EthernetClient client;
int totalCount = 0; 
int loopCount = 0;
char params[32];

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

  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;
    sprintf(params,"temp1=%i",totalCount);     
    if(!postPage(serverName,"/arduino.php",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,80))
  {
    Serial.println("connected");

    sprintf(outBuf,"POST %s HTTP/1.0",page);
    client.println(outBuf);
    sprintf(outBuf,"Host: %s",domainBuffer);
    client.println(outBuf);
    client.println("Content-Type: application/x-www-form-urlencoded");
    sprintf(outBuf,"Content-Length: %u\r\n",strlen(thisData));
    client.println(outBuf);
    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;
}

edit: Changed the postPage function to use the page variable instead of the test page I used.

I put this POST code in the playground. Both GET and POST methods are there now.
http://www.arduino.cc/playground/Code/WebClient