2

I am running a HTPC on Intel Nuc running Xenial. When I press the power button, it runs powerbtn.sh which initiates shutdown but my raspberry is able to wake it up, as I want it to.

The question is how do I get ubuntu to run this when on idle for 5 minutes. The two factors I am concerned about is that MythTV and ssh shouldnot be serving in that 10 minute period.

I think I could block SSH using the solution here Prevent machine from sleeping when SSH connections are on

I believe MythTV should automatically be factored in by the OS.

But how do I put all of this together and get it to work?

Thank you for your time!

EDIT: After much pondering I have come up with this script that I plan to run on cron every 15 minutes. Any suggestions will be greatly appreciated

#!/bin/bash

#check for SSH sessions, and prevent suspending:
if [ "$(who | grep -cv "(:")" -gt 1 ]; then
    echo "SSH session(s) are on. Not suspending."
    exit 1
fi

#check for MythTV sessions, and preventing suspending:
if [ "$(netstat -tun | grep :6543 | grep -i established | wc -l)" -gt 0 ]; then
    echo "MythTV  is still streaming. Not suspending."
    exit 1
fi

sleep 5m

#check for SSH sessions, and prevent suspending:
if [ "$(who | grep -cv "(:")" -gt 1 ]; then
    echo "SSH session(s) are on. Not suspending."
    exit 1
fi

#check for MythTV sessions, and preventing suspending:
if [ "$(netstat -tun | grep :6543 | grep -i established | wc -l)" -gt 0 ]; then
    echo "MythTV  is still streaming. Not suspending."
    exit 1
fi

echo "Safe to shutdown from MythTV and SSH"
/etc/acpi/powerbtn.sh
0

I couldnt get MythTV system events to work. Tried my best playing with permissions all in vain. Here is a my current working code. Replace the database variables with your settings. Save it as say /etc/cron.daily/idle_htpc.py If any of the step fails program will quit. Just sudo crontab -e this for every 5-59/15 * * * * /etc/cron.daily/idle_htpc.py /var/log/htpc_out 2> /var/log/htpc_err 15 minutes

Step 1: Look if there are any SSH connections

Step 2: Check if live or recorded video being played at the moment. If not sleep for 5 minutes

Step 3: Check once again if live or recorded video being played at the moment

Step 4: Check if there was a live stream within the last 5minutes just in case there was a sub-5 minute stream while the script was sleeping in Step 2. However if there was a recorded playback there is no means to detect here.

Step 5: Check the next upcoming recording and if there is one and it is >5minutes from now set ACPI wakeup 3 minutes before start time and shutdown or else clear ACPI wakeup and shutdown.

Hope this helps someone.

#!/usr/bin/python3

import pymysql
import pymysql.cursors
from datetime import timedelta,datetime
import subprocess
import time
import sys

print ( datetime.now().strftime("%Y-%m-%d %H:%M:%S"), file=sys.stdout)

def check_Logins():
    #Returns the number of SSH connections
    #result= subprocess.run('who | grep -cv "(:"', stdout=subprocess.PIPE, shell=True)
    result= subprocess.run("netstat -n |grep tcp |grep ':22' |wc -l", stdout=subprocess.PIPE, shell=True)
    print ('Logins:'+result.stdout.decode('UTF-8'), file=sys.stdout)
    return (int(result.stdout.decode('UTF-8')))

def check_if_InUse():
    #Checks if a live stream or a previosuly recorded program is being served at this moment. If yes, non zero value is returned
    InUse=1
    connection = pymysql.connect(host=$host,
                             user=$username,
                             password=$password,
                             db=$db,
                             charset='utf8mb4',
                             cursorclass=pymysql.cursors.DictCursor)

    try:
        with connection.cursor() as cursor:
            # Read a single record
            sql = "select count(*) from inuseprograms where recusage !='jobqueue' and recusage !='flagger'"
            cursor.execute(sql)
            result = cursor.fetchone()
            InUse = result["count(*)"]
    finally:
        connection.close()
    print ("Count: "+str(InUse), file=sys.stdout)
    return InUse

def check_live_5min():
    #Checks if there were any live streams served in last 5 minutes
    RecInUse_5min=1
    connection = pymysql.connect(host=$host,
                             user=$username,
                             password=$password,
                             db=$db,
                             charset='utf8mb4',
                             cursorclass=pymysql.cursors.DictCursor)

    try:
        with connection.cursor() as cursor:
            # Read a single record
            sql = "select max(starttime) from recordedseek"
            cursor.execute(sql)
            result = cursor.fetchone()
            print ('Recent: ', result['max(starttime)'], file=sys.stdout)
            print ('Current: ',datetime.utcnow(), file=sys.stdout)
            if datetime.utcnow()-result['max(starttime)']>=timedelta(minutes=5):
                RecInUse_5min =0
    finally:
        connection.close()
    return RecInUse_5min

def get_next_rec():
    #Returns a tuple indicating if there is any scheduled recording if yes, how far into the future
    retdata = (True, timedelta(minutes=1))
    connection = pymysql.connect(host=$host,
                             user=$username,
                             password=$password,
                             db=$db,
                             charset='utf8mb4',
                             cursorclass=pymysql.cursors.DictCursor)

    try:
        with connection.cursor() as cursor:
            # Read a single record
            sql = "select MIN(next_record) from record where recordid!=1 and next_record IS NOT NULL;"
            cursor.execute(sql)
            result = cursor.fetchone()
            if result['MIN(next_record)'] is None: #no scheduled recordings
                retdata= (False,timedelta(minutes=1))
            else:
                retdata= (True,result['MIN(next_record)']-datetime.utcnow())
    finally:
       connection.close()
    return retdata

if check_Logins()==0:
    print ('First check passed', file=sys.stdout)

    if check_if_InUse() == 0:
        print ('Second check passed', file=sys.stdout)
        time.sleep(5*60)

        if check_if_InUse() == 0:
            print ('Third check passed', file=sys.stdout)
            if check_live_5min()==0:
                print ('Fourth check passed', file=sys.stdout)
                (valid,upcoming) = get_next_rec()

                # Clear any previously set wakeup time 
                result = subprocess.run('echo 0 > /sys/class/rtc/rtc0/wakealarm',stdout=subprocess.PIPE,shell=True)
                print ('Clear:'+result.stdout.decode('UTF-8'), file=sys.stdout)

                if valid is True:
                    # Generate wakeup time string
                    upcoming = upcoming - timedelta(minutes=3)
                    wakeup_string="'+"+str(upcoming.days)+" days + "+str(max([int(upcoming.seconds/60)-3,0]))+" minutes'"
                    print ('Setting for '+wakeup_string, file=sys.stdout)
                    wakeup_command="echo `date '+%s' -d " +wakeup_string+ "` > /sys/class/rtc/rtc0/wakealarm"
                    #Setup wakeup time
                    result = subprocess.run(wakeup_command,stderr=subprocess.PIPE, shell=True)
                    print ('Set:'+result.stderr.decode('UTF-8'), file=sys.stdout)
                    #Check if alarm is set. It should show the unix time stamp
                    result= subprocess.run('cat /sys/class/rtc/rtc0/wakealarm', stdout=subprocess.PIPE, shell=True)
                    print ('Check:'+result.stdout.decode('UTF-8'), file=sys.stdout)

                print ('Shutting down', file=sys.stdout)
                subprocess.Popen(['/sbin/shutdown', '-h', 'now'])

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.