Ethershield problems

Hello,
I posted here a while ago about apparent random crashes of my arduino. I have partially found the problem - I think the wdt may have been causing a reboot loop - resetting before the bootloader had finished. However, now I have hit a new problem:

I added some serial out lines to debug code progress:
Opening Connection
Connected
Disconnecting
Disconected
Failed to connect

After running fine for 18 hours, I can no longer succesfully get a connection to my server - I get continous “opening connection” followed by “failed to connect”

I know the server is still up and running ok. I wondered if it was a limiy with the number of connections that can be opened at once, so I added the following to the disconnect section of my code:

 client.println();
    client.stop();

    while(client.status() != 0) {
      delay(10);
    }

But this doesn’t seem to have helped. A full code listing is provided below. any ideas?

//Basic energy monitoring sketch - by Trystan Lea
//Licenced under GNU General Public Licence more details here
// openenergymonitor.org

//Sketch measures voltage and current. 
//and then calculates useful values like real power,
//apparent power, powerfactor, Vrms, Irms.

#include <Ethernet.h>

#define SAMPLES 130

//Setup variables
int numberOfSamples = 6000;

byte ip[] = { 192, 168, 1, 44 };
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

//Router IP address
byte gateway[] = { 192, 168, 1, 254 };
byte subnet[] = { 255, 255, 255, 0 };
byte server[] = { 74, 52, 238, 98 }; 

//Set Voltage and current input pins
int inPinV = 1;
int inPinI = 0;

//Calibration coeficients
//These need to be set in order to obtain accurate results
double VCAL = 1.1633;
double ICAL = 0.128;

double PHASECAL = 2.3;

//Sample variables
int lastSampleV,lastSampleI,sampleV,sampleI;

//Filter variables
double lastFilteredV, lastFilteredI, filteredV, filteredI;

//Stores the phase calibrated instantaneous voltage.
double calibratedV,plot_calibratedV;

//Power calculation variables
double sqI,sqV,instP,sumI,sumV,sumP;

//Useful value variables
double realPower,
       apparentPower,
       powerFactor,
       Vrms,
       Irms;

double vPlot[SAMPLES];
double iPlot[SAMPLES];

double startPlot = 0;
double endPlot=0;
double plotTime=0;  

//Used to filter out errounous vPeriod readings.
//Configured for 50Hz
//- If your 60Hz set expPeriod = 16666
unsigned long expPeriod = 20000;
unsigned long filterWidth = 2000;
   
//time in microseconds when the voltage waveform
//last crossed zero.
unsigned long vLastZeroMsec;
//Micro seconds since last zero-crossing
unsigned long vPeriod;
//Sum of vPeriod's to obtain an average.
unsigned long vPeriodSum=0;
//Number of periods summed
unsigned long vPeriodCount=0;

float freq;

Client client(server, 80);

void setup()
{
  Serial.begin(9600);
  Ethernet.begin(mac, ip, gateway, subnet);
}

void loop()
{ 
  vPeriodSum=0;
  vPeriodCount=0;

  startPlot = 0;
  endPlot=0;
  plotTime=0;    
    
  startPlot=millis();
  for (int j=0; j<SAMPLES; j++)
  { 
    //Read in voltage and current samples.   
    vPlot[j] = analogRead(inPinV);
    iPlot[j] = analogRead(inPinI);
  }
  endPlot=millis(); 

  for (int k=0; k<SAMPLES; k++)
  {
    lastSampleV=sampleV;
    lastSampleI=sampleI;
    
    sampleV = vPlot[k];
    sampleI = iPlot[k];
   
    //Used for offset removal
    lastFilteredV = filteredV;
    lastFilteredI = filteredI;
  
    //Digital high pass filters to remove 2.5V DC offset.
    filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV);
    filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);
   
    //Phase calibration goes here.
    calibratedV =  lastFilteredV + PHASECAL * ( filteredV -  lastFilteredV);

    vPlot[k]=VCAL* calibratedV;
    iPlot[k]=  ICAL* filteredI;  
  }

  for (int n=0; n<numberOfSamples; n++)
  {
    //Used for offset removal
    lastSampleV=sampleV;
    lastSampleI=sampleI;
    
    //Read in voltage and current samples.   
    sampleV = analogRead(inPinV);
    sampleI = analogRead(inPinI);
   
    //Used for offset removal
    lastFilteredV = filteredV;
    lastFilteredI = filteredI;
  
    //Digital high pass filters to remove 2.5V DC offset.
    filteredV = 0.996*(lastFilteredV+sampleV-lastSampleV);
    filteredI = 0.996*(lastFilteredI+sampleI-lastSampleI);
   
    if (filteredV < 0 && lastFilteredV >= 0 && n>1)
    {
      //period of voltage waveform
      vPeriod = micros() - vLastZeroMsec;

      //Filteres out any erronous period measurments
      //Increases accuracy considerably
      if (vPeriod > (expPeriod-filterWidth) && vPeriod<(expPeriod+filterWidth)) 
      {
        vPeriodSum += vPeriod;
        vPeriodCount++;
      }
      vLastZeroMsec = micros();
    }
    //Phase calibration goes here.
    calibratedV = lastFilteredV + PHASECAL * (filteredV - lastFilteredV);
  
    //Root-mean-square method voltage
    //1) square voltage values
    sqV= calibratedV * calibratedV;
    //2) sum
    sumV += sqV;
   
    //Root-mean-square method current
    //1) square current values
    sqI = filteredI * filteredI;
    //2) sum 
    sumI += sqI;

    //Instantaneous Power
    instP = calibratedV * filteredI;
    //Sum
    sumP +=instP;
    
  }

  plotTime=endPlot-startPlot;
  freq = (1000000.0 * vPeriodCount) / vPeriodSum;

  //Calculation of the root of the mean of the voltage and current squared (rms)
  //Calibration coeficients applied. 
  Vrms = VCAL*sqrt(sumV / numberOfSamples); 
  Irms = ICAL*sqrt(sumI / numberOfSamples); 

  //Calculation power values
  realPower = VCAL*ICAL*sumP / numberOfSamples;
  apparentPower = Vrms * Irms;

  realPower=realPower;
  apparentPower=apparentPower;
  powerFactor=powerFactor;

  //Reset accumulators
  sumV = 0;
  sumI = 0;
  sumP = 0;
  Serial.println("Opening Connection");
  if (client.connect()) {   
  Serial.println("Connected");
  //Accessing a shared server requires the server domain name in here as there is no fixed ip address.
  //This is because a shared server shares one fixed IP between many users, its the url that points to your website on the shared hosting.
    client.print("GET http://bbarker.co.uk/energy/log.php?volts=");
    client.print(Vrms);
    client.print("&amps=");
    client.print(Irms);
    client.print("&va=");
    client.print(apparentPower);
    client.print("&pow=");
    client.print(realPower);
    client.print("&freq=");
    client.print(freq);
    client.print("&plotperiod=");
    client.print(plotTime);
    client.print("&vplot=");

    for(int i=1;i<SAMPLES;i++)
    {
      client.print(vPlot[i]);
      client.print(",");
    }
    client.print("&iplot=");

    for(int i=1;i<SAMPLES;i++)
    {
      client.print(iPlot[i]);
      client.print(",");
    }
    Serial.println("Closing Connection");
    client.println();
    client.stop();

    while(client.status() != 0) {
      delay(10);
    } 
    Serial.println("Connection Closed");
  }
  else{
    Serial.println("Failed to connect to client"); 
  }
  
  delay(7000);
  
}

I have some comments, I don’t know if they will fix the problem, but may lead to a fix…

  1. I would put a delay between the sending of the data and the client.stop() of at least 5 ms. You don’t want the request data to be in limbo when the TCP connection is destroyed.

  2. In your code, you start to create a HTTP request, but don’t finish. Your webserver is probably returning an invalid request, because you are missing the protocol HTTP/1.0 after your request string. (ie GET HTTP/1.0\r\n ) You may want to check the samples and the HTTP protocol specs for more information.

  3. In your code, you don’t ever send the HTTP body. After the request line GET HTTP/1.0\r\n you have to send a \r\n again.

I don’t ever check client.status in my code, so I can’t comment about how that effects/works with the other stuff. I have a home alarm that sends status data in the same manner that you do. Mine performes the same GET request (sometimes POST) at least every 10 seconds, and it has run for more than 5 months without a problem(other than when my home ISP goes down).

I would perhaps start with #1 and try it. If it fixes the problem, there may be a state machine problem in the chip that would sometimes mark the TCP connection as closing, but never use that socket again. You only get 4 simultaneous connections as far as I can see in the library source, and eventually they would all get used up.

Hello,

I have tried all above suggestions - this time it hung after 11 hours. Perhaps I should put something in such that if a connection fails, there is a delay of a few second such that the wdt triggers...

Well, a messy solution, but it seems to have worked...

It appears what may have been happening is that the ethernet library can only have 4 concurrent connections. However, failed connection attempts weren't being dealt with properly - they were neither able to be stopped with client.stop, but after 4 cfailed connection attempts I could never connect at all.

Now, if I get a failed connection attempt, I wait for 10 seconds with the wdt set to 8s - so the arduino rests. I only loose about 15sec of readings. As I say, a but messy, but it works :-)