web statistic EvilLawnGnome.com » 2007 » June

Using X10 Home Automation and Linux to manage your home internet connection

Blogged by Brian as Main — Brian Wed 20 Jun 2007 11:05 am

I've been using SBC/Yahoo!/AT&T DSL for quite a while now, and i'm more or less satisfied with my service. My one complaint would be that my modem tends to flake out now and again. Who cares, right? Me. I run a linux server behind my DSL. I use it as a jumpbox, a private fileserver, an audio streamer, and i manage my torrents from it. Under most circumstances, i would simply call up AT&T and request that they troubleshoot my modem. However, i know that this is going to be a painful process. They aren't going to like that i use a dedicated Linux PC as my router - they will want me to hook up the modem directly to my PC, or buy an "approved" broadband router. So, you say, "Lie to them! Tell them it's all hooked up like in the manual!" They'll want me to run the "software" that came with the modem - little more than glorified spyware. Not gonna do it. Failing that, theyll want to spend a half hour doing meaningless tests that i've already done. I'll have to listen to them tell me how to ping and run ipconfig. It will be an hour of frustration that i just don't need.

Instead, I've devised my own needlessly complicated solution: Monitor the internet connection via shell script, and power cycle the modem with a couple of X10 home automation modules fit the internet is unreachable.

Summary:

1. Get a couple of x10 modules
2. Hook a lamp module up to the cable modem and the transmitter module up to a linux pc
3. Write a script that checks the connection to the internet and power cycles the modem if necessary
4. Set the script up to run every five minutes via cron

The modules

I did a google search for "linux x10" and found Heyu (http://heyu.tanj.com/), an actively developed set of tools for the X10 protocol in linux. Looking at the supported devices, i popped a couple of those in to amazon, and a few days later, i had myself a CM11A and an LM14A module.

NOTE:
Some people (Eric and Neil) are saying that the LM14A may not be appropriate for this job. Personally, i find that it's working just fine, and i'm not to concerned if it lowers the life of my modem - at that point, i'll replace it. This added functionality is worth it, and the functionality comes with minimal input effort. Read the comments if you are concerned that the LM14A may reduce the life of your modem. Additionally, GrinningArmor advises, "Any X10 module being plugged to the battery-powered output of an UPS is not likely to work, and could be burnt," and i agree with him. Your mileage may vary, but please be aware of these factors when making your decision on implementing this solution, and when choosing a module.
The CM11A plugs in to the computer via serial port, and the LM14A simply plugs in to the wall. The modem is then plugged into the wall module, and we are, for the most part, done. The wall module needs to have an address, and I left this module set to A1 for simplicity. (Further details about the X10 system are out there; they are simply beyond the scope of this document.)

The software

I chose Heyu because it was command line based, and therefore, easy to script. I'm running Ubuntu Feisty on my router, and Heyu wasn't available through apt-get. However, compiling the source required minimal effort. Up until now, this computer had no need to compile source code, so i had to install the toolchain. That's easy enough:

  1. apt-get update
  2. apt-get install build-essential

The next step was to configure / make / make install.

  1. cd /directory/with/source
  2. ./Configure
  3. make
  4. sudo make install

Heyu is now installed and can be accessed like any other command. Heyu is a complete X10 toolset, but there were only two commands i needed:

  1. heyu on A1
  2. heyu off A1

The basic functionality was there - i heard the wall module click on and then back off. Now, all i need to do is script up an internet check script.

The script

I've done a little programming in the past - at least enough to know that this is a ... wordy way to do things. This script could be optimized in a number of ways, but considering the simplicity of function, i'm fairly satisfied with the results. Below is the exact script i use to check for a valid internet connection, and power cycle the modem if necessary:

  1. #!/bin/bash
  2. #logger -t intertest "Beginning outbound connectivity test..."
  3. ERRORS=0
  4. ping -q -c1 -W1 208.67.217.230 &> /dev/null
  5. let "ERRORS = $ERRORS + $?"
  6. ping -q -c1 -W1 216.91.182.78 &> /dev/null
  7. let "ERRORS = $ERRORS + $?"
  8. ping -q -c1 -W1 69.147.114.210 &> /dev/null
  9. let "ERRORS = $ERRORS + $?"
  10. ping -q -c1 -W1 216.74.180.189 &> /dev/null
  11. let "ERRORS = $ERRORS + $?"
  12. ping -q -c1 -W1 69.63.176.13 &> /dev/null
  13. let "ERRORS = $ERRORS + $?"
  14.  
  15. if [ $ERRORS -ge 5 ]; then
  16. logger -t intertest "FAILED OUTBOUND INTERNET PING TEST! THE MODEM WILL NOW POWER CYCLE!"
  17. logger -t intertest "Beginning power cycle..."
  18. heyu off A1
  19. sleep 2
  20. heyu on A1
  21. if [ $? -eq 0 ]; then
  22. logger -t intertest "Done. Modem was power cycled successfully."
  23. else
  24. logger -t intertest "ERROR: Unable to power cycle the modem. We are screwed."
  25. fi
  26. logger -t intertest "Done. Cycling outbound interface [eth3]"
  27. logger -t intertest "Power nap before cycling eth3..."
  28. sleep 8
  29. logger -t intertest "Waking up, cycling eth3..."
  30. ifdown eth3 &> logger
  31. ifup eth3 &> logger
  32. logger -t intertest "MODEM POWER CYCLE COMPLETE! Stirring the pot..."
  33. ping -q -c1 -W1 208.67.217.230 &> /dev/null
  34. ping -q -c1 -W1 216.91.182.78 &> /dev/null
  35. ping -q -c1 -W1 69.147.114.210 &> /dev/null
  36. ping -q -c1 -W1 216.74.180.189 &> /dev/null
  37. ping -q -c1 -W1 69.63.176.13 &> /dev/null
  38. #else
  39. #       logger -t intertest "Connectivity check OK."
  40. fi

Let's take a look at this one section at a time.

Section one: Check for an internet connection:

  1. #!/bin/bash
  2. #logger -t intertest "Beginning outbound connectivity test..."
  3. ERRORS=0
  4. ping -q -c1 -W1 208.67.217.230 &> /dev/null
  5. let "ERRORS = $ERRORS + $?"
  6. ping -q -c1 -W1 216.91.182.78 &> /dev/null
  7. let "ERRORS = $ERRORS + $?"
  8. ping -q -c1 -W1 69.147.114.210 &> /dev/null
  9. let "ERRORS = $ERRORS + $?"
  10. ping -q -c1 -W1 216.74.180.189 &> /dev/null
  11. let "ERRORS = $ERRORS + $?"
  12. ping -q -c1 -W1 69.63.176.13 &> /dev/null
  13. let "ERRORS = $ERRORS + $?"

These IP addresses resolve to google, yahoo, hotmail, savvis communications, and facebook. You can select your IPs differently if you choose, but it wont really matter. The script will only power cycle the modem if all 5 pings fail. Speaking of pings, these aren't your garden variety pings.

-q is quiet
-c1 is to send one packet
-W1 is a one second timeout
&> /dev/null redirects stdout and stderr to the black hole.

We redirect the output to /dev/null because we don't really care about it. What i'm looking for is the exit status of ping - 0 if a reply is sent, 1 if no reply is sent. This section of code tallies up the exit codes using the special variable $? which contains the exit status of the last command.

Section two: Error handling (the meat and potatoes)

  1. if [ $ERRORS -ge 5 ]; then
  2. logger -t intertest "FAILED OUTBOUND INTERNET PING TEST! THE MODEM WILL NOW POWER CYCLE!"
  3. logger -t intertest "Beginning power cycle..."
  4. heyu off A1
  5. sleep 2
  6. heyu on A1
  7. if [ $? -eq 0 ]; then
  8. logger -t intertest "Done. Modem was power cycled successfully."
  9. else
  10. logger -t intertest "ERROR: Unable to power cycle the modem. We are screwed."
  11. fi

The first if begins the test of our error count. If it is greater than 5, it is safe to say that the internet is out. Less than 5, it could be that hotmail was being DOS'ed, or any number of other reasons why a site is unreachable. We only want to cycle the modem if we are SURE that the internet is unreachable.

Logger is a handy command to write an entry to the syslog - this way i can look back and see when or how often the internet failed.

The next command you'll see is the Heyu command. We turn it off, and wait a couple seconds to make sure everything is drained before bringing it back up. I'm sure the manufacturer would like me to wait 5 minutes before turning it back on, but the manufacturer also made a crappy modem, so that shows how much THEY know.

We check the exit status of heyu on the second command to see if the modem was cycled properly. This way i can see in my log if the heyu command failed.

Section three: reset the outbound ethernet connection

  1. logger -t intertest "Done. Cycling outbound interface [eth3]"
  2. logger -t intertest "Power nap before cycling eth3..."
  3. sleep 8
  4. logger -t intertest "Waking up, cycling eth3..."
  5. ifdown eth3 &> logger
  6. ifup eth3 &> logger

I found that sometimes after the modem was up, i was still experiencing connection issues. "Flipping" the interface seemed to resolve the issue. We log that we are about to do it, then wait a few seconds to give the modem a chance to warm up. At that point, we proceed, piping the output to logger.

Section four: Priming the pump

  1. logger -t intertest "MODEM POWER CYCLE COMPLETE! Stirring the pot..."
  2. ping -q -c1 -W1 208.67.217.230 &> /dev/null
  3. ping -q -c1 -W1 216.91.182.78 &> /dev/null
  4. ping -q -c1 -W1 69.147.114.210 &> /dev/null
  5. ping -q -c1 -W1 216.74.180.189 &> /dev/null
  6. ping -q -c1 -W1 69.63.176.13 &> /dev/null

We repeat the ping exercise, except this time, we don't care about the return. All this does is generate some internet traffic to get the modem to establish a connection to the internets.

Section last: Fin

  1. #else
  2. #       logger -t intertest "Connectivity check OK."
  3. fi

This section is mostly commented out. I had it enabled for about ten minutes to make sure that the script was actually running. I commented it out so that if the check is successful, no output is generated. "fi" ends the if statement we began so long ago, and also ends our script.

The cron job

With the script written, the last step is to set it up as a cron job that runs every five minutes. As root,

  1. crontab -e

and insert the following:

  1. # m h  dom mon dow   command
  2. 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /usr/local/bin/intertest

This sets up the intertest command (my script) to run every five minutes, every hour, every day of the month, every month, every day of the week. This concludes the installation.

And this also concludes the how-to. I hope you enjoyed it.

Proudly powered by wordpress - Theme Back in Black 2 by neuro