Categories
Linux Raspberry Pi

Raspberry Pi automates cable modem power cycling task

2021 update

The problem with my cable modem is back. So I’ve revisited my own project and just slightly tweaked things. I am also using an RPi model 4 now. Works great…

Original Intro

I lose my Internet far too often – sometimes once a day. Of course I have lots of network gear in a rat’s nest of cables. I narrowed the problem down to the cable modem, which simply needs to be power cycled and all is good. Most people would call their cable company at this point. I decided to make a little project of it to see if I could get my Raspberry Pi to

– monitor the Internet connection and
– automatically power-cycle the cable modem

Cool, right?

Needless to say, if I can power cycle a modem, I can control power to all kinds of devices with the RPi.

Is there a product already on the market?
Why yes, there is. Normally that would shut me down in my tracks because what’s the point? But the product is relatively expensive – $100, so my DIY solution is considerably less since I already own the RPi. See references for a link to the commercial solution to this problem.


Getting a control cable

This is pathetic, but, in 2017 I originally cut out a cable from an old computer that no longer works. The jumper has more pins than I need, but I could make it work. In 2021 I used proper jumper cables. It’s neater. Thing is, I’ve had them for awhile and I forget where I got them from. perhaps a friend.

Setting up my GPIO, just for testing

The following is only there to show you how easy it is to send signals out the GPIO pin. The script I wrote below, connTest.sh, does all this setup for you if you just want to quickly get down to business.

I am plugged into the end so I need to manipulate GPIO pin 21.
Become root
$ sudo su –
Get to the right directory
$ cd /sys/class/gpio
Create the pin for user manipulation
$ echo 21 > export
Move to that pin’s directory
$ cd gpio21
Set up pin for sending signal OUT
$ echo out > direction
Test what we have so far
$ cat direction

out

$ cat value
0

connTest.sh script
I put this in /usr/local/etc and called it connTest.sh. I’m still tinkering with it a bit. But it shows what we’re basically trying to do.

#!/usr/bin/bash
# DrJ 8/2021
# Test if Internet connection is still good and send signal to relay if it is not
# see https://drjohnstechtalk.com/blog/2017/10/raspberry-pi-automates-cable-modem-power-cycling-task/?preview_id=3121&preview_nonce=9b896f248d&post_format=standard&_thumbnail_id=-1&preview=true
Break=300
Sleep=11
pingpadding=30 # if no response ping takes longer to run
log=/var/log/connTest
pinglog=/tmp/ping.log
#
# one-time setup of our GPIO pin so we can control it
# if the power is on the right, GPIO pin 21 is the lower right pin
pin=21
cd /sys/class/gpio
echo $pin > export
cd gpio$pin
echo out > direction

# divert STDOUT and STDERR to log file
exec 1>$log
exec 2>&1
echo "$0 starting monitoring at "$(date)
# report our external IP
curl -s ipinfo.io|head -2|tail -1
while /bin/true; do
try1=$(curl -is --connect-timeout 6 www.google.com|wc -c)
[[ $try1 -lt 300 ]] && {
  echo google came up short. Trying amazon next. characters: $try1
  sleep 60
  try2=$(curl -is --connect-timeout 6 https://www.amazon.com|wc -c)
  [[ $try2 -lt 300 ]] && {
    echo "#################"
    echo "We have a connection problem at "$(date)
    echo character counts. google: $try1, amazon, $try2
    echo "Power cycling router and waiting for $Break seconds"
# start a ping job
    ping -c $Break 1.1.1.1 > $pinglog 2>&1 &

# this will shut power off
    echo 1 > value
    sleep 4
# and this will turn it back on
    echo 0 > value
# this prevents us from too aggressively power-cycling
    sleep $(($Break+$pingpadding))
# report on ping results
#22 packets transmitted, 22 received, 0% packet loss, time 53ms
#rtt min/avg/max/mdev = 6.536/15.533/24.705/4.510 ms
    echo printing last three lines from ping results log:
    tail -3 $pinglog
    line=`tail -2 $pinglog|head -1`
    t1=`echo -n $line|awk '{print $1}'`
    t2=`echo -n $line|awk '{print $4}'`
#  downtime=$(($t1-$t2))
# test for integer inputs
    [[ "$t1" =~ ^[0-9]+$ ]] && [[ "$t2" =~ ^[0-9]+$ ]] && downtime=$(($t1-$t2))
    echo  DOWNTIME: $downtime seconds
# report our external IP
    curl -s ipinfo.io|head -2|tail -1
    echo "#################"
  }
}
sleep $Sleep
done

Starting on boot

These days I just use my crontab trick – much easier. You edit your crontab by saying sudo crontab -e. Then put in these lines at the bottom:

# DrJ 7/13/21
@reboot sleep 45; /usr/local/etc/connTest.sh > /tmp/connTestRun.log 2>&1
# bring down wireless after awhile – assume we have a wired connection
@reboot sleep 120; /usr/sbin/ifconfig wlan0 down

Only include that last line if you have an ethernet cable connection, which, for monitoring purposes, you should. WiFi is just not as reliable.

In all this I had the most trouble getting the startup script to bend to my will! But I think it’s functioning now. It may not be the most efficient, but it’s workable, meaning, it starts up connTest.sh after a reboot, and sends the log to /var/log/connTest.

My conntest file looks like this after I rebooted a few days ago:

/usr/local/etc/connTest.sh starting monitoring at Sat 18 Sep 08:11:47 EDT 2021
“ip”: “67.83.122.167”,
#################
We have a connection problem at Mon 20 Sep 14:13:03 EDT 2021
Power cycling router and waiting for 300 seconds
printing last three lines from ping results log:
— 1.1.1.1 ping statistics —
300 packets transmitted, 202 received, +9 errors, 32.6667% packet loss, time 563ms
rtt min/avg/max/mdev = 7.581/13.387/35.981/3.622 ms
DOWNTIME: 98 seconds
“ip”: “67.83.122.167”,

So it needs to restart my cable modem about every other day and often during those critical daytime hours when I am working from home.


Substitute below for one thousand words

Raspberry Pi GPIO pins 21 plus ground connected to the power relay

So you can almost make out the different outlets from the power relay: always on; normally on; normally off. Makes perfect sense, right?
See that green plug on the side of the relay? I was such a newbie I was shoving the wires into it, unsure how to make a good connection. Well, with a little effort it simply pulls out, revealing a screws that can be used to secure the wires in the holes.

Some conclusions about my cable modem problems

The problems always occur during the day, i.e., when it is being used more heavily (the monitoring is 24×7 so it doesn’t distinguish). So somehow it’s actual usage which triggers failure. I  wonder if it outputs more heat and overheats when the Internet is used more heavily? Just a hypothesis.

Outage can be reduced to about 90 seconds with this script based on the ping drop testing. Your mileage may vary, as they say.

My ISP does not give me a new IP after I reboot.

A strange error pops up

After running for awhile I noticed this error in the log:

604 Segmentation fault curl -s –connect-timeout 3 www.google.com > /dev/null

I ran curl by hand and confirmed the error. meanwhile, my bandwidth constraints were also lifted, so my librespeed testing was using up all my bandwidth due to that.

I’ve still got to look into that root cause of that issue. A reboot cleared it up however.

Conclusion

It’s fun to actually turn off and on 110V AC power using your Raspberry Pi! Especially when there is a useful purpose behind it such as a cable modem which starts to perform better after being power cycled. At only $30 this is a pretty affordable DIY project. I provide some scripts which shows how to work with GPIO pins using the command line. That turns out to be not so mysterious after all…
If the switching can work fast enough, I’m thinking of a next project with lights set to musical beats…!

References and related
Raspberry Pi models 2 – 4 GPIO pins are documented here: GPIO – Raspberry Pi Documentation

Generic GPIO documentation – how to use it from the operating system – is here: https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
A PERL example of controlling GPIO I personally find too difficult to follow is here: https://raspberrypi.stackexchange.com/questions/41014/gpio-callbacks-in-any-language

This really nice 110 volt AC relay device, controlled by DC signal of anywhere from 3.3 to 48 volt DC, is on Amazon: https://smile.amazon.com/gp/product/B00WV7GMA2/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1. This is a really sweet device. Perfect for hobbyists with either Raspberry Pi or Arduino. And only $29!

Product which does all this monitoring/power cycling for you automatically: https://smile.amazon.com/dp/B015NM0LKI/ref=dp_sp_detail?psc=1. But it’s $100.

Another alternative which would also work is switching over ethernet. This device does that: https://smile.amazon.com/dp/B00KQ4R1RK/ref=dp_sp_detail?psc=1&pd_rd_i=B00KQ4R1RK&pd_rd_wg=dxYdP&pd_rd_r=8TBE6X2F39S2XWX9CGKK&pd_rd_w=bmvYC. There is a simple CGI URL you can use to turn power off/on. But, again, it’s more costly: $75.

Need gpio cables? If you don’t happen to have a desktop computer you can cannibalize, then for only $10 this Rpi expansion kit seems like a good way to go. https://smile.amazon.com/Kuman-Expansion-Raspberry-Solderless-Breadboard/dp/B074DSMPYD/ref=sr_1_1_sspa?ie=UTF8&qid=1509737721&sr=8-1-spons&keywords=GPIO+CABLES&psc=1