Uno R3 and EthernetShield stops sending data for 24 hours

Hello all! I’ve been building a current monitor for home power usage monitoring. It currently uses 2 SCT013 100a sensors for the two main power lines in my breaker box, takes readings every 5 seconds, averages them and after 5 minutes, sends the average to a mySQL server (via a php script).

What I’ve been seeing is that after about a day or two, the readings stop coming for almost exactly 24 hours. After 24 hours passes, the readings resume.

At first I thought it was maybe the ethernet was dropping out or it was losing DHCP, so I changed it to a completely static IP address. That didn’t help either. The only guess is that somewhere in the code, it’s causing it to crash or some variable is getting too full or something beyond me. Please any suggestions would help!

Here’s my code:

/*
  Current Monitor
 */

#include <SPI.h>
#include <Ethernet.h>
#include "EmonLib.h"    // Include Emon Library
#include <elapsedMillis.h>
EnergyMonitor pmEMON1;
EnergyMonitor pmEMON2;
elapsedMillis timeElapsed; //declare global if you don't want it reset every time loop runs
// Intervals
int sendMySqQLData = 150;  // Number of readings before sending data to SQL
unsigned int getSensorData = 2000;  // Miliseconds between readings

// Name to use for SQL reporting
const char* pmSensorName = "SCT013000";


// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = {  
  0x90, 0xA2, 0xDA, 0x0F, 0x7F, 0xF9 };
// the dns server ip
IPAddress dnServer(10, 2, 2, 2);
// the router's gateway address:
IPAddress gateway(10, 2, 2, 1);
// the subnet:
IPAddress subnet(255, 255, 255, 0);

//the IP address is dependent on your network
IPAddress ip(10, 2, 2, 120);
  
  
// mySQL Server IP address
byte server[] = { 10, 2, 2, 100 }; 
// Setup a client
EthernetClient client;

// Global Variables
int i;
char pmEMONReading1;
char pmEMONReading2;
float pmAverage;
float pmTotal;
String dataString;
String pmAvgSendString = "";
double Irms1;
double Irms2;
float pmAmps1;
float pmAmps2;
int pmReadings = 0;


void setup()
{  
  Serial.begin(9600);
  // start the Ethernet connection:
  Serial.println("Starting Ethernet Interface...");
  Ethernet.begin(mac, ip, dnServer, gateway, subnet);
  // if (Ethernet.begin(mac) == 0) {
    // Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    // for(;;)
    //   ;
  // }
  // else {
    Serial.print("CurrentMonitor is running at: ");
    Serial.println(Ethernet.localIP());
  // }
    pmEMON1.current(0, 123);             // Current: input pin, calibration.
    pmEMON2.current(1, 123);  
}

// Function to extract decimal part of float
long getDecimal(float val) {
   int intPart = int(val);
   long decPart = 100*(val-intPart); //I am multiplying by 1000 assuming that the foat values will have a maximum of 3 decimal places
                                     //Change to match the number of decimal places you need
   if(decPart>0)return(decPart);           //return the decimal part of float number if it is available 
   else if(decPart<0)return((-1)*decPart); //if negative, multiply by -1
   else if(decPart=0)return(00);           //return 0 if decimal part of float number is not available
}

void getSensorDataFunc() {
  // Take readings and create an average
    pmReadings++;
//    Serial.print("Taking Reading #");
//    Serial.print(pmReadings);
//    Serial.println("...");
    Irms1 = pmEMON1.calcIrms(1480);
    Irms2 = pmEMON2.calcIrms(1480);
    // Skip any readings higher than 100, because they are false
    if (pmReadings > 1) {
      pmAmps1 = (Irms1 - 0.165) / 1.75;
      pmAmps2 = (Irms2 - 0.165) / 1.75;
      pmTotal = pmTotal + pmAmps1 + pmAmps2;
      pmAverage = pmTotal / i;
      Serial.print("Sensor 1");
      Serial.print(" Irms: ");
      Serial.print(Irms1);
      Serial.print(" Amps: ");
      Serial.println(pmAmps1);
      
      Serial.print("Sensor 2");
      Serial.print(" Irms: ");
      Serial.print(Irms2);
      Serial.print(" Amps: ");
      Serial.println(pmAmps2);
      
      Serial.print("Total Avg: ");
      Serial.print(pmAverage);
      Serial.print(" Total: ");
      Serial.print(pmTotal);
      Serial.print(" Count: ");
      Serial.println(i);
      
    } else {
      if (i > 0) { i = i - 1; }
      Serial.print("Reading skipped - pmReadings <= 1: ");
      Serial.print(pmReadings);
      Serial.print(" Count: ");
      Serial.println(i);
    } 
      
  if (i == sendMySqQLData) {
    Serial.println("Sending Data to SQL...");
    pmAvgSendString = String(int(pmAverage))+ "."+String(getDecimal(pmAverage)); 
    if (client.connect(server, 80)) {   
      String(dataString = "GET /cgi-bin/ardsql.pl?Table=MainPowerData&Sensor=");
      String(dataString = dataString + pmSensorName + "&Value=" + pmAvgSendString);
      Serial.println("dataString: ");
      Serial.println(dataString);
      client.print(dataString);
      client.println();
      client.stop();
    } else {
      Serial.println("Failed to connect to client!");
    }
  
    // Reset Readings
    pmTotal = 0;
    // Reset Counter;
    i = 0;
  }
}

void loop() {
    if (timeElapsed > getSensorData) {
      i++;
      getSensorDataFunc();
      timeElapsed = 0;
    }
}

Maybe if you read the server response it would give you a hint.

    if (client.connect(server, 80)) {   
      String(dataString = "GET /cgi-bin/ardsql.pl?Table=MainPowerData&Sensor=");
      String(dataString = dataString + pmSensorName + "&Value=" + pmAvgSendString);
      Serial.println("dataString: ");
      Serial.println(dataString);
      client.print(dataString);
      client.println();

// add this
      // connectLoop controls the hardware fail timeout
      int connectLoop = 0;

      while(client.connected())
      {
          while(client.available())
          {
             char inChar = client.read();
             Serial.write(inChar);
             // set connectLoop to zero if a packet arrives
             connectLoop = 0;
          }

          connectLoop++;

          // if more than 10000 milliseconds since the last packet
          if(connectLoop > 10000)
          {
             // then close the connection from this end.
            Serial.println();
            Serial.println(F("Timeout"));
            client.stop();
          }
          // this is a delay for the connectLoop timing
          delay(1);
      }
      Serial.println();

      Serial.println(F("disconnecting."));
      // close client end
// to here

      client.stop();

This has a timeout feature that prevents most lockups. If you see "Timeout" on the serial monitor, normally your script would have locked up there.

      String(dataString = "GET /cgi-bin/ardsql.pl?Table=MainPowerData&Sensor=");
      String(dataString = dataString + pmSensorName + "&Value=" + pmAvgSendString);

You've got some parentheses in the wrong places there.

PaulS:       String(dataString = "GET /cgi-bin/ardsql.pl?Table=MainPowerData&Sensor=");       String(dataString = dataString + pmSensorName + "&Value=" + pmAvgSendString);

You've got some parentheses in the wrong places there.

Can you provide an example of the correct way?