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
coder21
  • 21

1 Answers1

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'])
coder21
  • 21