Tool to shutdown system when there is no network traffic

There are a few ways to go about this, I have written a very simple bash script that you can use to monitor the speed in KB p/s for a desired interface, when the download speed drops below the minimum (which you can set), then your computer will be shutdown.

Some things to keep in mind here are:

  • This is a bash script that I put together quickly, there are many different techniques to achieve the same result, however this is an easy one to understand and implement.

  • You will need to execute the bash script from cron as root, that means you need to open cron as the root user and add a cronjob as desired. The reason it needs to be in root's cron is that you will not be able to shutdown your computer from the command line without being root, and you cannot use sudo while you are away from keyboard. There are ways to get around it but I am trying to keep it as simple as possible.

  • I use a linux tool called ifstat, so you will need to install this otherwise the script will not work:

    sudo apt-get install ifstat
    
  • There are 2 options that you can modify in the script below, the INTERFACE and MIN_SPEED. The INTERFACE needs to be set to the interface you are using to download, either eth0 for your wired device or wlan0 for you wireless device, you can use the command ifconfig from the command line to see what interfaces you have available. The MIN_SPEED is set as desired, in my example I set it to the number 5, which means that if my download speed is less than 5 KB per second then my computer will shutdown.

  • Lastly, to improve on the script we could use a while loop and check the download speed over a specified period of time and if the average is less than the minimum we would shutdown, as well as run the script as a service, this is a more accurate way of approaching the problem and I will be happy to help you with that if this is the route you would like to follow.

Copy and paste the below code into a file in a directory of your choice on your computer, example i_speed.sh, then, very important, make the file executable, to do this from the command line, if your file was called i_speed.sh as follows:

    chmod +x i_speed.sh 

Now you can sudo -i to root and setup your cronjob to call the script at time intervals that you desire.

Code to copy and paste into a file called i_speed.sh:

#!/bin/bash

# Bash script to determine a network interfaces current transfer speed and 
  shutdown the computer if the current transfer speed is less than MIN_SPEED

# Set INTERFACE to the network interface you would like to monitor
INTERFACE='wlan0'

# Set MIN_SPEED in KB per second that network interface (INTERFACE) speed 
  must be larger than, if speed falls below this number then computer will shutdown.
MIN_SPEED=5


# This is where the work get's done:
CURRENT_SPEED=`ifstat -i $INTERFACE 1 1 | awk '{print $1}' | sed -n '3p'`
INT=${CURRENT_SPEED/\.*}

if [ $INT -lt $MIN_SPEED ]; then
    shutdown -h now
else
    exit
fi

UPDATE

I wrote a small python program as an update to the bash script above which allows you to set additional variables such as retries and interval to get an average min speed over a specified period of time. Further updates will include a GUI for this program. Just copy and paste the code below into a file, example download_monitor.py then run it as follows sudo python download_monitor.py

## Download Monitor v0.1 - March 2012

# Set the interface you wish to monitor, eg: eth0, wlan0, usb0
INTERFACE = "eth0"

# Set the minimum download speed in KB/s that must be achieved.
MINIMUM_SPEED = 15

# Set the number of retries to test for the average minimum speed. If the average speed is less
# than the minimum speed for x number of retries, then shutdown.
RETRIES = 5

# Set the interval (in seconds), between retries to test for the minimum speed.
INTERVAL = 10


import os, time
from commands import getoutput

def worker ():
    RETRIES_COUNT = RETRIES
    while True:
        SPEED = int(float(getoutput("ifstat -i %s 1 1 | awk '{print $1}' | sed -n '3p'" % INTERFACE)))
        if (SPEED < MINIMUM_SPEED and RETRIES_COUNT <= 0):
            os.system("shutdown -h now")
        elif SPEED < MINIMUM_SPEED:
            RETRIES_COUNT -= 1
            time.sleep(INTERVAL)
        else:
            RETRIES_COUNT = RETRIES
            time.sleep(INTERVAL)

worker()

I found this topic very helpful. With no Python knowledge I've updated the above script to get average network speed and go into long sleep if average speed is more than minimum speed. After long sleep calculations are reset and average speed is calculated again.

## Download Monitor v0.2 - June 2017

# Set the interface you wish to monitor, eg: eth0, wlan0, usb0
INTERFACE = "enp4s0"

# Set the minimum download speed in KB/s that must be achieved.
MINIMUM_SPEED = 10

# Set the number of retries to test for the average minimum speed.
RETRIES = 5

# Set the interval (in seconds), between retries to calculate average speed.
INTERVAL = 5

# Set the interval (in seconds), between recalculating average speed
LONG_INTERVAL = 600

import os, time
from commands import getoutput

def worker ():
    RETRIES_COUNT = 1
    SPEED = 0
    while True:
        # Sum downstream and upstream and add with previous speed value
        # {print $1} use just downstream
        # {print $2} use just upstream
        # {print $1+$2} use sum of downstream and upstream
        SPEED += int(float(getoutput("ifstat -i %s 1 1 | awk '{print $1+$2}' | sed -n '3p'" % INTERFACE)))

        if RETRIES_COUNT > RETRIES:
            # Calculate average speed from all retries
            AVG_SPEED = int(float(SPEED) / float(RETRIES_COUNT))

            # If average speed is below minimum speed - suspend
            if AVG_SPEED < MINIMUM_SPEED:
                os.system("shutdown -h now")
            # Else reset calculations and wait for longer to retry calculation
            else:
                RETRIES_COUNT = 1
                SPEED = 0
                time.sleep(LONG_INTERVAL)
        else:
            RETRIES_COUNT += 1
            time.sleep(INTERVAL)

worker()