Arduino Ethernet relay

By | November 3, 2012

This is just a quick adaptation of the Arduino Ethernet example to control a couple of relays for an automated test setup. I hope the source code is self-explanatory. Beware that Arduino IDE 1.0.1 or later should be used – DHCP in the Ethernet library is buggy in version 1.0.

I am using Arduino ADK, Ethernet shield and a double relay board.


/*
Control 2 relays over Ethernet (Ethernet shield)
Supports DHCP
Relays are connected to pins 6 (relay 1) and 7 (relay 2). More relays can be added by putting their pin numbers to the relayPins array
Listening on TCP/IP port 22000
Control command syntax: R([aa],[bb])<CR><LF> where [aa]= relay number 00 for both, 01 or 02. [bb] is 00 (off) or 01 (on)
Response: OK<CR><LF> or ERROR<CR><LF> if a bad relay number or command is given
Multiple commands may be given. The server closes the client socket after 30s inactivity timeout
*/

#include <Ethernet.h>
#include <SPI.h>

////////////////////////////////////////////////////////////////////////
//CONFIGURE
////////////////////////////////////////////////////////////////////////
byte ip[] = { 192, 168, 0, 199 };   //Manual setup only
byte gateway[] = { 192, 168, 0, 1 }; //Manual setup only
byte subnet[] = { 255, 255, 255, 0 }; //Manual setup only

// if need to change the MAC address (Very Rare)
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

EthernetServer server = EthernetServer(22000); //port
////////////////////////////////////////////////////////////////////////

int relayPins[] = {6, 7};
int numRelays = sizeof(relayPins) / sizeof(int);
const bool useDhcp = true;

void setup()
{
// configure relay pins to output, OFF
for (int i = 0; i < numRelays; i++){
pinMode(relayPins[i], OUTPUT);
digitalWrite(relayPins[i], HIGH);
}

Serial.begin(9600);

//Pins 10,11,12 & 13 are used by the ethernet shield
Serial.println("Start");
Serial.print("Number of relays: " );
Serial.println(numRelays);

if (useDhcp) {
Ethernet.begin(mac); // DHCP
} else {
Ethernet.begin(mac, ip, gateway, subnet); //for manual setup
}

server.begin();
Serial.println(Ethernet.localIP());
}

void loop()
{
if (useDhcp) {
Ethernet.maintain();
}

// listen for incoming clients, and process request.
checkForClient();
}

int state = 0;
int relayNumber = 0;
int action = 0;

// reset command state machine
void Reset()
{
state = 0;
relayNumber = 0;
action = 0;
}

void checkForClient()
{
EthernetClient client = server.available();

if (client) {
int timeout = 1000;

Serial.println("Connected");

while (client.connected()) {
if (client.available()) {
char c = client.read();

// command parser is implemented as a simple state machine
switch (state){
case 0:
if (c == 'R') state++; break;
case 1:
if (c == '(') state++; else Reset(); break;
case 2:
case 3:
state++;
if ((c <= '9') && (c >= '0')){
relayNumber = relayNumber * 10 + (c - '0');
} else {
Reset();
}
break;
case 4:
if ((c == ':') || (c == ',') || (c == '.') || (c == ';')) state++; else Reset(); break;
case 5:
case 6:
state++;
if ((c <= '9') && (c >= '0')){
action = action * 10 + (c - '0');
} else {
Reset();
}
break;
case 7:
if (c == ')') state++; else Reset(); break;
case 8:
if (c == '\r') state++; else Reset(); break;
case 9:
if (c == '\n') {
if ((relayNumber > numRelays) || (action > 1)){
client.print("ERROR\r\n");
} else {
setRelay(relayNumber, action);
client.print("OK\r\n");
}
client.flush();
delay(100);
}
Reset();
break;
}
if (state > 0){
timeout = 1000;
}
} else {
timeout--;
if (timeout == 0){
Serial.println("Disconnecting - timeout");
client.stop(); // close the connection:
return;
} else {
delay(30); // 30ms * 1000 = 30s disconnect on idle timeout
}
}
}
Serial.println("Client disconnect");
}
}

void setRelay(int relayNumber, int action)
{
if (relayNumber == 0) { // 0 - all relays
for (int i = 0; i < numRelays; i++){
digitalWrite(relayPins[i], (action)?LOW:HIGH);
}
return;
}

digitalWrite(relayPins[relayNumber-1], (action)?LOW:HIGH);
}

5 thoughts on “Arduino Ethernet relay

  1. Max Nikolaus

    Hi. I made a similar system with Arduino + Ethernet + Relays but slightly different. I used a ENC28J60 board instead of a shield (doesn’t couple directly with Arduino. You have to use cables) and used a 4 relay controller instead of a 2 relay one.

    I used an EtherShield.h library instead of the Ethernet.h and had to do most of the tcp handling manually. I do that because I need to check whether the packet comes from a specific IP address and through a specific port to prevent unknown agents to command my Arduino.

    I also have a different format for the command. I use xxyy where xx may be from 00 to 15, symbolizing all relays turned off to all turned on* and yy may be from 00 to 09 symbolizing the time in seconds to keep that configuration of relays on/off. 00 would mean a permanent change.

    * for example, the command 0503 would turn on relays 1 and 3 for 3 seconds and then go back to previous state.

    All well and good, except that if I command the Arduino to change the state of the relays WITH THE TIMER (yy>00) MORE THAN 5 MINUTES AFTER LAST COMMAND EXECUTION, my Arduino executes the command twice in a row.

    I posted the complete code and problem in http://stackoverflow.com/questions/15621246/arduino-client-php-curl-server-executing-command-twice

    I’d very much appreciate your help solving this bug.

    Yours, Max.

    Reply
    1. Antanas Post author

      Hi Max,

      your project is quite different from mine, therefore it’s hard to spot the problem. I would suggest recording a serial port log to see where the second command comes from. Sniffing the network traffic via e.g. Wireshark could also be helpful. If it does not help, you could completely replace the Ethernet connection with serial port and see if the program behaves the same way. Try to narrow it down to the communication, web client, timer etc subsystems and debug that

      cheers
      Antanas

      Reply
  2. Rob

    Thanks a lot for the code. Finally I found what i was looking for!
    Now I’ve downloaded the sketch but it seems Ethernet shield doesn’t respond when i go to the ip address i’ve assigned for it. The browser hangs after a while saying “Oops! Google Chrome could not connect to 192.168.137.2”.
    Serial monitor seems to respond well:
    “Start
    Number of relays: 8
    192.168.137.22”
    BTW the ip adress assigned is 192.168.137.2 and I don’t know why it shows different ip.
    Will be very grateful if you can help me to solve this problem!

    Reply
    1. Antanas Post author

      Hi Rob,
      this code is not supposed to be accessed with a browser – there is no HTTP server in it. I had no need for web access yet – a listening socket responding to simple commands is sufficient and a lot easier to integrate with my automatic tests. You could first try connecting to the device with some terminal application (e.g. Hercules) and sending a command R(01,01). Use the port number set in the code (22000 is used in the example)

      How do you see that 192.168.137.2 is assigned? Is it in the code? If you want to hard-code an IP address, you should disable DHCP – otherwise your DHCP server (internet router) will handle the network configuration

      Reply

Leave a Reply

Your email address will not be published.