(SOLVED)Yun Shield EthernetClient Issue

Hello All,

I am tring to move a sketch that runs fine on a ethernet shield/mega2560 combination to a Yun Shield/mega2560 combination. But the Yun Shield combo is raising an error when it gets to this code in the sketch:

if (!client.connect(server, 80)) {
Console.println("-> Connection failure detected: Resetting ENC!"); // only use serial when debugging
} else {
client.stop();
}

client.connect(server, 80) is never true so it raises the "Connection failure detected..." message.

Like I said, the sketch works fine on the ethernet shield/mega2560 combo. I just want the sketch operational in the field on the Yun Shield so I can ssh into it when I need to.

Any ideas about why this might be happening?

Thank you in advance,
Murrah Boswell

I am getting 0 for the return code for the client.connect(server,80) statement:

int ret = client.connect(server, 80);
if (ret == 1) {
Console.println("connected");
}
else {
Console.println("Connection failed");
Console.println(ret);
Console.println(client.status());
}

returns 0 return code and 0 for client.status

otrcomm:
Any ideas about why this might be happening?

Yes. Networking with the Yun is completely different than with the Ethernet shield. It sounds like you're trying to request a web page from a server, Take a look at the HttpClient Example to see a minimum implementation of fetching a web page. It's quite a bit different than the Ethernet shield code.

With the Ethernet shield, the sketch has to do everything. With the Yun, the network is handled by the Linux side, and the sketch only needs to do the high-level stuff.

Post your full code (in code tags) if you have any questions.

ShapeShifter:
Yes. Networking with the Yun is completely different than with the Ethernet shield. It sounds like you’re trying to request a web page from a server, …

No, I am trying to open two separate connections to different servers, one on port 80 and the other on port 8080. The connection on port 80 sends a GET and the query string is read by a php script that loads data into a mysql database:

if (!client.connect(server, 80)) { #ifdef DEBUG Serial.println("-> Connection failure detected: Resetting ENC!"); // only use serial when debugging #endif } else { client.stop(); }

if (client.connect(server, 80)) {
#ifdef DEBUG
Serial.println(F("Client request 10.11.20.123:port 80: "));
#endif
/**********************************************************************************************/
// // Make a HTTP request:
// // Will need different scripts to read different sensors in various locations, so
// // could have various “add_data.php” scripts in different directories off /var/www/

client.print( “GET http://10.11.20.123/septic_houses/add_septic_house_D_data.php?");
#ifdef DEBUG
Serial.print( “GET http://10.11.20.123/septic_houses/add_septic_house_D_data.php?");
#endif
client.print(“datastring”); // print: datastring=
client.print(”=”);
client.print(datastring);
#ifdef DEBUG
Serial.print(“datastring”); // print: datastring=
Serial.print("=");
Serial.println(datastring);
#endif
// Not exactly sure what this code does yet, but it is necessary :slight_smile:
client.println( " HTTP/1.1");
client.println( “Host: 10.11.20.123” );
client.print(" Host: ");
client.println(server);
client.println( “Connection: close” );
client.println();
client.println();
client.stop();
} // End if (client.connect(server, 80))

Then the connection on port 8080 is on another server where I punch out data that is captured by a python script:

client = server2.available(); if(client) { boolean currentLineIsBlank = true; #ifdef DEBUG Serial.println(F("Server2")); Serial.print(F("Client request port 8080: ")); #endif while (client.connected()) { while(client.available()) { char c = client.read(); if (c == '\n' && currentLineIsBlank) { // send an http query string #ifdef DEBUG Serial.print(F("POST data: ")); Serial.println(); Serial.println(F("Sending query string")); #endif client.print(datastring);

client.stop();
}
else if (c == ‘\n’) {
currentLineIsBlank = true;
}
else if (c != ‘\r’) {
currentLineIsBlank = false;
}
}
}
#ifdef DEBUG
Serial.println(F(“done”));
#endif
} // End if(client)

This all works fine on the EthernetShield combo but not on the YunShield comb. I am not trying to do this on a Yun.

Thank you for you response,
Murrah Boswell

@ShapeShifter

BTW, the HTTPClient sketch you linked me to works fine on a YunShield with modifications to print to Console instead of to the serial port. I.e.,

#include <Bridge.h>
#include <Console.h>
#include <HttpClient.h>

void setup() {
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
Bridge.begin();
Console.begin();
}

void loop() {
HttpClient client;
client.get(“http://arduino.cc/asciilogo.txt”);

while (client.available()) {
char c = client.read();
Console.print(c);
}
Console.flush();

delay(5000);
}

The HttpClient works fine, it appears that the Ethernet client does not function properly on the YunShield.

Thank you,
Murrah Boswell

otrcomm:
The HttpClient works fine, it appears that the Ethernet client does not function properly on the YunShield.

Correct. Nothing in the library for the Ethernet Shield will work on the Yun or the Yun Shield. There are a few differences between a Yun and a YunShield, but they are very close to each other. Just like the Yun, networking with a YunShield is also nothing like the Ethernet Shield. The whole networking architecture is completely different. Forget that you ever heard of the Ethernet Shield or anything in Ethernet.h – it will only serve to confuse you with the Yun or YunShield.

Looking at your code… (BTW, please use the CODE tags when posting code: click on the button that looks like a scroll with blue angle brackets, then paste your code between those tags.)

You didn’t post the beginning of your sketch, so we don’t see the setup. But don’t #include Ethernet.h and take out just about everything that has to do with MAC addresses and setting up the Ethernet. All you need is to #include Bridge.h and call Bridge.begin().

Your port 80 code:

if (client.connect(server, 80)) {
#ifdef DEBUG
    Serial.println(F("Client request 10.11.20.123:port 80: "));
#endif   
/**********************************************************************************************/
//      // Make a HTTP request:
//      // Will need different scripts to read different sensors in various locations, so
//      // could have various "add_data.php" scripts in different directories off /var/www/

      client.print( "GET http://10.11.20.123/septic_houses/add_septic_house_D_data.php?");
#ifdef DEBUG
        Serial.print( "GET http://10.11.20.123/septic_houses/add_septic_house_D_data.php?");
#endif
    client.print("datastring"); // print: datastring=
    client.print("=");
    client.print(datastring);
#ifdef DEBUG
    Serial.print("datastring"); // print: datastring=
    Serial.print("=");
    Serial.println(datastring);
#endif

This will be replaced with a call to HttpClient.get(). Rather than print() each segment of the URL to the client, you will need to build a string, and then pass that full string to HttpClient.get().

      // Not exactly sure what this code does yet, but it is necessary :)   
      client.println( " HTTP/1.1");
      client.println( "Host: 10.11.20.123" );
      client.print(" Host: ");
      client.println(server);
      client.println( "Connection: close" );
      client.println();
      client.println();
      client.stop();
  } // End if (client.connect(server, 80))

You won’t need this section. This is sending the HTTP headers to the server, and HttpClient takes care of that for you.

Now for the port 8080 part. You don’t show the portion where you are opening the connection, but I assume that you are re-using client for this. This part is a little more complicated because of the different port number, and because you’re doing a POST, not a get. But I think it can be done.

HttpClient is really just a wrapper for curl. To do a POST with curl, the easiest way is to use the --data option. So the parameter would be something like http://myserver.com:8080/my/page/url --data <datastring>

You will basically have to pre-pend your server name, port, URL, and " --data " to the beginning of datastring, and then send the whole string in the HttpClient.get() call. Or at least that’s the theory: I’ve not tried it, and I’m not an expert in using curl. If you can come up with a string that works for curl, you should be able to get it to work with HttpClient. If all else fails, you can always create a Process object and make the curl call directly.

Now, with all of that said and done… is this all that the sketch does, get data from one server and send it to another? If so, it might be easier and more efficient to do everything on the Linux side. You will have a lot more power and flexibility there. You really only NEED to use a sketch to access the shield header pins, just about everything else (especially networking) may be easier or at least more efficient doing on the Linux processor.

@shapeshifter -

Thank you very much for your help!

I got it working using YunServer, YunClient and Bridge.

Thanks for the heads-up on the CODE tags.

I will modify my sketch to use HttpClient like you suggested.

What the sketch does is read digital and analog data from various sensors in a sewage pumping control house. I have four separate control houses scattered around the property and will have a YunShield system at each house. I also use another variation of the sketch to read data from various sensors in my well house to control well pumps and chlorination system.

Then the data from these various systems is sent to a data server and stored in mysql and also captured on the YunShield port 8080 thread by a python script so my supervisor can analyze the data in real-time.

The YunShield is the server that uses port 8080 and I set it up like so:

#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>
#include <Console.h>
...
...
...
char server[] = "10.11.20.123";  // IP address of data server for mysql
YunServer server2(8080);
// Bridge startup
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
Bridge.begin();
digitalWrite(13, HIGH);
delay(2000);
server2.begin();

void loop()
{

  YunClient client;

// Setup and read some digital and analog pins 
...
...
...
if (client.connect(server, 80)) {
...
...
...
} // End if (client.connect(server, 80))

client = server2.accept();
  if(client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
        char c = client.read();
        if (c == '\n' && currentLineIsBlank) {
          // send an http query string
          client.print(datastring);
          
          client.stop();
        }
        else if (c == '\n') {
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
    } 
  }

This is the heart of the sketch as it is now and it does work on a YunShield/Mega2560 combo.

I will rework it to use the HttpClient class.

“You really only NEED to use a sketch to access the shield header pins, just about everything else (especially networking) may be easier or at least more efficient doing on the Linux processor.”

How would I separate the task between the shield and the Linux side? I am very interested in learning how to do this. Do you have any examples of projects that do this? I have installed the avr toolchain on the YunShield and can compile sketches. I have not tried to compile any c-code yet. I am very new at working with the Arduino platforms and the YunShield, but I am eager to learn how to work with them.

Thank you again for all your help,
Murrah Boswell

otrcomm:
How would I separate the task between the shield and the Linux side? I am very interested in learning how to do this. Do you have any examples of projects that do this? I have installed the avr toolchain on the YunShield and can compile sketches. I have not tried to compile any c-code yet.

Of course you can write code in C to run on the Linx side, but Python seems to be a much more popular choice. Especially when it comes to communications between the Linux side and a sketch, as the C support for the Bridge class seems to be lacking compared to Python. (At least I could never get it to work, I finally resorted to translating the whole program to Python, just to have Bridge communications support.)

Speaking of the Bridge Library, that is the key to communications between the Linux side and a sketch.

One option is to call Bridge.put() in the sketch to save sensor readings as named key/value pairs. Then, the Linux side can asynchronously get() those values, package them up, and send them out. But what is really interesting about put() is that the values can be read remotely with a simple HTTP request. For example, http://<yun_address>/data/get/xyz will return the value that was put() using key “xyz”. In addition, http://<yun_address>/data/get (note that there is no key name) will return ALL values that have been put() to the Bridge. It’s possible that your remote systems won’t have to do any explicit networking themselves: the sketches on those systems just read sensor values and store the latest value to the Bridge, then the master system makes data get requests to gather the information. Those requests could be done by a sketch on the master using HttpClient calls, or could be done in Python using curl.

It’s also possible to remotely put() a command to a system using http://<yun_address>/data/put/abc/xyz which will put the value “xyz” with the key “abc”. The sketch (or Python code) on that system then just needs to call Bridge.get() to read the value.

A sketch can also communicate with the Linux side using the Process Class. This will send a command string to Linux to start a process. The data for Linux can either be in the command line for a self contained sample, or once the process is started, you can use client.write() to send data to the Linux process stdin, and client.read() to read from the process stdout. (As we recently discovered, the process stdout is buffered, so the process should call sys.stdout.flush() after writing data for the sketch, so that it is sent immediately.)

So, hopefully you can see that while the way to do networking is very different, it is also very powerful. You have the Linux processor which can do a lot of the work for you without any special coding, plus you can write your own application specific coding, plus you might just find an existing package that does a lot of the work for you. For example, check this out: HOWTO for simple monitoring and WWW graphs

@ShapeShifter

Thank you for the info, I will study it all in detail.

How do I get the moderator make this thread SOLVED ?

Thank you again,
Murrah Boswell

otrcomm:
How do I get the moderator make this thread SOLVED ?

You can do it yourself. Go back to the original post, hover over the "More..." drop-down in the lower right corner of the post, and select "Modify." Besides being able to edit your post, you can also edit the subject and add the solved tag.