Ethernet Shield crashes after a relay starts or stops an AC pump

Hi everybody,

I'm currently working on a project where my Arduino is controlling a pump and a lamp with relays and also monitoring temperature and humidity level and sending data to a website with the Ethernet Shield.

The Ethernet Shield is crashing after running for few minutes and after few hours of debugging I discovered that happens only when the relays starts or stops a pump or a fan.

I tested the relays with:

  • a pump (110VAC, 0.06A and has no ground)
  • a pump (110VAC, 0.02A and has no ground)
  • a pump (110VAC, 0.24A and has a ground)
  • a fan (110VAC, 0.4A and has no ground)

and after few minutes (Sometimes an hour) the Ethernet Shield can't connect to the server anymore and sometimes even the terminal stops displaying messages from the Arduino but the Arduino and the relays continue to work fine.

Then, I tried to test with a lamp (150 Watt, 110VAC, 4.5A with a ground) and it seems to work fine for many hours.

So I'm wondering if the pumps or the fan could make noise in the circuit and crash the Ethernet Shield but with the Relay Module I thought the Arduino and Ethernet Shield were protected. Could this help if the Relay Module was powered externally from the Arduino?

Here the principal parts I'm using for my project:

And I will post my code in the next post..

Thanks for your help! :slight_smile:

And here is my code:

#include <Time.h>
#include <TimeAlarms.h>
#include <Wire.h>
#include <DS1307RTC.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <SPI.h>
#include <DHT.h>
#include <OneWire.h>
#include <DallasTemperature.h>

boolean DEBUG = true;

/************ ETHERNET/UDP ************/
EthernetClient client;
byte mac[] = { 0x0, 0x11, 0x95, 0x5A, 0x9E, 0x91 };
IPAddress ip(192, 168, 2, 21);
String pass = "password";
String data;
String host = "website.ca";
EthernetUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets
const char timeServer[] = "pool.ntp.org";  // NTP server

/************ TIME ************/
const int timeZone = 0; // UTC±00:00
tmElements_t tm;

/************ SENSORS ************/
const int ONE_WIRE_BUS_PIN = 7;
OneWire oneWire(ONE_WIRE_BUS_PIN);
DallasTemperature sensors(&oneWire);
DeviceAddress tankTemperatureSensor = { 0x28, 0x23, 0xBA, 0x0A, 0x06, 0x00, 0x00, 0xC9 }; 
#define DHTPIN 2
#define DHTTYPE DHT21
DHT dht(DHTPIN, DHTTYPE);

/************ RELAYS ************/
const int lightRelay = 25;
const int pumpRelay = 24;
const int RELAY_ON = HIGH;
const int RELAY_OFF = LOW;

/************ VARIABLES ************/
boolean lightOn = false;
boolean pumpOn = false;

void setup()
{
  Serial.begin(9600);
  
  pinMode(53, OUTPUT);                       // set the SS pin as an output (necessary!)
  digitalWrite(53, LOW);                    // ? (not sure)
  pinMode(4, OUTPUT);                  // SD select pin
  digitalWrite(4, HIGH);               // Explicitly disable SD
  pinMode(10, OUTPUT);                  // Ethernet select pin
  digitalWrite(10, LOW);               // Explicitly enable Network
  /************ ETHERNET/UDP ************/
  Ethernet.begin(mac, ip);
    
  /************ TIME ************/
  SetRTCTime();
  setSyncProvider(RTC.get);
  Alarm.delay(2000);
  
  // Verify if we have to start or stop the light at this time
  if(hour() >= 10) {
    StartLightRelay();
  } else {
    StopLightRelay();
  }
  TogglePumpRelay();
  PostTemperatureAndHumity();
  
  Alarm.alarmRepeat(8,00,0, SetRTCTime);  // Everyday 4:00am (hour + offset => 4 + 4 = 8)
  Alarm.alarmRepeat(10,00,0, StartLightRelay);  // Everyday 6:00am (hour + offset => 6 + 4 = 10)
  Alarm.alarmRepeat(0,00,0, StopLightRelay);  // Everyday 8:00pm (hour + offset => 20 + 4 = 24)
 
  Alarm.timerRepeat(30, PostStillALive);
  Alarm.timerRepeat(300, TogglePumpRelay); // Every five minutes [300 seconds]
  Alarm.timerRepeat(600, PostTemperatureAndHumity); // Every ten minutes [600 seconds]
  
  /************ SENSORS ************/
  sensors.begin();
  sensors.setResolution(tankTemperatureSensor, 10);
  
  /************ RELAYS ************/
  pinMode(lightRelay, OUTPUT);
  pinMode(pumpRelay, OUTPUT);
}

void loop() {  
  digitalClockDisplay();
  Alarm.delay(1000); // wait one second between clock display
}

/* START - Light*/
void StartLightRelay() {
  lightOn = true;
  UpdateLightRelay();
}

void StopLightRelay() {
  lightOn = false;
  UpdateLightRelay();
}

void UpdateLightRelay() {
  String lightState = lightOn ? "1" : "0";
  postData("lightState=" + lightState, "lightState");
  if( lightOn ) {
    digitalWrite(lightRelay, RELAY_ON);
  } else {
    digitalWrite(lightRelay, RELAY_OFF);
  }
}
/* END - Light*/

void TogglePumpRelay() {
  pumpOn = !pumpOn;
  String pumpState = pumpOn ? "1" : "0";
  postData("pumpState=" + pumpState, "pumpState");
  if( pumpOn ) {
    digitalWrite(pumpRelay, RELAY_ON);
  } else {
    digitalWrite(pumpRelay, RELAY_OFF);
  }
}

void PostStillALive() {
  postData("", "still-alive");
}

void PostTemperatureAndHumity() {
  float humidity = dht.readHumidity();
  float temperature = dht.readTemperature();
  if (isnan( temperature ) || isnan( humidity )) {
    // Log a problem
    // Serial.println("Failed to read from DHT");
  }
  
  char bufferHumidity[10];
  dtostrf(humidity, 3, 1, bufferHumidity);
  
  char bufferTemperature[10];
  dtostrf(temperature, 3, 1, bufferTemperature);
  
  postData("roomTemperature=" + (String)bufferTemperature + "&humidity=" + (String)bufferHumidity + "&tankTemperature=" + strTemperature(tankTemperatureSensor), "data");
}

boolean postData(String data, String action) {
  if(action.length() > 0) {
    if(data.length() > 0) {
      data += "&";
    }
    
    data += "action=" + (action);
    data += "&datetime=" + (String)getDatetime();
    data += "&pass=" + (pass);
    if(DEBUG) {
      data += "&debug=true";
    }
  }

  if( client.connected() ) {
    Serial.println("Connected");
    Alarm.delay(1000);
  }

  if ( client.connect( host.c_str(), 80) ) {
    if( DEBUG ) {
      Serial.println("Connected to " + host + "...");
    }

    client.print("POST /api/instance HTTP/1.1\n");
        
    client.print("Host: "+ host +"\n");                          
    client.print("Connection: close\n");
     
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    
    client.print(data.length());                                            
    client.print("\n\n");
    client.print(data);
    
    if( DEBUG ) {
      Serial.println(data);
    }
    client.stop();
    if( DEBUG ) {
      Serial.println(F("disconnected"));
    }
  } else {
    if( DEBUG ) {
      Serial.println("Problem while connecting to " + host + "...");
      Serial.println("connected : " + (String)(client.connected() ? "true" : "false") + "");
    }
  }
}

float getTemperature(DeviceAddress deviceAddress) {
    sensors.requestTemperatures();
    return sensors.getTempC(deviceAddress);
}

String strTemperature(DeviceAddress deviceAddress) {
    float currentTemp = getTemperature(deviceAddress);
    char buffer[10];
    return dtostrf(currentTemp, 3, 1, buffer);
}

void SetRTCTime() {
  Serial.println("SetRTCTime");
  time_t time = ntpUnixTime(Udp);
  if( time > 0 ) {
    if (RTC.set(time)) {
      Serial.println("Time set");
    } else {
      Serial.println("Error");
    }
  }
}

time_t getDatetime() {
  if (RTC.read(tm)) {
    return makeTime(tm);
  } else {
    if (RTC.chipPresent()) {
      Serial.println("The DS1307 is stopped.  Please run the SetTime");
      Serial.println("example to initialize the time and begin running.");
      Serial.println();
    } else {
      Serial.println("DS1307 read error!  Please check the circuitry.");
      Serial.println();
    }
    delay(9000);
  }
}

void digitalClockDisplay()
{
  if (RTC.read(tm)) {
    //return tm.Hour;
    Serial.print(tm.Hour);
    printDigits(tm.Minute);
    printDigits(tm.Second);
    Serial.println(); 
  }
}

void printDigits(int digits)
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}



/*-------- NTP code ----------*/

/*
 * © Francesco Potortì 2013 - GPLv3 - Revision: 1.13
 *
 * Send an NTP packet and wait for the response, return the Unix time
 *
 * To lower the memory footprint, no buffers are allocated for sending
 * and receiving the NTP packets.  Four bytes of memory are allocated
 * for transmision, the rest is random garbage collected from the data
 * memory segment, and the received packet is read one byte at a time.
 * The Unix time is returned, that is, seconds from 1970-01-01T00:00.
 */
time_t ntpUnixTime (UDP &udp)
{
  static int udpInited = udp.begin(localPort); // open socket on arbitrary port

  //const char timeServer[] = "pool.ntp.org";  // NTP server

  // Only the first four bytes of an outgoing NTP packet need to be set
  // appropriately, the rest can be whatever.
  const long ntpFirstFourBytes = 0xEC0600E3; // NTP request header

  // Fail if WiFiUdp.begin() could not init a socket
  if (! udpInited)
    return 0;

  // Clear received data from possible stray received packets
  udp.flush();

  // Send an NTP request
  if (! (udp.beginPacket(timeServer, localPort)
	 && udp.write((byte *)&ntpFirstFourBytes, 48) == 48
	 && udp.endPacket()))
    return 0;				// sending request failed

  // Wait for response; check every pollIntv ms up to maxPoll times
  const int pollIntv = 150;		// poll every this many ms
  const byte maxPoll = 15;		// poll up to this many times
  int pktLen;
  for (byte i=0; i<maxPoll; i++) {
    if ((pktLen = udp.parsePacket()) == 48)
      break;
    delay(pollIntv);
  }
  if (pktLen != 48)
    return 0;

  const byte useless = 40;
  for (byte i = 0; i < useless; ++i)
    udp.read();

  unsigned long time = udp.read();	// NTP time
  for (byte i = 1; i < 4; i++)
    time = time << 8 | udp.read();

  time += (udp.read() > 115 - pollIntv/8);

  udp.flush();

  return time - 2208988800ul;
}

Finally, after testing with my lamp (150 Watt, 110VAC, 4.5A) the Ethernet Shield crashed after few hours so now I'm testing my project with nothing plugged on the relays and will see if it crashes after few hours of running.

If someone has an idea, I would be really happy to have some help :slight_smile:

Thanks!

How do you power the setup.
An ethernet shield is power-hungry, and so are relays.
The onboard 5volt regulator could overheat and shutdown if you power this setup the wrong way.

The relay module should be powered seperately anyway, so there can be opto isolation.

Remove the JD-VCC jumper.
Connect a 5volt supply (e.g. old cellphone charger) to JD-VCC and ground of the relay module.
Remove the ground wire between the Mega and relay module.
It has no function.
Yes, remove the ground wire between the Mega and relay module.
No opto isolation if you share grounds.

If that doesn't help, then use a snubber network or a MOV across the loads.

To stop relays chattering during bootup, try this.

/************ RELAYS ************/
digitalWrite(lightRelay, HIGH);
digitalWrite(pumpRelay, HIGH);
pinMode(lightRelay, OUTPUT);
pinMode(pumpRelay, OUTPUT);
Leo..