Not everyone in my house can easily tell if the internet connection is up or down and they are worried about touching the modem and router to restart them. To solve this I thought a little Arduino project would do the job.

I needed the solution to have a simple interface and allow the modem and router to be restarted (turning the power off and on is good enough).

THE SETUP

For an interface I thought 3 LEDs would be simple enough: Blue for everything is fine (as blue LEDs are cooler than green ones); red for something is wrong; and yellow for the modem and router are being restarted. I added a button to do the actual restarting as I wanted it to only be done deliberately.

For the internals I went with:

Arduino mini pro clone 5v

ENC28J60 Ethernet connector (datasheet)

Fotek DC to AC Solid State Relay (SSR) (datasheet)

LM2936 3.3v linear regulator (datasheet)

Funduino level shifter (BSS138 mosfet bidirectional shifter, lots of implementations such as this and this, found mine at my local electronics store)

Resistors, capacitors, etc as per diagram.

For the Ethernet controller, I used the Ethercard library which is on GitHub.

First thing I did was to breadboard the Arduino and the voltage regulator. Reading the data sheet it wanted a capacitor of at least 22uF with a ESR about 0.5 – 5 Ohm (hard to actually tell as the graph is small and has a logarithmic scale). I have a big bag of electrolytic capacitors but could not find a great deal of information on their ESR. There were many tables of typical ESR values (such as http://www.your-book.co.uk/design/esrchart.htm) for electrolytic capacitors but none of them agree and without a datasheet I would have to test it with a specific ESR testing tool. Instead of just hoping that the electrolytic would do I put two in parallel so the resistance would halve and capacitance would double (got the idea from a post in electronic stackexchange). This gave me a nice and stable 3.3v output for the Ethernet controller and level shifter.

Next was getting the Arduino and Ethernet together and check connectivity. I attempted to craft my own level shifter using logic gates but ran into troubles that required more investigation than this little project really called for. So I settled for the level shifter and once connected I progressed to the Ethercard Library. Once it all was connected and the ping example was uploaded the serial connection confirmed that it was working perfectly without any modification.

My next challenge was the Solid State Relay (SSR). When I first added it to the breadboard I had it with a 1k resistor and it wouldn’t work (only 5mA). Reading the datasheet it stated it required 12v at 7.5mA to trigger but at 5v it meant that I needed at least 18mA to trigger (assuming that the trigger is based on power, as if it was resistance the earlier circuit should have worked). Following the datasheet for a normally closed relay I used a 220 Ohm resistor to make sure the SSR has enough current and had the Arduino trigger a transistor to ground the circuit. I then got a standard power board; stripped the middle of the cord to find the active, neutral and ground; cut and stripped the active; attached it to the SSR; and packed it all up in a standard junction box from the electrical section of the local hardware store.

The full circuit diagram is below with Ethernet, level shifter and SSR excluded as they just plug in:

The pins to the Ethernet in the diagram are as follows (the Arduino pins are defined by the Ethercard library):

Ground CS (from Arduino pin 8) SI (from Arduino pin 11) SO (from Arduino pin 12) SCK (from Arduino pin 13) 3.3v (technically 5v to shifter and 3.3v to other side of shifter and to Ethernet)

A picture of it all soldered up

All boxed up and installed on the wall

Just plug the power to Box, plug the power board to the wall, connect the Box to the SSR, plug the Ethernet to the Box and finally plug the modem and router into the SSR controlled power board.

THE CODE

The code is just a copy of the ping example with modifications. There are some holes in the code such as several of the connection checks don’t have proper timeouts if it doesn’t get a response (only if it gets back a error); and I should remove some of the code left over from the example that is not needed; but it is good enough for the solution for now.

#include // ethernet interface mac address, must be unique on the LAN static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; byte Ethernet::buffer[700]; static uint32_t timer; boolean bconnected, pingSent; byte allGoodPin = 7; byte notGoodPin = 6; byte restartLEDPin = 5; byte buttonPin = 4; byte SSRPin = 3; // called when a ping comes in (replies to it are automatic) static void gotPinged (byte* ptr) { ether.printIp(">>> ping from: ", ptr); } void setup () { Serial.begin(57600); Serial.println("

[pings]"); timer = -9999999; // start timing out right away pinMode(allGoodPin,OUTPUT); pinMode(notGoodPin,OUTPUT); pinMode(restartLEDPin,OUTPUT); pinMode(buttonPin,INPUT); pinMode(SSRPin,OUTPUT); digitalWrite(SSRPin,LOW); pingSent = bconnected = false; SetLEDsInitalise(); } void loop () { if (!bconnected) { if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) { Serial.println(F("Failed to access Ethernet controller")); SetLEDsNotConnected(); return; } if (!ether.dhcpSetup()) { Serial.println(F("DHCP failed")); SetLEDsNotConnected(); return; } ether.printIp("IP: ", ether.myip); ether.printIp("GW: ", ether.gwip); #if 1 // use DNS to locate the IP address we want to ping if (!ether.dnsLookup(PSTR("www.google.com"))) { Serial.println("DNS failed"); SetLEDsNotConnected(); return; } #else ether.parseIp(ether.hisip, "74.125.77.99"); #endif ether.printIp("SRV: ", ether.hisip); // call this to report others pinging us ether.registerPingCallback(gotPinged); //all must be good if we got here SetLEDsConnected(); bconnected = true; pingSent = false; Serial.println(); } else { word len = ether.packetReceive(); // go receive new packets word pos = ether.packetLoop(len); // respond to incoming pings // report whenever a reply to our outgoing ping comes back if (len > 0 && ether.packetLoopIcmpCheckReply(ether.hisip)) { Serial.print(" "); Serial.print((micros() - timer) * 0.001, 3); Serial.println(" ms"); pingSent = false; } // ping a remote server once every few seconds if (micros() - timer >= 5000000) { if (!pingSent) { ether.printIp("Pinging: ", ether.hisip); timer = micros(); ether.clientIcmpRequest(ether.hisip); pingSent =true; } else { pingSent = false; SetLEDsNotConnected(); bconnected = false; } } } \\if the button is pressed if (digitalRead(buttonPin) == HIGH) { delay(2000); \\check button is still pressed and restart if (digitalRead(buttonPin) == HIGH) { SetLEDsRestarting(); digitalWrite(SSRPin,HIGH); delay(30000); digitalWrite(SSRPin,LOW); SetLEDsInitalise(); pingSent = bconnected = false; return; } } } void SetLEDsNotConnected() { digitalWrite(allGoodPin,LOW); digitalWrite(notGoodPin,HIGH); digitalWrite(restartLEDPin,LOW); } void SetLEDsConnected() { digitalWrite(allGoodPin,HIGH); digitalWrite(notGoodPin,LOW); digitalWrite(restartLEDPin,LOW); } void SetLEDsInitalise() { digitalWrite(allGoodPin,HIGH); digitalWrite(notGoodPin,HIGH); digitalWrite(restartLEDPin,HIGH); } void SetLEDsRestarting() { digitalWrite(allGoodPin,LOW); digitalWrite(notGoodPin,LOW); digitalWrite(restartLEDPin,HIGH); }