Connecting two Arduinos over network?

Alrighty. I've been searching for information how to do this properly, but I haven't been able to find anything conclusive, and I would really want some advice before I drop money on tech which might not help me.

I have a project where I need to have two Arduinos, in two different locations, equipped with sensors reading various things, which in turn should be able to rely the data to its counterpart. So it's not just one Arduino talking to the other, the communication needs to go both ways. The locations are separated by about 100-150ft or so, but they are on the same network, so I could just hook up an ethernet cable to a socket and get connectivity that way. I cannot however lay any new cable, so it either needs to be able to go via the ethernet sockets, via WIFI or other wireless technology.

Now, my question, can I get this kind of behaviour by using two Ethernet shields, or are they strictly for talking with the internet, not necessarily listening from it?

I've been looking into XBees as well, however, due to the distance and the amount of walls in between it seems like a shaky concept at best (unless I drop several hundred dollars to buy the really long range ones, which should be able to penetrate quite a few walls short range). In the past I've had trouble getting the regular cheaper ones to even talk through one wall, let alone through several and over a busy road.

Basically, I already have the Arduino boards, but I'm trying to keep everything else I need to get under about $150 or so. Data rate is not really important, I'd happily sacrifice range and connectivity over speed. I've done quite a bit of work with Arduino in the past, though never anything involving connectivity like this, so any insight would be helpful.

Thanks!

Via ethernet with the Ethernet Shield is possible.
I think udp would be the best protocol, but I haven't used udp myself.
You could make one of them the 'master' and send its data to the other one and also requests the data from the other Arduino.

I have not found a good example, so hopefully someone else knows good working code.

I think wireless is also no problem, 150ft is 45 meters.
Did you use 2.4GHz modules before ? some cheap ones have only a range of a few meters or less.
With a good quality 433MHz TX/RX module with an antenna, it should be possible.

What you're describing can be done via Ethernet, but you have some work to do. If your network uses dynamic addressing then you need to use DHCP to assign an address for each node, and then one node will need to use DNS to find the other node's address. If it's using static addresses then you will need to allocate an address for each node and hard-code or configure each node with its address. (In a typical corporate or home network, dynamic addressing is far more likely.) The standard Ethernet library supports both modes of operation.

You will have to understand the nature of the data being passed between them and decide how to encode that within a network message and how the sequence of messages will be controlled. It may be that a client-server architecture is suitable, but perhaps you will need a peer-to-peer arrangement in which case you need to provide a way for both devices to find each other. I don't think that any more specific advice is possible without knowing more about the nature of the data you need to communicate.

Essentially the data being transmitted could just basically be an on or off state, a 1 or 0, so it doesn't need to be anything fancy. Imagine having an IR sensor that's tracking if something passes by it, that could in turn programmatically in the Arduino be translated to a 1 or a 0, on or off, and sent to the other Arduino to actually do something with, let's say to turn on an LED. So it could just send a stream of 0s constantly when nothing is happening and it's just listening waiting for a 1 to activate. Though, that's one way communication, I want the other Arduino to be able to do the same thing back. The systems should be replicas of each other (more or less).

I haven't done this kind of stuff before, only been working with XBees, and connecting them to each other (range aside) has been a breeze, so I hope I'm coming across clearly what I need. If not I'd be happy to hear some suggestions how I could do it instead.

It's just a matter of learning the Ethernet library (for boards with the Wiznet W5100 or W5200 chips) or EtherCard library (for boards with ENC28J60 chips).

I've only used the EtherCard library, myself. The boards are dirt cheap and so am I ;). But you can find examples at EtherCard/examples at main · njh/EtherCard · GitHub

Do you have any reliability requirements - does it matter (to the sender) whether the receiver receives the notifications or not?

I have a project where I need to have two Arduinos, in two different locations, equipped with sensors reading various things, which in turn should be able to rely the data to its counterpart. So it's not just one Arduino talking to the other, the communication needs to go both ways.

Combined client/server code that with some tinkering could probably do bidirectional communication with data and such.

//zoomkat 7-03-12, combined client and server
//simple button GET with iframe code
//for use with IDE 1.0
//open serial monitor and send an g to test client and
//see what the arduino client/server receives
//web page buttons make pins high/low
//use the ' in html instead of " to prevent having to escape the "
//address will look like http://192.168.1.102:84 when submited
//for use with W5100 based ethernet shields
//note that the below bug fix may be required
// http://code.google.com/p/arduino/issues/detail?id=605

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

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //assign arduino mac address
byte ip[] = {192, 168, 1, 102 }; // ip in lan assigned to arduino
byte gateway[] = {192, 168, 1, 1 }; // internet access via router
byte subnet[] = {255, 255, 255, 0 }; //subnet mask
EthernetServer server(84); //server port arduino server will use
EthernetClient client;
char serverName[] = "web.comporium.net"; // (DNS) zoomkat's test web page server
//byte serverName[] = { 208, 104, 2, 86 }; // (IP) zoomkat web page server IP address

String readString; //used by server to capture GET request 

//////////////////////

void setup(){

  pinMode(5, OUTPUT); //pin selected to control
  pinMode(6, OUTPUT); //pin selected to control
  pinMode(7, OUTPUT); //pin selected to control
  pinMode(8, OUTPUT); //pin selected to control

  //pinMode(5, OUTPUT); //pin 5 selected to control
  Ethernet.begin(mac,ip,gateway,gateway,subnet); 
  server.begin();
  Serial.begin(9600); 
  Serial.println("server/client 1.0 test 7/03/12"); // keep track of what is loaded
  Serial.println("Send an g in serial monitor to test client"); // what to do to test client
}

void loop(){
  // check for serial input
  if (Serial.available() > 0) 
  {
    byte inChar;
    inChar = Serial.read();
    if(inChar == 'g')
    {
      sendGET(); // call client sendGET function
    }
  }  

  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();

        //read char by char HTTP request
        if (readString.length() < 100) {

          //store characters to string 
          readString += c; 
          //Serial.print(c);
        } 

        //if HTTP request has ended
        if (c == '\n') {

          ///////////////
          Serial.print(readString); //print to serial monitor for debuging 

            //now output HTML data header
          if(readString.indexOf('?') >=0) { //don't send new page
            client.println(F("HTTP/1.1 204 Zoomkat"));
            client.println();
            client.println();  
          }
          else {   
            client.println(F("HTTP/1.1 200 OK")); //send new page on browser request
            client.println(F("Content-Type: text/html"));
            client.println();

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

            client.println(F("<H1>Zoomkat's simple Arduino 1.0 button</H1>"));

            // DIY buttons
            client.println(F("Pin5"));
            client.println(F("<a href=/?on2 target=inlineframe>ON</a>")); 
            client.println(F("<a href=/?off3 target=inlineframe>OFF</a>

")); 

            client.println(F("Pin6"));
            client.println(F("<a href=/?on4 target=inlineframe>ON</a>")); 
            client.println(F("<a href=/?off5 target=inlineframe>OFF</a>

")); 

            client.println(F("Pin7"));
            client.println(F("<a href=/?on6 target=inlineframe>ON</a>")); 
            client.println(F("<a href=/?off7 target=inlineframe>OFF</a>

")); 

            client.println(F("Pin8"));
            client.println(F("<a href=/?on8 target=inlineframe>ON</a>")); 
            client.println(F("<a href=/?off9 target=inlineframe>OFF</a>

")); 

            client.println(F("Pins"));
            client.println(F("&nbsp;<a href=/?off2468 target=inlineframe>ALL ON</a>")); 
            client.println(F("&nbsp;<a href=/?off3579 target=inlineframe>ALL OFF</a>")); 

            client.println(F("<IFRAME name=inlineframe style='display:none'>"));          
            client.println(F("</IFRAME>"));

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

          delay(1);
          //stopping client
          client.stop();

          ///////////////////// control arduino pin
          if(readString.indexOf('2') >0)//checks for 2
          {
            digitalWrite(5, HIGH);    // set pin 5 high
            Serial.println("Led 5 On");
            Serial.println();
          }
          if(readString.indexOf('3') >0)//checks for 3
          {
            digitalWrite(5, LOW);    // set pin 5 low
            Serial.println("Led 5 Off");
            Serial.println();
          }
          if(readString.indexOf('4') >0)//checks for 4
          {
            digitalWrite(6, HIGH);    // set pin 6 high
            Serial.println("Led 6 On");
            Serial.println();
          }
          if(readString.indexOf('5') >0)//checks for 5
          {
            digitalWrite(6, LOW);    // set pin 6 low
            Serial.println("Led 6 Off");
            Serial.println();
          }
          if(readString.indexOf('6') >0)//checks for 6
          {
            digitalWrite(7, HIGH);    // set pin 7 high
            Serial.println("Led 7 On");
            Serial.println();
          }
          if(readString.indexOf('7') >0)//checks for 7
          {
            digitalWrite(7, LOW);    // set pin 7 low
            Serial.println("Led 7 Off");
            Serial.println();
          }     
          if(readString.indexOf('8') >0)//checks for 8
          {
            digitalWrite(8, HIGH);    // set pin 8 high
            Serial.println("Led 8 On");
            Serial.println();
          }
          if(readString.indexOf('9') >0)//checks for 9
          {
            digitalWrite(8, LOW);    // set pin 8 low
            Serial.println("Led 8 Off");
            Serial.println();
          }         

          //clearing string for next read
          readString="";

        }
      }
    }
  }
} 

//////////////////////////
void sendGET() //client function to send and receive GET data from external server.
{
  if (client.connect(serverName, 80)) {
    Serial.println("connected");
    client.println("GET /~shb/arduino.txt HTTP/1.0");
    client.println();
  } 
  else {
    Serial.println("connection failed");
    Serial.println();
  }

  while(client.connected() && !client.available()) delay(1); //waits for data
  while (client.connected() || client.available()) { //connected or data available
    char c = client.read();
    Serial.print(c);
  }

  Serial.println();
  Serial.println("disconnecting.");
  Serial.println("==================");
  Serial.println();
  client.stop();

}

Chagrin, that's what I expected. I will take a dive off the deep end this afternoon.

PeterH, yes, I would say that is of outmost importance. I can even live with a connection speed of a byte per second as long as I can make sure that every bit of data makes it across. It's not a big hurdle to make analog sensor data into something more compact prior to sending/receiving.

zoomkat, thank you, that looks promising (at least from skimming through the code), I will look into it!

MrPumpernickel:
I would say that is of outmost importance

In that case I suggest you use a TCP socket for the connection, with one Arduino designated as the server and the other as a client.

It's conceivable that you may not always be able to establish a network connection and you will need to decide what to do in that situation - do you keep trying the sample you have until you succeed, or keep taking new samples and throw them away if they can't be sent, or keep a queue of historical data?