Arduino as a Network Monitor

I have set up an Arduino as a Network monitor so I can be silently alerted if a WEB server on the LAN/Internet goes down. In a previous post, here, I show the relay circuit I am using in this sketch to flash a CFL lamp. This sketch also uses the same ENC28J60 module to connect to the LAN/Internet.

Arduino Leonardo and SPI Communications using the ENC28J60 ethernet moduleThe uniqueness of this code is that it uses PING against multiple servers. I tried and tried to get this function using the UIPEthernet library working without success. I finally switched to the EtherCard library and found the solution for PINGing multiple servers. The EtherCard library also solves the problem of the CS Pin on the Arduino Leonardo that I document here. (The EtherCard library allows the code to select which pin will be used for the CS pin.)

There are several interesting things to note about this sketch:

  1. It uses PROGMEM so the IP Addresses are preserved thru each PING loop
  2. The IP address for the ENC28J60 module is dynamically set (the comments show how to switch to a static IP)
  3. MAXCYCLES can be set to re-ping and not alert in case your LAN is not perfect (the device you are pinging might miss a few)
  4. Since this is wired as a temporary setup, I blink the light when the sketch first starts to make sure the wiring is correct
  5. An LCD is used to display the IP address and millisecond PING times (this same info is also displayed to the serial port)

Here is the sketch:

// From earl@microcontrollerelectronics.com

#include <avr/pgmspace.h>
#include <EtherCard.h>
#include <LiquidCrystal.h>

#define CS_PIN        10
#define pinToToggle   9

static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };

// myip,gwip,mask,dns Only needed if using a Static IP
static byte myip[]  = { 192,168,2,50 };
static byte gwip[]  = { 192,168,2,1 };
static byte mask[]  = { 255,255,255,0 };
static byte dns[]   = { 8,8,8,8 };

byte Ethernet::buffer[700];
static int32_t timer;
static int polling;

//change these to the IPs that you want to ping
const char srv0[]  PROGMEM = "192.168.2.1";
const char srv1[]  PROGMEM = "192.168.0.105";
const char srv2[]  PROGMEM = "192.168.2.104";
const char srv3[]  PROGMEM = "192.168.0.103";
const char srv4[]  PROGMEM = "192.168.2.101";
const char srv5[]  PROGMEM = "192.168.2.153";
const char srv6[]  PROGMEM = "192.168.0.107";
const char srv7[]  PROGMEM = "192.168.0.104";
const char srv8[]  PROGMEM = "192.168.2.102";
const char srv9[]  PROGMEM = "192.168.0.176";

// Make sure this list matches the above list
const char* const servers[] PROGMEM = {srv0,srv1,srv2,srv3,srv4,srv5,srv6,srv7,srv8,srv9};

#define NUMSRVRS (sizeof(servers) / sizeof(servers[0]))
#define MAXCYCLES 3
#define PING_DELAY 2000000

static int cycles;

char sbuffer[30];

static int i;

float ms;

long interval              = 500;
unsigned long currentTime  = 0;
unsigned long previousTime = 0;

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void blink() {
  currentTime = millis();
  if(currentTime - previousTime > interval) {
    previousTime = currentTime;
    digitalWrite(pinToToggle, !digitalRead(pinToToggle));
  }
}

static void gotPinged (byte* ptr) {
  ether.printIp(">>> ping from: ", ptr);
} 

void setup () {
  
  pinMode(pinToToggle,OUTPUT);
  
  lcd.begin(16, 2);
    
  Serial.begin(57600);

// Uncomment to wait till serial port is ready
//  while (!Serial) { }

  Serial.println(F("Ping Servers\n"));
  
  if (!ether.begin(sizeof Ethernet::buffer, mymac, CS_PIN))
    Serial.println(F("Failed to access Ethernet controller\n"));
  
  strcpy_P(sbuffer, (char*)pgm_read_word(&(servers[0])));
  ether.parseIp(ether.hisip,sbuffer);

// Comment these two lines and uncomment staticSetup
// to use static vs DHCP IP address
  if (!ether.dhcpSetup())
    Serial.println(F("DHCP failed\n"));
    
//  if (!ether.staticSetup(myip, gwip, dns, mask))
//    Serial.println(F("Failed to set Static IP"));

  while (ether.clientWaitingGw())
    ether.packetLoop(ether.packetReceive());
  
  Serial.println("Gateway found");
  
  ether.printIp("IP:  ",     ether.myip);
  ether.printIp("GW:  ",     ether.gwip);
  ether.printIp("Netmask: ", ether.netmask);
  ether.printIp("DNS IP: ",  ether.dnsip);
  Serial.println();
  
  ether.registerPingCallback(gotPinged);
  
  timer   = -9999999;
  polling = 0;
  i       = NUMSRVRS;
  cycles  = 0;
    
  digitalWrite(pinToToggle, !digitalRead(pinToToggle));
  delay(2000);
  digitalWrite(pinToToggle, !digitalRead(pinToToggle));
 
}

void loop () {
  
// Uncomment to change to no delay 
// if ( ( (micros() - timer) >= PING_DELAY) || !polling  ) {

//Comment this next line, if the above line is uncommented
 if ((micros() - timer) >= PING_DELAY) {
   if (polling) {
     ether.printIp("\n",ether.hisip);
     Serial.println(F("Timeout\n"));
     lcd.setCursor(0, 1);
     lcd.print("Timeout");
     if (cycles >= MAXCYCLES) while (1) blink();
   }
   else {
     polling = 1;
     lcd.clear();
     lcd.setCursor(0, 0);
     ++i;
     if (i >= NUMSRVRS) i = 0;
     strcpy_P(sbuffer, (char*)pgm_read_word(&(servers[i])));
     lcd.print(sbuffer);
     ether.parseIp(ether.hisip,sbuffer);
     ether.printIp("Pinging: ", ether.hisip);
   }
    
   cycles += 1;
   ether.clientIcmpRequest(ether.hisip);
   timer = micros();

  }

  word len = ether.packetReceive(); 
  word pos = ether.packetLoop(len); 

  if (len > 0 && ether.packetLoopIcmpCheckReply(ether.hisip)) {
    Serial.print("  ");
    ms = (micros() - timer) * 0.001;
    Serial.print(ms, 3);
    Serial.println(" ms\n");
    lcd.setCursor(0, 1);
    lcd.print(ms);
    lcd.print(" ms");
    polling   = 0;
    cycles    = 0;
  }
   
}

To use it in your environment, change the IP addresses to PING (and number of them) to suit your LAN. Also see the comments to use a static versus dynamic IP address for the monitor itself.

18 comments

Skip to comment form

    • Abu on May 27, 2016 at 10:18 am
    • Reply

    Hi
    I try your code but no any respond in the serial it shows DHCP fails
    But am using the Ethernet shield with mage2560. If I used example file it works and I need to monitor 8 server boxs via SMS text.
    any Help from you thank you very much indeed.

    1. Hi,
      IF you have a DHCP server, check its log to see why the server is not giving it an address. IF you don’t have a DHCP server then take a look at the comments to have the sketch use a static IP address.
      Earl

    • Darko Svilkovic on July 8, 2018 at 4:18 am
    • Reply

    Could you send/upload the complete connecting diagram …

    i’m using an ethernet card,and have no output on LCD display …

    thx

    1. Here is how to connect the LCD (this is an UNO but the pin connections I use on the Leonardo are the same)
      https://microcontrollerelectronics.com/wp-content/uploads/2017/01/LCD.png

      Also, you don’t really need the LCD, look at the serial monitor, you should see the output there too.

    • Shane on December 10, 2018 at 6:24 pm
    • Reply

    Dear Earl,
    I am really new to Arduino but I have some knowledge in basic electronics and pc hardware. I am trying to build a system that displays LAN server status as in if server is up green LED or if not display an LED lit in different color ( preferably red )or maybe if thats too complicated, just a non illuminated LED for a server that is down. This display is for 8 servers on a labelled diagram of a railway track. Thanks in advance.

    Shane.

      • earl on December 11, 2018 at 4:40 am
        Author
      • Reply

      Hi Shane, You should be able to use the code here to start from. Arduino coding is a fun adventure!

      Earl

        • Kanchan on July 27, 2019 at 7:07 am
        • Reply

        HELLO EARL
        Actually also i want little bit same thing but it not happening. I want to ping only one server. If we got positive reply then one pin of arduino will go on HIgh State. But if we dont get reply from that server. The pin will be on low state.
        And after using this code i am unable to get any results of ping in serial window. Please guide me regarding this matter.

        1. Hi!

          Are you sure that your wiring is correct and did you change the IP addresses to match your network?

          Earl

    • Fikri on May 6, 2020 at 4:11 pm
    • Reply

    Hello, can i replace the ip address shown at LCD with the name of my own server ?

    1. Yes. Check the comments in the code. It shows where to change IP addresses.

        • Fikri on May 7, 2020 at 3:25 pm
        • Reply

        Not the ip address, i mean like 192.168.1.1 = NASserver.
        I want LCD shown NASserver not the ip

        1. You could also see if the UIPethernet library does DNS lookup but if your IPs are local you might not have a local DNS server.

          So, probably the easiest way to do what you want is to maintain a table of IP addresses to server names. Check which IP is being pinged and then display its name instead.

    • Paul D. on June 22, 2020 at 6:42 am
    • Reply

    Hi Earl!

    You did great job, thank you!
    But i got a question. Your program stops after one of IPs is not pinging (i guess it’s about while(1) operand). How do i change your code to continue pinging rest of IPs after one is down?
    Thanks in advance!

    1. Hi Paul!

      You can change line 130 from:

      if (cycles >= MAXCYCLES) while (1) blink();

      to this:

      if (cycles >= MAXCYCLES) polling = 0;

      and that should continue to ping the rest.

      Earl

    • Jim Kossow on September 25, 2021 at 8:47 am
    • Reply

    I have tried this sketch. I am having an issue where if the IP address is unavailable or the ping times out the loop stops running. I am using this in a DMVPN application to monitor the spoke routers. The eventual plan is to have this mounted int he rack with the Hub router with an LCD display, it will provide a quick reference is a spoke router is online. Some of the spoke routers are not active yet as soon as the arduino tries to ping an inactive address the loop stops running

    What needs to be changed so that is a ping to a IP address times out it proceeds to the next ip address.

    TNX Jim

      • earl on September 26, 2021 at 6:36 am
        Author
      • Reply

      Hi Jim!

      You can change line 130 from:

      if (cycles >= MAXCYCLES) while (1) blink();

      to this:

      if (cycles >= MAXCYCLES) polling = 0;

      and that should continue to ping the rest.

      Earl

    • Ali Rafie on July 12, 2022 at 10:20 pm
    • Reply

    Hi, I got a question : is there a way to check if a HTTP request is received by one of the IPs on the same network as arduino?
    Please note that I don’t want to decrypt the request or something, I just want to know if it’s received.

    1. Hello Ali,
      I’m sorry to say that my Dad, the creator of this content, passed away last year and I am not able to confirm the answer to this question. I hope you are able to find the answer somewhere.
      Gwen

Leave a Reply

Your email address will not be published.