PHP data transfer with official Wifi shield

Hello all,
While fairly familiar with Arduinos, I'm completely new to PHP and google hasn't proven to be very helpful with this, so I'm hoping someone can supply the piece(s) of missing information.

Essentially, I am trying to pass some data from the arduino to the PHP script using the GET function. I have this working fairly well, but it occasionally will fail and I have to reset the arduino. If you have any advice on how to make this process more reliable based on my code below, awesome. In an effort to try to help myself, I was thinking that having the PHP return some sort of checksum to the arduino may help in the diagnosis of what is actually causing the link to fail. The problem I've run into is that I can't get that checksum data back to the arduino. I'm currently using ECHO in the PHP script to output the time and it shows up fine when I access the script from my browser, but I have tried placing client.available() calls at multiple points in my arduino code and it never seems to receive any data back. Since I'm not familiar with PHP, I'm likely either missing a step, or going about this completely wrong.

Codes are posted below. Any suggestions?

-Scott

Arduino:

#include <WiFi.h>
#include <SPI.h>

int status = WL_IDLE_STATUS;
WiFiClient client;

#define ssid "my_ssid"

void setup() {
  Serial.begin(9600);
  if (WiFi.status() == WL_NO_SHIELD) {  // check for the presence of the shield
    Serial.println("WiFi failed"); 
    while(true);
  } 
  while (status != WL_CONNECTED) {  // attempt to connect to Wifi network
    Serial.print("Connecting:");
    Serial.println(ssid);   
    status = WiFi.begin(ssid);
    delay(5000);  // wait for connection:
  }  
}

void loop() {
  servePage();
  delay(10000);
}

void servePage() {
  Serial.println("connecting to server");
  String url = "http://my_website.com/update.php?ID=1&DATA=0";
  char server[] = "www.my_website.com";
  boolean complete = false;
  byte timeout = 0;
  
  while (!complete) {
    if (client.connect(server, 80)) {
      client.print("GET ");
      client.print(url);
      client.println(" HTTP/1.1");
      client.println("Host: www.my_website.com");
      //delay(500);
      //Serial.println(client.available());
      client.println("Connection: close");
      client.println();
      Serial.println("Update complete");
      complete = true;
    }
    timeout++;
    if (timeout > 10) {
      Serial.print("update failed");
      while (true) {}
    }    
  }
  delay(500);
  Serial.println(client.available());
  delay(50);
  client.stop();
}

PHP:

<?PHP

$ID = $_GET['ID'];
$DATA = $_GET['DATA'];

echo date("G:i:s");

?>
  String url = "http://my_website.com/update.php?ID=1&DATA=0";

Using the String class risks memory fragmentation and the kind of occasional crash that is one of the symptoms you're complaining about.

Change this to char url[] = "http://..." and it might be more reliable.

-br

Update: in order to get the response back from the PHP script, you will need to client.read() all the characters it sends, and perhaps print them.

I will take a look at switching over to char instead of String.

I am aware that I will need to eventually client.read() in the returned data, but client.available() is telling me that there is nothing to read.

-Scott

If you think about it, it's highly unlikely that there will be any data for several hundred milliseconds at least, as your GET request goes to the server, your script runs, and the result comes back. Your client.available call is about zero milliseconds after the GET request, so of course it returns false.

You need a little loop to hang out and wait for client.available to go true, and then read/print until it goes false.

For style points, add a timeout...

-br

At one point during my troubleshooting, I did have a loop that checked client.available() every 100ms for 5 or 6 seconds and still got nothing.

Can anyone confirm that ECHO is the right function that I should be using on the PHP side? Is the arduino looking for any kind of a header on the returned data or is just ECHOing a timestamp fine?

-Scott

You've already confirmed the script works, so echo must be okay:

it shows up fine when I access the script from my browser

Is the arduino looking for any kind of a header on the returned data

Not until you write some code that says client.read(). There is no magic. You have to read every character of the response, starting with the headers.

-br

Edit: It might be worthwhile to check out the ethernet webclient example…

You've already confirmed the script works, so echo must be okay:

it shows up fine when I access the script from my browser

The script works in my browser, yes. Not being very familiar with how the behind-the-scenes internet works, I do not know whether anything different is needed for it to work with the arduino instead or if it acts exactly like my web browser.

Not until you write some code that says client.read()

I'm fully aware of how .read() works - there is no point in .read()ing if there is no .available() to read from. I do not have this in my code at the moment because nothing is showing up in the buffer to read.

-Scott

Then wait a little longer. Your timeout should be on the order of 30 seconds. It can easily take several seconds for your reply to start coming back.

See waitForInput at line 127 here: socket.io-arduino-client/SocketIOClient.cpp at master · billroy/socket.io-arduino-client · GitHub

-br

Edit: Another thing to check: what do the access and error logs on the server say when your sketch sends the GET request?

I think I see a bug that may account for the problem you're seeing.

It's this same line of code:

  String url = "http://my_website.com/update.php?ID=1&DATA=0";

The url that is sent in a get request is not supposed to include the http://mywebsite.com part. Just the url relative to the server. So, this might work better for you, and fix the String / char* thing at the same time:

  char *url = "/update.php?ID=1&DATA=0";

I wouldn't be surprised if you were getting an error in your error log before, and I bet this change would help.

-br

Thanks for the advice so far.

I stumbled on some example code and have been able to get farther along with it (aka: I'm now getting data back from the server), but I am getting a 404/No input file specified error even though I can browse to the page without an issue from my PC. Any ideas what might be going on?

Arduino:

#include <SPI.h>
#include <WiFi.h>

char ssid[] = "my_SSID";          //  your network SSID (name)

int status = WL_IDLE_STATUS;
char servername[]="my_website.com";

WiFiClient client;

void setup() {
  Serial.begin(19200);
  Serial.println("Attempting to connect to WPA network...");
  Serial.print("SSID: ");
  Serial.println(ssid);

  status = WiFi.begin(ssid);
  if ( status != WL_CONNECTED) {
    Serial.println("Couldn't get a wifi connection");
    // don't do anything else:
    while(true);
  }
  else {
    Serial.println("Connected to wifi");
    Serial.println("Starting connection...");
    // if you get a connection, report back via serial:
    if (client.connect(servername, 80)) {
      Serial.println("connected");
      // Make a HTTP request:
      client.println("GET /my_folder/hello_world.php?ID=0 HTTP/1.0");
      client.println();
    }
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    while (client.available()) {
      Serial.print(char(client.read()));
    }
  }

  // if the server's disconnected, stop the client:
  if (!client.connected() && !client.available()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

    // do nothing forevermore:
    for(;;)
      ;
  }
}

hello_world.php:

<?PHP
$x = $_GET['ID'];
echo 'hello world';
echo $x;
?>

Error returned in serial monitor:

HTTP/1.1 404 Not Found
Content-Type: text/html
Server: Microsoft-IIS/7.0
X-Powered-By: ASP.NET
Date: Thu, 09 May 2013 15:16:32 GMT
Connection: close
Content-Length: 25

No input file specified.

Edit: I'm working with IT to get the server logs

You removed the Host: header, which is probably needed, and changed the HTTP/1.1 to HTTP/1.0, which won't help.

Whenever you have a problem like this the first thing to do is to check the error and access logs to see what's really being received by the server. That would be a good place to start, after making the two fixes above.

-br

HTTP/1.1 404 Not Found

It did not find that file. What happens if you use this in a web browser address bar?
http://my_website.com/my_folder/hello_world.php?ID=0

Is your site being hosted on a virtual server? If so, like billroy said, you must send a Host parameter. I also use a "Connection: close" and "HTTP/1.1".

      // Make a HTTP request:
      client.println("GET /my_folder/hello_world.php?ID=0 HTTP/1.1");
      client.println("Host: my_website.com\r\nConnection: close\r\n");

I eliminated the last client.println() by putting it in the Host send (\r\n). That way, it all goes in one packet.

Those last few changes did the trick - I'm finally seeing the echo. Thanks guys!

-Scott