1

I have found several questions about this, but I can't seem to find one that suits my needs.

I'd like my machine (Xubuntu 16.04) to power-off if I'm not using it for 30 minutes. However, I use it to stream videos to my media center (through a SAMBA server), so I don't want it to shut down in that case.

All the answers I've found ignore network activity and only focus on keystrokes and mouse moves.

Jacob Vlijm
  • 83,767

2 Answers2

1

I have set up my own cron job to deal with this.

What I achieved

Suspending/shutting down the machine if it has been idle (no keystrokes or mouse moves) for a certain amount of time, unless there are files being accessed in its SAMBA server.

Requirements

  • root access.
  • xprintidle (install it by executing in a terminal: sudo apt-get install xprintidle)

How to

  1. Save the following script in a location of your choice (in my case, /home/user/.useful-scripts/idle.sh):

    #!/bin/bash
    
    # Checks the time the computer has been idle (no keystrokes or mouse moves)
    # If it's greater than the set limit, it will suspend the machine if no
    # files are being accessed through the SAMBA server.
    
    
    # The maximum number of milliseconds the computer is allowed to be idle before
    # it is suspended (set to 20 minutes)
    IDLE_LIMIT_MS=1200000
    
    # How long the machine has been idle for
    IDLE_TIME_MS=$(/sbin/runuser -l ic -c "DISPLAY=:0.0 /usr/bin/xprintidle")
    
    if [ $IDLE_TIME_MS -gt $IDLE_LIMIT_MS ] ;
    then
        # If there are no files locked by SAMBA, suspend the machine
        FILES_LOCKED=$(/usr/bin/smbstatus | /bin/grep 'Locked files:')
    
        if [[ -z "${FILES_LOCKED}" ]] ;
        then
            /bin/systemctl suspend -i
            # If you prefer to shut down instead of suspend, comment the
            # previous line and uncomment the following one:
            # /sbin/poweroff
        fi
    fi
    

    Be aware that this script will be run by cron. This has certain implications, but mainly that DISPLAY and PATH environment variables are not set. Therefore, we need give the full path when invoking a command. The paths might change in your machine, so make sure they match your configuration (for example, to find the path for xprintidle execute in a terminal which xprintidle).

    We also need to specify the DISPLAY for which we want the xprintidleinformation. It is normally :0.0, but you can be sure of that by running w from a terminal while logged in and checking the FROM column. Read these three links (1, 2 and 3) for more information about PATH and DISPLAY under cron.

  2. Make sure you make it executable:

    chmod +x /home/user/.useful-scripts/idle.sh

  3. Set up the job to run periodically using cron. smbstatus requires to be run as root, so we need to invoke crontab using sudo:

    sudo crontab -e

    Add the following line to run the script periodically:

    * * * * * /home/user/.useful-scripts/idle.sh

    This sets up a cron job to run every minute and execute our script. You can set up the periodicity to a higher value if you don't care about smaller precision (see this link for more information on the necessary syntax).

This is it. cron will check the idle state of the machine every minute, and if it has been idle for more than 20 minutes (can be adjusted with the IDLE_LIMIT_MS variable) it will make sure that no files are being accessed through the SAMBA server; in that case, it will suspend the machine.

1

You can run the (very low on juice) background script, which will suspend the computer, rounded on 10 seconds:

#!/usr/bin/env python3
import time
import subprocess

# --- set idle time below (seconds)
idle_set = 1200
# ---

def get_packets():
    return int([l.strip().split()[1].replace("packets:", "") for l in \
            subprocess.check_output("ifconfig").decode("utf-8").splitlines()\
            if " RX " in l][0])

def get_idle():
    return int(int(subprocess.check_output("xprintidle").decode("utf-8").strip())/1000)

data1 = get_packets()
t = 0

while True:
    time.sleep(10)
    data2 = get_packets()
    if data2 - data1 > 3000:
        t = 0
    else:
        t += 10
    idletime = get_idle()
    if all([idletime > idle_set, t > idle_set]):
        subprocess.Popen(["systemctl", "suspend", "-i"])
    data1 = data2

What it does

  • Once per 10 seconds, it checks the current received amount of data, comparing it with 10 seconds ago (using ifconfig). If it exceeds a certain amount, the "counter" is set to zero, else a0 seconds is added to the "stream" -idle time.
  • Also once per 10 seconds it looks at the "general" idle-time, using xprintidle

If both exceed the set time (in the head of the script), the computer is put to sleep.

How to set up

  1. The script needs xprintidle

    sudo apt-get xprintidle
    
  2. Copy the script into an empty file, save it as set_idle.py

  3. In the head section of the script, set the desired idle time
  4. Test- rfun it by the command:

    python3 /path/to/set_idle.py
    

If all works fine, add it to Startup Applications.

Note

This answer assumes traffic is via Ethernet connection. If not, the function get_packets() possibly needs a small edit.

Jacob Vlijm
  • 83,767
  • Thanks! The script seems to succeed in doing what it wants to do, but I'm not sure it is what I need. When streaming content, it is not the amount of packets received but the amount of packets sent that should be monitored. Also, 3000 is a bit of a magic constant. The idea seems to be good to send the computer to sleep if it is not downloading stuff, though. – user2891462 Sep 08 '16 at 10:57