If the Arduino doesn't have a working internet connection, nothing works

I've just got an ethermega. Looks like a great board. (It's 100% compatible with the official mega).

I have a question regarding ethernet. I am unclear over how the TCP/IP works. I understand I assign the device an IP in the sketch and I assign it a mac address too. OK so far so good.

I tried this and refreshed my router's 'attached devices' page. The ethermega did not appear. I then added it as a reserved device on the router, adding the mac address and IP the device was claiming. Again - no dice.

I tried to ping the board from a LAN machine. Each ping returned "device not reachable" but the RX light flashed on the board. A glimmer of hope, at last.

How can the device tell the router, which is assigning OTHER devices IPs via DHCP server, that it is just going to be 192.168.0.9? Wouldn't the router have to consent?

Any tips? When I tried to run the NTP RTC update sketch from the playground, it returned "UDP not available". When I totally unplugged the Ethernet cable - same message.

This most basic level of arduino Ethernet interfacing doesn't seem to be covered anywhere!

Thanks.

DANE: How can the device tell the router, which is assigning OTHER devices IPs via DHCP server, that it is just going to be 192.168.0.9? Wouldn't the router have to consent?

The router doesn't have to consent. If a device tries to use an IP address that is from the routers DHCP range the router just might ignore it. Try an address outside the range the router has been told to use for DHCP requests.

Typically you would assign only a MAC address and let DHCP assign an IP address. If you specify an IP address of 192.168.0.9 the Ethernet library is going to assume that the router and DNS server are at 192.168.0.1.

Have you tried the examples from the Ethernet library? Start with the sketch Files->Examples->Ethernet->DhcpAddressPrinter. If that doesn't work you have something wrong in your hardware or router setup.

BTW ping is a specific protocol - if you want ping to work you have to write an ICMP driver (unless your ethernet chip supports it directly). As I understand it DHCP and TCP/IP will work without ICMP, but the router might not (fully) recognise the device without ICMP.

Some client test code you can try.

//zoomkat 2-13-12
//DNS and DHCP-based web client test code
//for use with IDE 1.0
//open serial monitor and send an e to test
//and to see test result
//for use with W5100 based ethernet shields
//browser equivelant URL: 
//http://web.comporium.net/~shb/arduino.txt

#include <SPI.h>
#include <Ethernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
char serverName[] = "web.comporium.net"; // zoomkat's test web page server
EthernetClient client;

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

void setup(){
  Serial.begin(9600); 
  Serial.println("DNS and DHCP-based web client test 2/13/12"); // so I can keep track of what is loaded
  Serial.println("Send an e in serial monitor to test"); // what to do to test
  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    while(true);
  }
  // print your local IP address:
  Serial.print("Arduino IP address: ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print("."); 
  }
  Serial.println();
  Serial.println();
}

void loop(){
  // check for serial input
  if (Serial.available() > 0) //if something in serial buffer
  {
    byte inChar; // sets inChar as a byte
    inChar = Serial.read(); //gets byte from buffer
    if(inChar == 'e') // checks to see byte is an e
    {
      sendGET(); // call sendGET function below when byte is an e
    }
  }  
} 

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

void sendGET() //client function to send/receive GET request data.
{
  if (client.connect(serverName, 80)) {  //starts client connection, checks for connection
    Serial.println("connected");
    client.println("GET /~shb/arduino.txt HTTP/1.0"); //download text
    client.println(); //end of get request
  } 
  else {
    Serial.println("connection failed"); //error message if no client connect
    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(); //gets byte from ethernet buffer
    Serial.print(c); //prints byte to serial monitor 
  }

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

}

aha, thanks all.

I was confused by the DS1307 NTP code:

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x00, 0x11, 0x22, 0x33, 0xFB, 0x11 };         // Use your MAC address
byte ip[] = { 192, 168, 0, 1 };                              // [color=orange]no DHCP so we set our own IP address[/color]
byte subnet[] = { 255, 255, 255, 0 };                        // subnet mask
byte gateway[] = { 192, 168, 0, 2 };                         // internet access via router

Which seems to me to be a static IP version of the below?

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
// Initialize the Ethernet client library
EthernetClient client;

Can I not just replace the first code segment with the second?

Can I not just replace the first code segment with the second?

I wonder which would have been faster. Uploading the code to the Arduino and trying it, or posting on the forum.

Go out on the limb, and find out. You can't damage the Arduino, the ethernet shield, or the internet, by uploading bad code, or every Arduino and ethernet shield in the world would be headed for the landfill and the internet would not be working at all.

I will try to not be so "hardcore" about my response. ;)

You should be able to replace the first code with the second.

The first code (static ip) has the ip and gateway backwards for most router setups. The router/gateway is normally 192.168.0.1, not the Arduino.

BTW, PaulS is correct. Good thing too! Mine would have been in the landfill many months ago. :)

PaulS:

Can I not just replace the first code segment with the second?

I wonder which would have been faster. Uploading the code to the Arduino and trying it, or posting on the forum. Go out on the limb, and find out.

I see what you're saying good buddy! However, sit yourself down for a story.

I'm at work right now, in a break. When I posted earlier, was from the breakfast work break. Much as I love to experiment to find out WHY things work or don't work, the Arduino is not a supported device here!

However, tonight, I'll be at home, with the evening off and all my chores done, barn raised and the pigs mucked out. I wanted to have everything lined up for doing some proper experimenting with the Arduino - not this ultra basic stuff.

Hence me trying to get it sorted in my head now. I'm still unclear why that code (from 2012, after all) would use a difficult, error prone way of assigning IPs when it could use the DHCP facility??

Hope I've clarified why I didn't just try the replace myself. But I take your point. It is preferable to try things out.

But I take your point. It is preferable to try things out.

It is. If you had said "I'm not at home now, so I can't test this, but I'm wondering if this will work" instead of "Will this work", I would have replied quite differently.

Hence me trying to get it sorted in my head now. I'm still unclear why that code (from 2012, after all) would use a difficult, error prone way of assigning IPs when it could use the DHCP facility??

Well, until v1.0, there was no dhcp facility in the ethernet library. That function is brand new. 2012.

And I don't have any problem with that "error prone" way of assigning static ips. But that also changed in 2012. Be careful about converting pre v1.0 code to v1.0. The Ethernet.begin() function (and others) changed formats.

There are still some issued with DHCP in 1.0. Some fixes are in for 1.0.1 ( http://code.google.com/p/arduino/issues/detail?id=742 and http://code.google.com/p/arduino/issues/detail?id=669 ) There is one about maintainging/renewing a lease that might not get in in 1.0.1 http://code.google.com/p/arduino/issues/detail?id=716

Could you post your sketch here? So we could get a quicker grasp of what you are trying to do, and perhaps being able to spot the error as well.

kmpm:
Could you post your sketch here? So we could get a quicker grasp of what you are trying to do, and perhaps being able to spot the error as well.

Sure.

#include <Twitter.h>
#include <Bounce.h>
#include <Wire.h>
#include "RTClib.h"
#include <Servo.h>
#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>	

byte mac[] = {
  0x00, 0x11, 0x22, 0x33, 0xFB, 0x11 }; EthernetClient client; Twitter twitter("secretsandlies");

unsigned int localPort = 8888;             
byte timeServer[] = {
  193, 79, 237, 14};    // ntp1.nl.net NTP server  
const int NTP_PACKET_SIZE= 48;             // NTP time stamp is in the first 48 bytes of the message
byte pb[NTP_PACKET_SIZE];                  // buffer to hold incoming and outgoing packets 
#if ARDUINO >= 100
EthernetUDP Udp;
#endif		

Servo servo1;
#define ledPin1 8      		// the number of the LED pin
#define buttonPin 2		// the number of the button pin
const int pinSpeaker = 7;

int buttonState = LOW;		// used to set the button state
int LedState1 = LOW;		// used to set the LED state
int LedState2 = LOW;	        // used to set the LED state if LED was already on
long LedOnDuration = 10000;	// time to keep the LED on for (10s)
long FlashRate = 400;		// time to keep the LED on for (0.4s)
long previousMillis1 = 0;	// will store last time LED was updated for press 1
long previousMillis2 = 0;       // will store last time LED was updated for press 2

//The pips
unsigned int pip1 = 0;
unsigned int pip2 = 0;
unsigned int pip3 = 0;
unsigned int pip4 = 0;
unsigned int pip5 = 0;
unsigned int pip6 = 0;
unsigned int RTCUD = 0;
unsigned int INITIALSET = 0;

// Instantiate a Bounce object with a 20 millisecond debounce time Bounce nursery = Bounce( buttonPin, 500); int nurseryvalue;

RTC_DS1307 RTC;

enum {
  OFF, ON, FLASH};

void setup()
{
  pinMode(buttonPin,INPUT);      
  pinMode(ledPin1,OUTPUT);      
  pinMode(pinSpeaker, OUTPUT);
  digitalWrite(ledPin1, OFF);
  servo1.attach(6);
  LedState1 = OFF;
  LedState2 = OFF;
  Serial.begin(57600);
  Wire.begin();
  RTC.begin();
  Serial.println("Annunciator Panel v0.7");
  Ethernet.begin(mac);	   
  Udp.begin(localPort);
  Serial.println();
  if (! RTC.isrunning()) {
    Serial.println("Error!: The RTC is NOT running/set!");

  }
}

void loop() {
  DateTime now = RTC.now();
  nursery.update();
  nurseryvalue = nursery.read();
  unsigned long currentMillis = millis();

  if (currentMillis > 20000 && INITIALSET < 1)
  {
    Serial.println("20s have elapsed since power on/reset, so");
    Serial.println("time to sync the clock initially.");
    Serial.println();
    RTCUD = 1;
  }

  if (now.hour() == 14 && now.minute() == 10 && now.second() == 10)
  {
    if (RTCUD < 1)  
    {
      Serial.print("Time to set the clock at: ");
      PrintDateTime(RTC.now());
      Serial.println();
      RTCUD = 1;
    }
  }


  if (RTCUD == 1)
  {
    RTCUD = 0;               
    INITIALSET = 1;      
    Serial.print("RTC before: ");
    PrintDateTime(RTC.now());
    Serial.println();
    sendNTPpacket(timeServer);
    delay(1000);
    if ( Udp.available() ) {

#if ARDUINO < 100
      Udp.readPacket(pb, NTP_PACKET_SIZE); #else
      Udp.read(pb, NTP_PACKET_SIZE);      // New from IDE 1.0,
#endif	
      unsigned long t1, t2, t3, t4;
      t1 = t2 = t3 = t4 = 0;
      for (int i=0; i< 4; i++)
      {
        t1 = t1 << 8 | pb[16+i];      
        t2 = t2 << 8 | pb[24+i];      
        t3 = t3 << 8 | pb[32+i];      
        t4 = t4 << 8 | pb[40+i];
      }

      float f1,f2,f3,f4;
      f1 = ((long)pb[20] * 256 + pb[21]) / 65536.0;      
      f2 = ((long)pb[28] * 256 + pb[29]) / 65536.0;      
      f3 = ((long)pb[36] * 256 + pb[37]) / 65536.0;      
      f4 = ((long)pb[44] * 256 + pb[45]) / 65536.0;
      const unsigned long seventyYears = 2208988800UL;
      t1 -= seventyYears;
      t2 -= seventyYears;
      t3 -= seventyYears;
      t4 -= seventyYears;
      t4 += 1;               
      if (f4 > 0.4) t4++;    
      RTC.adjust(DateTime(t4));
      Serial.print("RTC after : ");
      PrintDateTime(RTC.now());
      Serial.println();
      Serial.println("Time update successful");
      RTCUD = 0;      // RTC has been set for the morning / evening    
      INITIALSET = 1;      // RTC has been set for the morning / evening    
    }
    else
    {
      Serial.println("Error: Time update unsuccessful");
    }
  }

  int y = now.hour();
  int x = now.minute();
  char button1msg[162];
  sprintf(button1msg, "Button 1 registered @ Minute %d, Hour %d", y, x);



  if (nurseryvalue == HIGH)
  {
    if (buttonState == OFF)
    {
      // button pressed
      //===============
      buttonState = ON;
      if (LedState1 == OFF)
      {
        // the button's pressed and LED is OFF
        // turn it ON
        //====================================
        digitalWrite(ledPin1, ON);
        LedState1 = ON;
        //servo1.write(180);
        previousMillis1 = currentMillis;
        Serial.print("initial press of button 1 registered @ ");
        PrintDateTime(RTC.now());
        Serial.println();
        Serial.println("connecting to Twitter...");
        if (twitter.post(button1msg)) {
          int status = twitter.wait();
          if (status == 200) {
            Serial.println("Posted!");
          } 
          else {
            Serial.print("failed : code ");
            Serial.println(status);
          }
        } 
        else {
          Serial.println("connection failed.");
        }
      }
      else if (LedState1 == ON)
      { 		
        // if the button's pressed and LED is ON
        // start FLASHing
        //======================================
        digitalWrite(ledPin1, OFF);
        LedState1 = FLASH;
        //servo1.write(180);
        Serial.print("second press of button 1 registered @ ");
        PrintDateTime(RTC.now());
        Serial.println();
        Serial.println("connecting to Twitter...");
        if (twitter.post("Button 2 Pressed")) {
          int status = twitter.wait();
          if (status == 200) {
            Serial.println("Posted!");
          } 
          else {
            Serial.print("failed : code ");
            Serial.println(status);
          }
        } 
        else {
          Serial.println("connection failed.");
        }
        previousMillis1 = currentMillis;	
      }
    }
  }
  else
  {
    buttonState = OFF;
    servo1.write(0);
  }

  if (previousMillis1 + LedOnDuration < currentMillis) 
  {		
    // If the predefined interval has elapsed for the first button press
    // turn led OFF
    //==================================================================
    digitalWrite(ledPin1, OFF);
    LedState1 = OFF;
  }

  if (LedState1 == FLASH && previousMillis2 + FlashRate < currentMillis) 
  {        	
    // If the predefined interval has elapsed for the second button press
    // make the LED 'flash' by toggling it
    //===================================================================
    digitalWrite(ledPin1, !digitalRead(ledPin1));
    previousMillis2 = currentMillis;
  }


}





void PrintDateTime(DateTime t)
{
  char datestr[24];
  sprintf(datestr, "%04d-%02d-%02d  %02d:%02d:%02d  ", t.year(), t.month(), t.day(), t.hour(), t.minute(), t.second());
  Serial.print(datestr);
}


// send an NTP request to the time server at the given address unsigned long sendNTPpacket(byte *address) {
  // set all bytes in the buffer to 0
  memset(pb, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  pb[0] = 0b11100011;   // LI, Version, Mode
  pb[1] = 0;     // Stratum, or type of clock
  pb[2] = 6;     // Polling Interval
  pb[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  pb[12]  = 49;
  pb[13]  = 0x4E;
  pb[14]  = 49;
  pb[15]  = 52;

  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp: 		   
#if ARDUINO < 100
  Udp.sendPacket( pb,NTP_PACKET_SIZE,  address, 123); //NTP requests are to port 123 #else
  // IDE 1.0 compatible:
  Udp.beginPacket(address, 123); //NTP requests are to port 123
  Udp.write(pb,NTP_PACKET_SIZE);
  Udp.endPacket(); 
#endif	  
}

Basically, if the Arduino doesn’t have a working internet connection, nothing works. Firstly, I’m kind of surprised that it’s needed, but if it is and it’s not just me being silly, I’d like to add some error checking to find out if the Arduino has an internet connection to avoid the loop hanging. It seems internet code acts like delay() if there’s no internet connection.

Does it display this message in the serial monitor?

Serial.println("Annunciator Panel v0.7");

When you say "no internet connection", do you mean no connection from the shield to the dhcp server also?

You probably should check if the ethernet shield got an ip from the dhcp server. If not, the rest of the ethernet related code probably won't work. I don't use dhcp for any of my projects, so I haven't tried this.

boolean EthernetRunning=true;

// in setup()
if (Ethernet.begin(mac) == 0) {
   Serial.println("No dhcp");
   EthernetRunning = false;
}

if(EthernetRunning) {
   Udp.begin(localPort);
}

This code is in your loop(). What do you expect this to do if the ethernet shield did not get an ip?

    sendNTPpacket(timeServer);

SurferTim: This code is in your loop(). What do you expect this to do if the ethernet shield did not get an ip?

    sendNTPpacket(timeServer);

Please note where the above appears in my sketch

Serial.println("20s have elapsed since power on/reset, so"); Serial.println("time to sync the clock initially.");

(i.e. after the arduino has been told to print the above to the serial port.)

Then try this:

if (Ethernet.begin(mac) == 0) {
   Serial.println("No dhcp");
   EthernetRunning = false;
}
Serial.println("dhcp finished");

Do you ever see "dhcp finished" on the serial monitor?

Bear in mind, the dhcp stuff is new. There will be bugs, and not always yours.

I know that the initial DHCP request can take up to a minute to timeout, so there you are way beyond those initial 20sec wait. EthernetClient.connect takes a bunch of seconds to timeout as well but it should still run.

That said. If you don't get any IP from the DHCP server nothing using the network will work as intended.

Dane:

SurferTim: Does it display this message in the serial monitor?

Serial.println("Annunciator Panel v0.7");

Yes, it does, but it's the last thing it does so to speak. It doesn't display

Serial.println("20s have elapsed since power on/reset, so");
Serial.println("time to sync the clock initially.");

which it ought to do.

SurferTim: When you say "no internet connection", do you mean no connection from the shield to the dhcp server also?

I mean that the ethermega isn't getting an IP from from the DHCP server and/or that there is no connectivity from the router to the wider internet.

SurferTim: You probably should check if the ethernet shield got an ip from the dhcp server. If not, the rest of the ethernet related code probably won't work. I don't use dhcp for any of my projects, so I haven't tried this.

Thanks - I guess I then add an && EthernetRunning == true to my If statements? Say if the internet went down for an hour - I guess it would take a reset of the Arduino before EthernetRunning became true again, right - or wrong? Or can I also check/set this from loop?

What puzzles me is why the lack of internet connectivity should so monstrously interfere with the loop running as normal.

Thanks - I guess I then add an && EthernetRunning == true to my If statements? Say if the internet went down for an hour - I guess it would take a reset of the Arduino before EthernetRunning became true again, right - or wrong? Or can I also check/set this from loop?

You may run any variation of "Ethernet.begin()" in the loop. You can even change the ip if you use a static ip. If EthernetRunning is false, you could try running the begin now and then, depending on how often you can afford to be "down" for a minute.