[mythtv-users] how to make idle frontend exit?
Michael Watson
michael at thewatsonfamily.id.au
Sun Jul 8 23:48:08 UTC 2012
On 8/07/2012 9:39 PM, Petr Stehlik wrote:
> Hi all,
>
> in the new 0.25 mythfrontend there's an idle timer. How can I set it up
> so that the final action is not the current "turn off screen" but "exit
> the frontend" or "run this sleep script"?
>
> Thanks,
>
> Petr
>
>
>
I have written the attached script to do just that, its also designed to
shutdown a slave backend / frontend when idle as well.
For a frontend run via crontab every 10 minutes or so, use command line
options "mysleepcommand -f" or "mysleepcommand -f -j" if you are running
mythjobqueue as well as mythfrontend. On a frontend machine it uses
xscreensaver to determine whether the frontend is idle, so clearly you
need to install/configure xscreensaver.
You need to set the hostname of your MBE in XML_STATS_URL on line 7, and
adjust FRONTEND_IDLE to your liking (Remember this is the No of seconds
xscreensaver is active before shutting down).
For a slave backend, set the script to run via the "Slave Backend ->
Sleep Command", you will need command line options like "mysleepcommand
-b -d -f" for a SBE with FE, or "mysleepcommand -b -d" for just a SBE.
One Ubuntu 10.04 you will need to add "-u1" to the command, otherwise
shutdown will be blocked.
You need to add something like this to "/etc/sudoers" so the script has
access to shutdown and query xscreensaver
%mythtv ALL=(ALL) NOPASSWD: /sbin/shutdown, /usr/bin/xscreensaver-command
Shutdown is blocked if:
uptime is less than ten minutes.
Additional users are logged in
Frontend is in mythbrowser, ripcd, and mythmusic
Transcoding or Commercial flagging
Currently recording (or about to start recording) on local Backend
Regards
Michael Watson
-------------- next part --------------
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
MIN_UPTIME=10
FRONTEND_IDLE=300 # Seconds to Wait to assume Frontend is Idle
FRONTEND_CMD="mythfrontend.real" # MythFrontend Executable
XML_STATS_URL = "http://myth01:6544" # MBE XML Status Hostname:PortNo
SHUTDOWN_CMD = "sudo /sbin/shutdown -P now" # Command to Shutdown System
MYTHJOBS = "mythcommflag mythtranscode" # Executables used by MythTV Jobs
FRONTEND_LOCATIONS = "playlistview playlisteditorview mythbrowser ripcd visualizerview" # Block Frontend Idle if in these locations
logMask = 'general'
logLevel = 'info'
logPath = '/var/log/mythtv'
import socket, urllib, commands, os, time, datetime, sys, string
import xml.etree.ElementTree as xml
from MythTV import MythBE, MythDB, MythError, MythDBError, MythFEError, MythLog
from optparse import OptionParser
# Initial Defaul Settings and Global Variable Declartion
HOSTNAME = "localhost"
LEVEL = None
ISBACKEND = False
ISFRONTEND = False
JOBQUEUE = False
SLEEPTIME = 300
NOUSERS = None
DB = None
LOG = None
BACKEND = None
FRONTEND = None
class VERBOSE_LEVEL:
DEFAULT = 0
VERBOSE = 1
DEBUG = 2
def verbose(level, *messages):
if (LEVEL >= level):
# print ''.join(map(str,messages))
LOG(LOG.GENERAL, LOG.INFO, ''.join(map(str,messages)))
def setuplog():
global DB, LOG, FRONTEND, BACKEND
try:
DB = MythDB()
except MythDBError:
print "Problem Connecting to Database"
sys.exit(1)
try:
BACKEND = MythBE()
except MythBEError:
print "Problem Connecting to Master Backend"
sys.exit(1)
# if ISFRONTEND == True:
# try:
# FRONTEND = DB.getFrontend(HOSTNAME)
# except MythFEError:
# print "Problem Connecting to Frontend"
# sys.exit(1)
LOG = MythLog(module='MythSleep', db=DB)
LOG._setmask(logMask)
LOG._setlevel(logLevel)
LOG._setfileobject(open('/var/tmp/mysleepcommand.log', 'a'))
# LOG._setpath(logPath)
def checktuner():
# Return True if All Tuners are Idle
tuneridle = True
if ISBACKEND is True:
xmldata = xml.parse(urllib.urlopen("%s/Status/xml" % XML_STATS_URL))
rootElement = xmldata.getroot()
now = datetime.datetime.now()
for encoders in rootElement.getiterator('Encoders'):
for encoder in encoders.getiterator('Encoder'):
if encoder.attrib.get('hostname') == HOSTNAME:
if int(encoder.attrib.get('state')) > 0:
for program in encoder.getiterator('Program'):
title = program.attrib.get('title')
break
verbose(VERBOSE_LEVEL.DEBUG, 'Encoder %d is Recording %s' % (int(encoder.attrib.get('id')), title))
tuneridle = False
break
if tuneridle is True:
for schedule in rootElement.getiterator('Scheduled'):
for program in schedule.getiterator('Program'):
title = program.attrib.get('title')
if program.attrib.get('hostname') == HOSTNAME:
for channel in program.getiterator('Channel'):
recorder = int(channel.attrib.get('inputId'))
for recording in program.getiterator('Recording'):
start = recording.attrib.get('recStartTs')
recstart = datetime.datetime.strptime(start, "%Y-%m-%dT%H:%M:%S")
if int(((recstart - now).seconds) / 60) <= 15:
verbose(VERBOSE_LEVEL.DEBUG, 'Next Recording Starts in %d Minutes. Using Tuner ID: %d' % ((((recstart - now).seconds) / 60), recorder))
tuneridle = False
break
if tuneridle is True:
verbose(VERBOSE_LEVEL.DEBUG, 'Tuners Are Idle')
return tuneridle
def checkusers():
# Return True if No additional Users are logged in
idle = True
nousers = int(commands.getstatusoutput("who -q | grep users | awk -F\"=\" '{ print $2 }'")[-1])
if nousers > NOUSERS:
idle = False
verbose(VERBOSE_LEVEL.DEBUG, 'Users: %s No. Users: %d' % (idle, nousers))
return idle
def checkuptime():
# Return True if uptime is > MIN_UPTIME
try:
f = open("/proc/uptime")
contents = f.read().split()
except:
print "Problem Reading UpTime"
sys.exit(1)
total_minutes = float(contents[0])
total_minutes = int(total_minutes / 60)
if total_minutes > MIN_UPTIME:
idle = True
else:
idle = False
verbose(VERBOSE_LEVEL.DEBUG, 'Uptime: %s' % idle)
return idle
def getpid(process):
pid=commands.getoutput("ps -ef | grep %s | grep -v grep" % process)
if pid == "":
return 0
else:
pid=commands.getoutput("ps -ef | grep %s | grep -v grep | awk '{ print $2 }'" % process)
pidlist=pid.splitlines()
return int(pidlist[0])
def checkjobs():
# Return True if No Transcode or Commflag Jobs are Active
idle=True
if JOBQUEUE is True:
for progname in string.split(MYTHJOBS):
job_pid=getpid(progname)
if job_pid > 0:
idle=False
break
verbose(VERBOSE_LEVEL.DEBUG, 'Jobs: %s' % idle)
return idle
def checkscreensaver(mintime):
# Retrun True if Screen Saver Active Time > FRONTEND_IDLE
idle = False
saveruserlist=commands.getoutput("ps -ef | grep xscreensaver | grep -v grep | awk '{ print $1 }'")
saveruser=saveruserlist.splitlines()[0]
status = commands.getoutput("export DISPLAY=:0.0; sudo -u %s xscreensaver-command -time" % saveruser)
verbose(VERBOSE_LEVEL.DEBUG, status)
if status != "no saver status on root window":
savermode = str.split(status)[3]
if savermode == "blanked":
idledate = "%s %s %s %s" % (str.split(status)[7], str.split(status)[6], str.split(status)[9], str.split(status)[8])
idletime = time.strptime(idledate, "%d %b %Y %H:%M:%S")
localtime = time.localtime()
diff=datetime.datetime(*localtime[:6]) - datetime.datetime(*idletime[:6])
verbose(VERBOSE_LEVEL.DEBUG, 'Screensaver Active %d Secs' % diff.seconds)
if diff.seconds > mintime:
idle=True
verbose(VERBOSE_LEVEL.DEBUG, 'ScreenSaver: %s' % idle)
return idle
def checkfrontend():
if getpid("mythfrontend.real") == 0:
# IF Frontend Not Running, Return True
return True
# backend = MythBE()
# db = MythDB()
frontend = DB.getFrontend(HOSTNAME)
location = frontend.sendQuery('Location')
# print "Frontend Location: %s" % location
if location in FRONTEND_LOCATIONS:
# If we are in one of these location, assume Frontend is not idle
return False
if str.split(location)[0] == "Playback":
# If we are in Playback and screen saver is active, playback is paused, triple idle time
idle = checkscreensaver(FRONTEND_IDLE * 3)
return idle
idle = checkscreensaver(FRONTEND_IDLE)
return idle
def shutdown_frontend():
verbose(VERBOSE_LEVEL.VERBOSE, 'Shutting Down Frontend')
# db = MythDB()
frontend = DB.getFrontend(HOSTNAME)
location = frontend.sendQuery('Location')
if str.split(location)[0] == "Playback":
frontend.key['enter']
frontend.jump['mainmenu']
location = frontend.sendQuery('Location')
if location != "mainmenu":
frontend.jump['mainmenu']
# Shutdown Frontend
frontend.key['escape']
frontend.key['down']
frontend.key['enter']
time.sleep(5)
def shutdown_system():
verbose(VERBOSE_LEVEL.VERBOSE, 'Shutting Down System')
result = commands.getstatusoutput(SHUTDOWN_CMD)
def idlechecks():
# print "Uptime : ", checkuptime()
# print "Users : ", checkusers()
# print "Jobs : ", checkjobs()
# print "Tuner : ", checktuner()
# print "FrontEnd: ", checkfrontend()
idle = False
if checkuptime():
if checkusers():
if checkjobs():
if checktuner():
if checkfrontend():
idle = True
pid=getpid(FRONTEND_CMD)
if pid > 0:
shutdown_frontend()
shutdown_system()
if idle == False:
verbose(VERBOSE_LEVEL.DEFAULT, 'System Active. Shutdown Aborted')
def run_daemon():
# fork once
try:
pid = os.fork()
if pid:
# parent, exit
sys.exit(0)
except OSError, e:
verbose(VERBOSE_LEVEL.DEFAULT, "Daemon failed fork to background.")
sys.exit(1)
os.chdir("/")
os.setsid()
os.umask(0)
# fork twice
try:
pid = os.fork()
if pid:
# parent, exit
sys.exit(0)
except OSError, e:
verbose(VERBOSE_LEVEL.DEFAULT, "Daemon failed fork to background.")
sys.exit(1)
setuplog()
# backend = MythBE()
current_uptime = old_uptime = BACKEND.getUptime()
while current_uptime >= old_uptime:
old_uptime = current_uptime
verbose(VERBOSE_LEVEL.DEBUG, 'Backend Uptime: %s' % current_uptime)
# print "Uptime: ", current_uptime
try:
# uptime = MYTH_BE.getUptime()
# print uptime
idlechecks()
except MythError, e:
# MythError
# wait for bindings to automatically reconnect
print "Exception Error"
pass
time.sleep(SLEEPTIME)
current_uptime = BACKEND.getUptime()
verbose(VERBOSE_LEVEL.DEBUG, 'Daemon Exiting')
if __name__ == '__main__':
parser = OptionParser(usage="usage: %prog [options]")
parser.set_defaults(verbose_level=VERBOSE_LEVEL.DEFAULT)
parser.add_option('-v', '--verbose', action='store', type='int', dest='verbose_level', default=VERBOSE_LEVEL.DEFAULT, help='Verbosity level')
parser.add_option('-d', '--daemonize', action='store_true', dest='daemon', default=False, help='Daemonize and manage mythjobqueue')
parser.add_option('-b', '--backend', action='store_true', dest='backend', default=False, help='Host is Backend')
parser.add_option('-f', '--frontend', action='store_true', dest='frontend', default=False, help='Host is Frontned')
parser.add_option('-j', '--jobqueue', action='store_true', dest='jobqueue', default=False, help='Host Runs JobQueue')
parser.add_option('-s', '--sleep', action='store', type='int', dest='sleeptime', default=SLEEPTIME, help='Seconds between Idle Checks')
parser.add_option('-u', '--users', action='store', type='int', dest='nousers', default=0, help='No Users Normally logged in')
opts, args = parser.parse_args()
# If we are a Backend, perform JobQueue checks as well
if opts.backend is True:
JOBQUEUE = True
else:
JOBQUEUE = opts.jobqueue
LEVEL = opts.verbose_level
ISBACKEND = opts.backend
ISFRONTEND = opts.frontend
HOSTNAME = socket.gethostname()
SLEEPTIME = opts.sleeptime
NOUSERS = opts.nousers
if opts.daemon:
run_daemon()
sys.exit(0)
else:
setuplog()
idlechecks()
More information about the mythtv-users
mailing list