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.
The 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:
- It uses PROGMEM so the IP Addresses are preserved thru each PING loop
- The IP address for the ENC28J60 module is dynamically set (the comments show how to switch to a static IP)
- 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)
- Since this is wired as a temporary setup, I blink the light when the sketch first starts to make sure the wiring is correct
- 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
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.
Author
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
Could you send/upload the complete connecting diagram …
i’m using an ethernet card,and have no output on LCD display …
thx
Author
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.
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.
Author
Hi Shane, You should be able to use the code here to start from. Arduino coding is a fun adventure!
Earl
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.
Author
Hi!
Are you sure that your wiring is correct and did you change the IP addresses to match your network?
Earl
Hello, can i replace the ip address shown at LCD with the name of my own server ?
Author
Yes. Check the comments in the code. It shows where to change IP addresses.
Not the ip address, i mean like 192.168.1.1 = NASserver.
I want LCD shown NASserver not the ip
Author
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.
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!
Author
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
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
Author
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
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.
Author
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