Arduino WebClient

Hi! I am building up a web interface for Arduino. but I am not really experienced in Arduino programming. I have two php files in a server and i would like to send data to one (receive.php) of them and receive data from the other (send.php).
This is my Arduino code, it sucessfully sends data, but fails to receive a string from the server (which could be either “led1=0” or “led1=255”).

#include <Ethernet.h>;

int led1 = 6;
String stat1 = "led1=255";
String stat2 = "led1=0";
 
byte mac[] = {0x90,0xA2,0xDA,0x00,0x55,0x8D};

unsigned long lastConnectionTime = 0;
const unsigned long postingInterval = 500L;
 
void setup()
{
Ethernet.begin(mac);
delay(1000);
pinMode(led1, OUTPUT);
digitalWrite(led1, HIGH);
delay(1000);
digitalWrite(led1, LOW);
delay(1000);
}
 
void loop(){

String stat;
if(digitalRead(led1) == HIGH){
  stat+="";
  stat+="255";
}
if(digitalRead(led1) == LOW){
  stat+="";
  stat+="0";
}
String data;
data+="";
data+="device=led1&value=" + stat;

if (client.connect("server",80)) {
client.println("POST /receive.php HTTP/1.1");
client.println("Host: server");
client.println("Content-Type: application/x-www-form-urlencoded");
client.println("Connection: close");
client.print("Content-Length: ");
client.println(data.length());
client.println();
client.print(data);
client.println();

  String action;
  
  if (client.available()) {
    char c = client.read();
  }

  if (millis() - lastConnectionTime > postingInterval) {
    httpRequest(action);
    if(stat1 == action){
      digitalWrite(led1, HIGH);
    }
    if(stat2 == action){
      digitalWrite(led1, LOW);
    }
  }

}

delay(500);

}

int httpRequest(String& inData) {

  inData = "";
  client.stop();

  if (client.connect("server", 80)) {
    // send the HTTP PUT request:
    client.println("GET /send.php HTTP/1.1");
    client.println("Host: server");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();

     while (client.connected()){
      while (client.available()) {
     char thisChar = client.read();
     inData += thisChar;
     }
     client.stop();
     return 1;
     }

    lastConnectionTime = millis();
  } else {
    return 0;
  }
}

I know the code is untidy and inefficient, but it is only for testing purposes. Thank you for your help!

I suspect that at least part of the problem is requiring that the server respond within a few microseconds.

    client.println();

     while (client.connected()){
        while (client.available()) {
           char thisChar = client.read();
           inData += thisChar;
        }
     client.stop();
     return 1;
     }

You should note the time and wait until you receive the result or a reasonable timeout expires. I would also send the received lines to Serial Monitor to see what exactly is being returned.

@johmwasser: That code waits for a server response. Granted it is "Perfect World" code with no timeout, but it should read the response from the server. The server will close the connection from its end when finished sending.

The challenge I see is the String data type. It has never failed to crash my sketches.

But besides that, inData has no limit on it. A server can respond with a rather large amount of text.

I suspect the problem is that the code is providing the proper responses.

When acting as a web server, the Arduino must send a HTTP response.

The OP needs to look at the "handshaking" that is in the WebServer example sketch and the WebClient example sketch.

Thank you for your help. Now I got two working sketches, but I obviously need to have only one.

Here they are:

This one receives a char sent by a php echo (a or b) and turn on or off a led accordingly.

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

int led1 = 6;

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

EthernetClient client;

char server[] = "server";

unsigned long lastConnectionTime = 0;
const unsigned long postingInterval = 1000L;

void setup() {
  
  Serial.begin(9600);
  while (!Serial) {
    ; 
  }

  delay(1000);
  
  Ethernet.begin(mac);

  pinMode(led1, OUTPUT);
  digitalWrite(led1, HIGH);
  delay(1000);
  digitalWrite(led1, LOW);
  delay(1000);  
  

  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());
}

void loop() {

  if (client.available()) {
    char c = client.read();
    Serial.write(c);
    if(c == 'a'){
      digitalWrite(led1, LOW);
    }
    if(c == 'b'){
      digitalWrite(led1, HIGH);
    }
  }


  if (millis() - lastConnectionTime > postingInterval) {
    httpRequest();
  }

}

// this method makes a HTTP connection to the server:
void httpRequest() {

  client.stop();

  if (client.connect(server, 80)) {
    Serial.println("connecting...");

    client.println("GET /send.php HTTP/1.1");
    client.println("Host: server");
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();

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

This one sends the led status to a php script that saves it to a database.

#include <Ethernet.h>;

int led1 = 6;
 
byte mac[] = {0x90,0xA2,0xDA,0x00,0x55,0x8D};
EthernetClient client;
 
void setup()
{
Ethernet.begin(mac);
delay(1000);
pinMode(led1, OUTPUT);
digitalWrite(led1, HIGH);
delay(1000);
}
 
void loop(){
String stat;
if(digitalRead(led1) == HIGH){
  stat+="";
  stat+="255";
}
if(digitalRead(led1) == LOW){
  stat+="";
  stat+="0";
}
String data;
data+="";
data+="device=led1&value=" + stat;

if (client.connect("server",80)) {
client.println("POST /receive.php HTTP/1.1");
client.println("Host: server");
client.println("Content-Type: application/x-www-form-urlencoded");
client.println("Connection: close");
client.print("Content-Length: ");
client.println(data.length());
client.println();
client.print(data);
client.println();
}

delay(500);

}

I need one sketch to do what those two do. I’ve been trying to figure out how to do it, but I would really appreciate a little help. Thank you!

I don't understand why you need to send the status.

The Arduino is being told what to do by the receive.php script.

Because I want the website to tell me whether the led is on or off, because if I don’t, I wouldn’t know if I’m turning the led on or off when clicking the button. The server scripts and html are finished and they work.

Because I want the website to tell me whether the led is on or off, because if I don’t, I wouldn’t know if I’m turning the led on or off when clicking the button. The server scripts and html are finished and they work.

You have two scripts where the Arduino is a client. You should have ONE script with the Arduino as server. There is no reason to be storing light status in a relational database. Every time the client wants to know the status of the lights, it should ask the Arduino. If the status might change outside of the client’s control, the client needs to be told to ask for the status on a regular basis (using the appropriate meta tags for refresh).

The client should make a GET request when a form’s submit button is pressed.

The server scripts you have have no real purpose.

SurferTim:
@johmwasser: That code waits for a server response.

I beg to differ. If the response is not immediately available the code is equivalent to:

    while (client.connected()) {
        client.stop();
        return 1;
    }

If the "client.stop();" didn't end the 'while' loop, the "return 1;" certainly did.

After some thinking, I concluded that it was better to have only one php script, so my arduino would only need to make one connection. I came up with these:

PHP:

<?php

require_once("connect.php");

$dev = $_POST['device'];
$value = $_POST['value'];

if ($value == "255") {
    $value = 255;
}
if ($value == "0") {
    $value = 0;
}

$db = "dbname";
mysqli_select_db($connection, $db);

$write = "UPDATE control SET status = $value WHERE device='$dev'";
$reswrite = mysqli_query($connection, $write);

$query = "SELECT * FROM control";
$result = mysqli_query($connection, $query);

while ($row = mysqli_fetch_assoc($result)) {
	if($row['action'] == 0){
	    echo 'a';
	}
	if($row['action'] == 255){
	    echo 'b';
	}
}

?>

ARDUINO

#include <Ethernet.h>

int led1 = 8;

// assign a MAC address for the ethernet controller.
// fill in your address here:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
// fill in an available IP address on your network here,
// for manual configuration:
//IPAddress ip(192, 168, 1, 177);

// fill in your Domain Name Server address here:
//IPAddress myDns(1, 1, 1, 1);

// initialize the library instance:
EthernetClient client;

char server[] = "SERVERNAME";
//IPAddress server(64,131,82,241);

unsigned long lastConnectionTime = 0;             // last time you connected to the server, in milliseconds
const unsigned long postingInterval = 1000L; // delay between updates, in milliseconds
// the "L" is needed to use long type numbers

void setup() {
  // give the ethernet module time to boot up:
  delay(1000);
  // start the Ethernet connection using a fixed IP address and DNS server:
  Ethernet.begin(mac);

  pinMode(led1, OUTPUT);
  digitalWrite(led1, HIGH);
  delay(1000);
  digitalWrite(led1, LOW);
  delay(1000);
}

void loop() {
  // if there's incoming data from the net connection.
  // send it out the serial port.  This is for debugging
  // purposes only:
  if (client.available()) {
    char c = client.read();
    if(c == 'a'){
      digitalWrite(led1, LOW);
    }
    if(c == 'b'){
      digitalWrite(led1, HIGH);
    }
  }

  // if ten seconds have passed since your last connection,
  // then connect again and send data:
  if (millis() - lastConnectionTime > postingInterval) {
    httpRequest();
  }

}

// this method makes a HTTP connection to the server:
void httpRequest() {
  // close any connection before send a new request.
  // This will free the socket on the WiFi shield
  client.stop();

  String stat;
  if(digitalRead(led1) == HIGH){
    stat+="";
    stat+="255";
  }
  if(digitalRead(led1) == LOW){
    stat+="";
    stat+="0";
  }
  String data;
  data+="";
  data+="device=led1&value=" + stat;

  // if there's a successful connection:
  if (client.connect(server, 80)) {
    // send the HTTP PUT request:
    client.println("POST /php/hardware.php HTTP/1.1");
    client.println("Host: HERE-WAS-THE-SERVERNAME");
    client.println("Content-Type: application/x-www-form-urlencoded");
    client.println("Connection: close");
    client.print("Content-Length: ");
    client.println(data.length());
    client.println();
    client.print(data);
    client.println();

    // note the time that the connection was made:
    lastConnectionTime = millis();
  } else {
    // if you couldn't make a connection:
  }
}

The arduino code above is a modified example. Both are only for testing purposes. Shouldn’t it work? Where am I making the mistake?
Thank you for your help!

Shouldn't it work?

If the redacted stuff was correct, yes.

But, suppose that the server said "The requested script does not have the proper permissions". What is your code going to do? It is going to turn an LED off. How will THAT communicate anything to you?

The comment was referring to some code you deleted. PUT THAT CODE BACK!

Where am I making the mistake?

Well, the code did something. You didn't tell us what it actually did. So, we don't even know what the mistake was, let alone how to fix it.

My apology johnwasser. It is missing a brace.

     while (client.connected()){
        while (client.available()) {
           char thisChar = client.read();
           inData += thisChar;
        }
// needs this brace
     }
     client.stop();

There was information missing. Arduino is going to post some data to the php script. The script will modify a database table accordingly, then read another field of the same table and echo it to arduino. The table, which is named control, is structured like this:

device status action
led1 0 0

The field to be modified according to the posted data is status, and the field read and returned to arduino is action. The web interface will read the status and a button will modify the action field.

Your new Arduino code is not reading the response from the server. How do you expect to retrieve this data?

What about this part? It is at the beginning of the loop.

  if (client.available()) {
    char c = client.read();
    if(c == 'a'){
      digitalWrite(led1, LOW);
    }
    if(c == 'b'){
      digitalWrite(led1, HIGH);
    }
  }

Have you displayed the response? How many 'a' and 'b' characters are there in the response header?

You were better off with your old code.

SurferTim:
Have you displayed the response? How many 'a' and 'b' characters are there in the response header?

You were better off with your old code.

That was my point in reply #10. It was ignored there, too.