Ethernet sheild stops connecting after an extended period

I have read many accounts of the same thing happening.

My Arduino Ethernet shield (attached to an uno) retrieves XML data from twitter for about an hour and then stops connecting to the server... I think.
Serial monitor looks like this. It's all good up until the continuous "connecting to server..." At this point it has stopped functioning properly.

connecting to server...
making HTTP request...
no new tweets
connecting to server...
making HTTP request...
no new tweets
connecting to server...
making HTTP request...
no new tweets
connecting to server...
making HTTP request...
connecting to server...
connecting to server...
connecting to server...
connecting to server...
connecting to server...

I understand there may be a way of resetting the Ethernet shield without a reset of the Uno if I insert some kind of 'watchdog' function into this section of code...

void connectToServer() {
  // attempt to connect, and wait a millisecond:
  Serial.println("connecting to server...");
  if (client.connect(serverName, 80)) {
    Serial.println("making HTTP request...");
    // make HTTP GET request to twitter:
    client.println("GET /1/statuses/user_timeline.xml?screen_name=accountnamehere&count=1 HTTP/1.1");
    client.println("HOST: api.twitter.com");
    client.println();
  }
  else 
  // note the time of this connect attempt:
  lastAttemptTime = millis();
}

Is this correct?

I think it's funny how I heard no mention of this problem until I experienced it. Then when searching I find a constant stream of similar troubles dating back four years, with no clear antidote.

If you know how to fix this I will be very grateful.

Best Regards

Stuart

If I was to use this function

void software_Reset() // Restarts program from beginning but does not reset the peripherals and registers
{
Serial.println ("Cannot connect, resetting");
asm volatile ("  jmp 0");

}

where in here should I place the software_Reset(); ?

void connectToServer() {
  // attempt to connect, and wait a millisecond:
  Serial.println("connecting to server...");
  if (client.connect(serverName, 80)) {
    Serial.println("making HTTP request...");
    // make HTTP GET request to twitter:
    client.println("GET /1/statuses/user_timeline.xml?screen_name=accountnamehere&count=1 HTTP/1.1");
    client.println("HOST: api.twitter.com");
    client.println();
  }
  else 
  // note the time of this connect attempt:
  lastAttemptTime = millis();
}

Well that didn't work at all. Even having the void in the sketch without telling it to run reset it before it had a chance to do anything. I didn't know that was possible.

Maybe if you posted all the code? I don't see where you read the response and close the connection.

I don't know whether String is the culprit here, but that'd be my prime suspect.

Are there alternatives?

Do you have a memory card in the micro SD slot?

No, I don't think I need one for this project.

Then the code may be leaving connections open and running out of sockets.

Here is my client code. It downloads Google home every 10 seconds.

Note how it makes the request to the server, and then reads the response and closes the connection. You should be able to use that with your code. Extend the time to 10 minutes, and change the server and request to your twitter settings.

stuarthooper:
Are there alternatives?

Just use plain old char arrays with a null terminator - classic 'C strings. The String class is an attempt to make these easier to use but in its current implementation introduces a memory leak (has this been fixed yet?) and also tends to lead to heap fragmentation. For an application where stability was important, I'd suggest you stay away from anything using dynamic heap memory allocation and that includes the String class.

You should be able to use that with your code.

SurferTim,
Call me stupid, I don't know how to do that. I've been at it all day.

Just use plain old char arrays with a null terminator - classic 'C strings. The String class is an attempt to make these easier to use but in its current implementation introduces a memory leak (has this been fixed yet?) and also tends to lead to heap fragmentation. For an application where stability was important, I'd suggest you stay away from anything using dynamic heap memory allocation and that includes the String class.

PeterH,
I've also tried to turn the Strings into Chars but I keep getting problems with the comparison operators between things like tweet and inChar.

Here is the original code, tidied up a bit. I feel like I'm watching paint dry in the rain today.
lil help?

//setup for all libs
#include <SPI.h> // needed in Arduino 0019 or later
#include <Ethernet.h>
#include <Twitter.h>
#include <EthernetUdp.h>
#include <PString.h>
#include <TextFinder.h>

int ledPin = 3;
byte mac[] = { $$$$$$$$ };
byte ip[] = {$$$$$$$4};
Twitter twitter("$$$$$$$$$$$$$");



//Ethernet Client

EthernetClient client;
const unsigned long requestInterval = 15000;  // delay between requests
char serverName[] = "api.twitter.com";  // twitter URL
boolean requested;                   // whether you've made a request since connecting
unsigned long lastAttemptTime = 0;            // last time you connected to the server, in milliseconds
String currentLine = "";            // string to hold the text from server
String previousLine = "";           //String to hold the previous text from server for comparison
String tweet = "";                  // string to hold the tweet
String makeCoffee = ">make me coffee";
boolean readingTweet = false;       // if you're currently reading the tweet
TextFinder finder( client );

//TweetString
char buffer[140] = {0};
PString tweetString(buffer, sizeof(buffer));
long randNumber;
boolean firstTweetRead = false;



void setup(){
 
  pinMode (ledPin, OUTPUT);
  randomSeed(analogRead(5));
  
  //Serial Reader
  Serial.begin(9600); // Initialize serial port
  
  //Ethernet Client
  currentLine.reserve(256);
  tweet.reserve(150);
  
  //General
  delay(1000);
  Ethernet.begin(mac);
  Serial.begin(9600);
    
 //Ethernet Client
   // attempt a DHCP connection:
  Serial.println("setup");
  if (!Ethernet.begin(mac)) {
    // if DHCP fails, start with a hard-coded address:
    Serial.println("failed, trying manually");
    Ethernet.begin(mac, ip);
  }

// connect to Twitter:
  connectToServer();
}




void loop(){
  
  Ethercheck();
}


void Ethercheck(){
 //Ethernet Client
   if (client.connected()) {
    if (client.available()) {
      // read incoming bytes:
      char inChar = client.read();

      // add incoming byte to end of line:
      currentLine += inChar; 

      // if you get a newline, clear the line:
      if (inChar == '\n') {
        previousLine = "";
        previousLine = tweet;
        currentLine = "";
      } 
      // if the current line ends with <text>, it will
      // be followed by the tweet:
      if ( currentLine.endsWith("<text>")) {
        // tweet is beginning. Clear the tweet string:
        readingTweet = true; 
        tweet = "";
      }
      // if you're currently reading the bytes of a tweet,
      // add them to the tweet String:
      if (readingTweet) {
        if (inChar != '<') {
          tweet += inChar;
        } 
        else {
          // if you got a "<" character,
          // you've reached the end of the tweet:
          readingTweet = false;
           if (tweet != previousLine){
          Serial.println(tweet);   
          // close the connection to the server:
          client.stop(); 
                
                if (firstTweetRead != false){
                if (tweet.startsWith (makeCoffee)){
                  
                  //if( waterLevel is higher than said amount){
                  Serial.println ("Making coffee");
                  tweetString.begin();
                  tweetString = " Making coffee now, random number: ";
                  randNumber = random(1000);
                  tweetString.print (randNumber);
                  
                  make();
                }

                }
                else{
                 firstTweetRead = true;
                }
                }
         else {
           Serial.println("no new tweets");
           client.stop(); 
          
         }
        }
      }
    }
  }
  else if (millis() - lastAttemptTime > requestInterval) {
    // if you're not connected, and fifteen seconds have passed since
    // your last connection, then attempt to connect again:
    connectToServer();
    
  }
  
}
  
  



void connectToServer() {
  // attempt to connect, and wait a millisecond:
  Serial.println("connecting to server...");
  if (client.connect(serverName, 80)) {
    Serial.println(serverName);
    Serial.println("making HTTP request...");
    // make HTTP GET request to twitter:
    client.println("GET /1/statuses/user_timeline.xml?screen_name=$$$$$$$&count=1 HTTP/1.1");
    client.println("HOST: api.twitter.com");
    client.println();
  }
  // note the time of this connect attempt:
  lastAttemptTime = millis();
}   







void make(){
  Serial.println("Tweeting ...");
  if (twitter.post(tweetString)) {
    // Specify &Serial to output received response to Serial.
    // If no output is required, you can just omit the argument, e.g.
    // int status = twitter.wait();
    int status = twitter.wait(&Serial);
    if (status == 200) {
      digitalWrite(ledPin, HIGH); //turn coffee maker on
      Serial.println(", Reply was tweeted. Making coffee now.");
      //Start the coffee making
        //when water level is low
          //Stop the coffee making and run the finished function
        
        
    } 
    else {
      Serial.print("failed : code ");
      Serial.println(status);
      Serial.println(tweetString);
      Serial.print("new Tweet is this: ");
              tweetString.begin();
              tweetString = " Making coffee now, random number: ";
               randNumber = random(1000);
              tweetString.print ( randNumber);
              Serial.println(tweetString);
              delay(10000);
              return make();
    }
  } 
  else {
    Serial.println("connection failed. Cannot Tweet");
  }
}

I'm with the guy who said thought it's due to open sockets as the wiznet chip supports only 4 open sockets.. i can't view all the code because i'm on my phone atm

Not only are you still using the String class, you are using two different String classes. That really has to stop.

  currentLine.reserve(256);
  tweet.reserve(150);

Are these really reasonable values?

void loop(){
  
  Ethercheck();
}

Calling just one function from loop() is a waste of time and resources.

Your constant strings in Serial.print() functions are taking up SRAM, too. Stop that by wrapping them in the F() macro.
Serial.println(F("Tweeting ..."));

When I strip the Ethercheck void back to just printing the client without the strings it works until my computer sleeps (at five hours). I think this means it is the strings causing the problem.

I currently use the .startsWith to find out if the tweet starts with the same words as makeCoffee in order to recognise a tweeted command. I am told by the console that I cannot use .startsWith with Char. I have researched a function called memcmp(); Is this what I have to use to create a comparison between two chars?

Also if I cannot say

   currentLine += inChar;

When currentLine is a char, not a string.. how do I complete the function with currentLine as a char?

I currently use the .startsWith to find out if the tweet starts with the same words as makeCoffee in order to recognise a tweeted command.

Use the strncmp() function, instead.

how do I complete the function with currentLine as a char?

You can't. currentLine needs to be a char array. And, you need an index into the array, to keep track of where to write.

char currentLine[80]; // Reserve space for some characters
byte index = 0;
currentLine[index++] = inChar; // Append the character
currentLine[index] = '\0'; // NULL terminate the array

Loe and behold, I've fucked up again.

void Ethercheck(){
 //Ethernet Client
   if (client.connected()) {
    if (client.available()) {
      // read incoming bytes:
      char inChar = client.read();
     // Serial.print (inChar);

     // add incoming byte to end of line:
      currentLine[index++] = inChar;
      currentLine[index] = '\0';

      // if you get a newline, clear the line:
      if (inChar == '\n') {
        previousTweet == tweet;
      } 
      // if the current line ends with <text>, it will
      // be followed by the tweet:
      if (strncmp(currentLine,"<text>")==0) {
        // tweet is beginning. Clear the tweet string:
        readingTweet = true; 
      }
      // if you're currently reading the bytes of a tweet,
      // add them to the tweet String:
      if (readingTweet) {
        if (inChar != '<') {
          tweet[index++] = inChar;
        //  currentLine[index] = '\0';
          
        } 
        else {
          // if you got a "<" character,
          // you've reached the end of the tweet:
          readingTweet = false;
           if (tweet != previousTweet){
          Serial.println(tweet);   
          // close the connection to the server:
          Serial.println(F("disconnecting"));
          client.stop(); 
                
                if (firstTweetRead != false){
                if (strncmp(tweet,"<text>")==0) {
                  
                  //if( waterLevel is higher than said amount){
                  Serial.println (F("Making coffee"));
                  tweetString.begin();
                  tweetString = " Making coffee now, random number: ";
                  randNumber = random(1000);
                  tweetString.print (randNumber);
                  
                  make();
                }

                }
                else{
                 firstTweetRead = true;
                }
                }
         else {
           Serial.println(F("no new tweets"));
           Serial.println(F("disconnecting"));
           client.stop(); 
          
         }
        }
      }
    }
  }
  else if (millis() - lastAttemptTime > requestInterval) {
    // if you're not connected, and fifteen seconds have passed since
    // your last connection, then attempt to connect again:
    client.flush();
    totalCount++;
    Serial.print (F("Total count:"));
    Serial.println(totalCount);
    connectToServer();
    
  }
  
}

setup
connecting to server...connected
making HTTP request...
Total count:1
connecting to server...

I'm not sure how to use the strncmp(). I thought this would be correct.
PaulS, Thanks for helping me with every stage of this project. I'd say I was teaching myself but that would be a lie.

      if (strncmp(currentLine,"<text>")==0) {

It's hard to believe that that even compiles, since strncmp() takes three arguments. The third is the number of characters to compare.

      if (readingTweet) {
        if (inChar != '<') {
          tweet[index++] = inChar;
        //  currentLine[index] = '\0';
          
        }

You need a separate index for each array, or, at a minimum you need to reset index to 0 before you use it to index another array.

Uncomment the print that shows what was read. You can't debug serial/client reading code without seeing what you read.

I'm lost, This is printing jibberish.

void Ethercheck(){
 //Ethernet Client
   if (client.connected()) {
    if (client.available()) {
      // read incoming bytes:
      char inChar = client.read();
      //Serial.print (inChar);

     // add incoming byte to end of line:
      currentLine[currentIndex++] = inChar;
      currentLine[currentIndex] = '\0';
      Serial.print (currentLine);
       
      // if you get a newline, clear the line:
      if (inChar == '\n') {
        previousTweet == tweet;

      } 
      // if the current line contains <text>, it will
      // be followed by the tweet:
      if (strncmp(currentLine,"<text>",6)==0) {
        // tweet is beginning. Clear the tweet string:
        readingTweet = true; 
      }
      // if you're currently reading the bytes of a tweet,
      // add them to the tweet String:
      if (readingTweet) {
        if (inChar != '<') {
          tweet[tweetIndex++] = inChar;
          tweet[tweetIndex] = '\0';
          
        } 
        else {
          // if you got a "<" character,
          // you've reached the end of the tweet:
          readingTweet = false;
          
           if (tweet != previousTweet){
            Serial.println(F("TWEET"));
            Serial.println(tweet);   
            // close the connection to the server:
            Serial.println(F("disconnecting"));
            client.stop(); 
                
                if (firstTweetRead != false){
                if (strncmp(tweet,makeCoffee, 16)==0) {
                  
                  //if( waterLevel is higher than said amount){
                  Serial.println (F("Making coffee"));
                  tweetString.begin();
                  tweetString = " Making coffee now, random number: ";
                  randNumber = random(1000);
                  tweetString.print (randNumber);
                  
                  make();
                }

                }
                else{
                 firstTweetRead = true;
                }
                }
         else {
           Serial.println(F("no new tweets"));
           Serial.println(F("disconnecting"));
           client.stop(); 
          
         }
        }
      }
    }
  }
  else if (millis() - lastAttemptTime > requestInterval) {
    // if you're not connected, and fifteen seconds have passed since
    // your last connection, then attempt to connect again:
    client.flush();
    totalCount++;
    Serial.print (F("Total count:"));
    Serial.println(totalCount);
    connectToServer();
    
  }
  
}

i have same problem,
if you connectinc using DHCP , connection drops after 60 minuts
its easily fix problem
You need to use Ethernet.maintain() every 15-30 minuts

unsigned long previousMillis = 0;
int interval = 900000;

void loop()
{
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval)
  {
    previousMillis = currentMillis;
    Ethernet.maintain();
    delay(100);
  }
}
      if (inChar == '\n') {
        previousTweet == tweet;

No. An equality operator is NOT what you want to use. You can't assign (=) a char array this way, either. You need strcpy().

At some point, you need to set index and tweetIndex back to 0, and put the NULL in position 0 in each array.

You also need to stop posting snippets. How are we supposed to know how previousTweet, tweet, currentLine, currentIndex, and tweetIndex are defined?