From dcaa0d05f36fb2f67fe245804ca7a6c3c7e12a5c Mon Sep 17 00:00:00 2001
From: Britney Fransen <brfransen@gmail.com>
Date: Wed, 5 Feb 2014 19:16:04 +0000
Subject: LinHES-system: add idle.py to replace idle.sh. refs #958

update myth_mtc.py to use idle.py. update mythwelcome-config.py to update the db to use idle.py and run mythwelcome-config.py on install
---
 abs/core/LinHES-system/PKGBUILD              |  10 +-
 abs/core/LinHES-system/idle.py               | 310 +++++++++++++++++++++++++++
 abs/core/LinHES-system/myth_mtc.py           | 107 +--------
 abs/core/LinHES-system/mythwelcome-config.py |   2 +-
 abs/core/LinHES-system/system.install        |   3 +
 5 files changed, 322 insertions(+), 110 deletions(-)
 create mode 100755 abs/core/LinHES-system/idle.py

diff --git a/abs/core/LinHES-system/PKGBUILD b/abs/core/LinHES-system/PKGBUILD
index 1edffb8..8bb0e76 100755
--- a/abs/core/LinHES-system/PKGBUILD
+++ b/abs/core/LinHES-system/PKGBUILD
@@ -1,6 +1,6 @@
 pkgname=LinHES-system
 pkgver=8.1
-pkgrel=13
+pkgrel=14
 arch=('i686' 'x86_64')
 install=system.install
 pkgdesc="Everything that makes LinHES an automated system"
@@ -23,7 +23,7 @@ binfiles="LinHES-start optimize_mythdb.py myth_mtc.py
  misc_recent_recordings.pl misc_status_config.py misc_status_info.sh
  misc_upcoming_recordings.pl misc_which_recorder.pl
  change_channel.sh change_channel_wrapper.sh stop_xss.sh
- be_check.py checkXFSfrag.sh find_orphans.py idle.sh xwin_find.sh
+ be_check.py checkXFSfrag.sh find_orphans.py idle.py xwin_find.sh
  linhes_update.sh linhes_update2.sh myth2mkv myth2mp3 ripD_eject.sh
  mythwelcome-config.py mythwelcome-set-alarm.sh mythwelcome-test-wakeup.sh"
 
@@ -79,7 +79,7 @@ md5sums=('7ab2a2c643d2b286811d8303d08982ad'
          'de32a1c50101265dd7f6ca5037f7a26a'
          '301884fb60521627fffd1160b2cf5181'
          '76b2637cac0452b3acdbeeb4e8a5474b'
-         '22807bd1e37d2a07bc0bd3f2a9fd2bb4'
+         '6d473cfc5c8e2ffedbd894807824d56f'
          'dc3eef2a624754e16805d72bbe488b67'
          '617af86b901538817ebdcaf646248dc5'
          '542e670e78d117657f93141e9689f54d'
@@ -117,14 +117,14 @@ md5sums=('7ab2a2c643d2b286811d8303d08982ad'
          '8b0298f70f97cc1dc2a58b9a73c64bd3'
          '911b0fbc8d9178dac1a193346c9decaf'
          '34fc1f58ad1eabf4eff4979d420760c0'
-         'c3ada01d3a739abe3f920b02d4ea3f6e'
+         '1118e7982ba77cb5be9b2391b7cdfd38'
          'a94fe6d980f4b810f2e2ae5352084b39'
          '2c56266a79d058bf01f0de19c2cd042a'
          'c27d3fdf59b211f9d3cd76a81f6257dc'
          '503df99218373dfc75e7e7f5e449a44e'
          '4a1fda884dcd7d65fb2690fbdbd92a83'
          '2b7fe3b57592823a4c7e3ec132dcb7f4'
-         '92950f0ffb1faf1ed64c6be2b8fbc3f6'
+         '20dd97b614cab2454794416a3601c497'
          '95c092f67036a361ef7a57436f44332e'
          '410795ef9039e4c6c0484e706ecfd567'
          'eb879fee9603a05d5420d4ce8ed9e450'
diff --git a/abs/core/LinHES-system/idle.py b/abs/core/LinHES-system/idle.py
new file mode 100755
index 0000000..40bbb16
--- /dev/null
+++ b/abs/core/LinHES-system/idle.py
@@ -0,0 +1,310 @@
+#!/usr/bin/python2
+
+import argparse, os, re, subprocess, sys, time
+from datetime import datetime, date, timedelta
+
+def msg(cmdargs,msg):
+    if cmdargs.silent is False:
+        print "%s" %msg
+
+def mythshutdownlock_check(cmdargs,cursor):
+    if (cmdargs.lock):
+        msg(cmdargs,"    Checking mythshutdown for lock...")
+        try:
+            cursor.execute("select data from settings where value = 'MythShutdownLock'")
+            results=cursor.fetchone()
+        except:
+            return True
+        lock=results[0]
+        if int(lock) == 0 :
+            msg(cmdargs,"        mythshutdown is NOT locked.")
+            return True
+        else:
+            msg(cmdargs,"        mythshutdown is locked.")
+            return False
+    else:
+        return True
+
+def dailywake_check(cmdargs,cursor):
+    if (cmdargs.daily):
+        msg(cmdargs,"    Checking if in a daily wake period...")
+        dailyWake=False
+        today = date.today()
+        now = datetime.now()
+        try:
+            cursor.execute("select data from settings where value = 'DailyWakeupStartPeriod1'")
+            results=cursor.fetchone()
+            p1Start=datetime.strptime(' '.join([str(today), results[0]]), "%Y-%m-%d %H:%M")
+            cursor.execute("select data from settings where value = 'DailyWakeupEndPeriod1'")
+            results=cursor.fetchone()
+            p1End=datetime.strptime(' '.join([str(today), results[0]]), "%Y-%m-%d %H:%M")
+            cursor.execute("select data from settings where value = 'DailyWakeupStartPeriod2'")
+            results=cursor.fetchone()
+            p2Start=datetime.strptime(' '.join([str(today), results[0]]), "%Y-%m-%d %H:%M")
+            cursor.execute("select data from settings where value = 'DailyWakeupEndPeriod2'")
+            results=cursor.fetchone()
+            p2End=datetime.strptime(' '.join([str(today), results[0]]), "%Y-%m-%d %H:%M")
+        except:
+            print "error"
+            return True
+
+        # Check for time periods that cross midnight    
+        if (p1End < p1Start):
+            if (now > p1End):
+                p1End = p1End + timedelta(days=1)
+            else:
+                p1Start = p1Start + timedelta(days=-1)
+        if (p2End < p2Start):
+            if (now > p2End):
+                p2End = p2End + timedelta(days=1)
+            else:
+                p2Start = p2Start + timedelta(days=-1)
+
+        #Check for one of the daily wakeup periods
+        if (p1Start != p1End):
+            if (now >= p1Start and now <= p1End):
+                msg(cmdargs,"        Currently in daily wake period 1.")
+                return False
+        if (p2Start != p2End):
+            if (now >= p2Start and now <= p2End):
+                msg(cmdargs,"        Currently in daily wake period 2.")
+                return False
+
+        #Are we about to start a daily wakeup period using the -t TIME var
+        if (p1Start != p1End):
+            delta=p1Start-now
+            if (delta.seconds >= 0 and delta.seconds <= cmdargs.time * 60):
+                msg(cmdargs,"        Daily wake period 1 will start in less than %s minutes." %cmdargs.time)
+                return False
+        if (p2Start != p2End):
+            delta=p2Start-now
+            if (delta.seconds >= 0 and delta.seconds <= cmdargs.time * 60):
+                msg(cmdargs,"        Daily wake period 2 will start in less than %s minutes." %cmdargs.time)
+                return False
+
+        msg(cmdargs,"        Currently NOT in a daily wake period.")
+        return True
+    else:
+        return True
+
+def schemalock_check(cmdargs,cursor):
+    msg(cmdargs,"    Checking if the schema is locked...")
+    try:
+        cursor.execute("select count(*) from schemalock")
+        results=cursor.fetchone()
+    except:
+        return True
+    schemalock=results[0]
+    if schemalock == 0:
+        msg(cmdargs,"        The schema is NOT locked.")
+        return True
+    else:
+        msg(cmdargs,"        The schema is locked.")
+        return False
+
+def in_use(cmdargs,cursor):
+    msg(cmdargs,"    Checking if programs are in use...")
+    try:
+        cursor.execute("select count(*) from inuseprograms")
+        results=cursor.fetchone()
+    except:
+        return True
+    prginuse=results[0]
+    if prginuse == 0 :
+        msg(cmdargs,"        Programs are NOT in use.")
+        return True
+    else:
+        msg(cmdargs,"        Programs are in use.")
+        return False
+
+def job_check(cmdargs,cursor):
+    msg(cmdargs,"    Checking jobqueue for active jobs...")
+    try:
+        cursor.execute("select count(*) from jobqueue where status between 2 and 5")
+        results=cursor.fetchone()
+    except:
+        return True
+    jobs=results[0]
+    if jobs == 0 :
+        msg(cmdargs,"        No jobs are active.")
+        return True
+    else:
+        msg(cmdargs,"        Jobs are active.")
+        return False
+
+def upcoming_check(cmdargs,mythBE):
+    msg(cmdargs,"    Checking for recordings in the next %s minutes..." %cmdargs.time)
+    try:
+        upcoming = mythBE.getUpcomingRecordings()
+    except:
+        msg(cmdargs,"        Could not get upcoming recordings.")
+        return True
+    time_diff=10000
+    r=0
+    for i in upcoming:
+        r += 1
+        if r > 1:
+            break
+        show=str(i)
+        show=show.strip()
+        showtime=re.split("[-+]\d\d:\d\d",str(i.starttime))[0]
+        now=time.time()
+        rec_time=time.strptime( showtime ,"%Y-%m-%d %H:%M:%S" )
+        r=time.mktime(rec_time)
+        time_diff = ( r - now ) / 60
+
+    if ( time_diff > cmdargs.time) :
+        msg(cmdargs,"        No recordings starting in %s minutes." %cmdargs.time)
+        return True
+    else:
+        msg(cmdargs,"        A recording is starting in %s minutes." %int(time_diff))
+        return False
+
+def mfd_check(cmdargs):
+    msg(cmdargs,"    Checking if mythfilldatabase is running...")
+    with open(os.devnull, "w") as fnull:
+        mythfilldatabase_ret = subprocess.call(["pidof", "mythfilldatabase"], stdout=fnull)
+    if mythfilldatabase_ret == 0 :
+        msg(cmdargs,"        mythfilldatabase is running.")
+        return False
+    else:
+        msg(cmdargs,"        mythfilldatabase is NOT running.")
+        return True
+
+def mythtvsetup_check(cmdargs):
+    msg(cmdargs,"    Checking if mythtv-setup is running...")
+    with open(os.devnull, "w") as fnull:
+        mythsetup_ret = subprocess.call(["pidof", "mythtv-setup"], stdout=fnull)
+    if mythsetup_ret == 0 :
+        msg(cmdargs,"        mythtv-setup is running.")
+        return False
+    else:
+        msg(cmdargs,"        mythtv-setup is NOT running.")
+        return True
+
+def mythfe_check(cmdargs,cursor,mythDB):
+    if ( cmdargs.runningfe ):
+        msg(cmdargs,"    Checking for running and playing mythfrontends...")
+    else:
+        msg(cmdargs,"    Checking for playing mythfrontends...")
+    try:
+        #frontends = mythDB.getFrontends() #use cursor instead so it doesn't test connection
+        cursor.execute("select hostname from settings where value = 'FrontendIdleTimeout'")
+        frontends=cursor.fetchall()
+    except:
+        return True
+
+    for i in frontends:
+        try:
+            msg(cmdargs,"        Checking %s's mythfrontend status..." %i)
+            frontend = mythDB.getFrontend(''.join(i)) 
+            if ( cmdargs.runningfe ):
+                msg(cmdargs,"            %s's mythfrontend is RUNNING." %i)
+                return False
+            location = frontend.sendQuery('Location') 
+            if ( location.startswith('Playback ') ):
+                msg(cmdargs,"            %s's mythfrontend is PLAYING." %i)
+                return False
+            else:
+                msg(cmdargs,"            %s's mythfrontend is NOT playing." %i)
+        except:
+            msg(cmdargs,"            Could not connect to %s's mythfrontend." %i)
+
+    if ( cmdargs.runningfe ):
+        msg(cmdargs,"        No mythfrontends are running or playing.")
+    else:
+        msg(cmdargs,"        No mythfrontends are playing.")
+
+    return True
+
+def usage():
+    line = '''
+    idle.py checks if the system is idle.
+    Use idle.py -h to see options.
+
+    idle.py checks these parts of the system in this order to
+    determine if it is idle:
+    - (option -l) mythshutdown is locked return busy
+    - (option -d) In a daily wake period or
+        about to start a daily wake period return busy
+        checks the next 15 minutes. -t TIME changes time
+    - schema is locked return busy
+    - There are in use programs return busy
+    - There are active jobs in the job queue return busy
+    - mythfilldatabase is running return busy
+    - mythtv-setup is running return busy
+    - There are upcoming recordings return busy
+        checks the next 15 minutes. -t TIME changes time
+    - mythfrontends playing back a recording or video
+    - (option -r) mythfrontends running
+
+    idle.py stops checking and returns false (busy) when the first busy is found.
+    '''
+    print line
+    sys.exit(0)
+
+def main(args=[False]):
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-d', '--daily', action='store_true', help='Include daily wake & about to start wake in system busy. (default: daily wake & about to start wake is system idle)')
+    parser.add_argument('-l', '--lock', action='store_true', help='Include mythshutdown lock in system busy. (default: mythshutdown lock is system idle)')
+    parser.add_argument('-r', '--runningfe', action='store_true', help='Include running mythfrontends in system busy. (default: running mythfrontends are system idle)')
+    parser.add_argument('-s', '--silent', action='store_true', help='Run without printing output. Recommended for use in cron jobs or scripts.')
+    parser.add_argument('-t', '--time', type=int, default=15, help='Minutes of idle time needed to return idle for upcoming recordings and daily wake.')
+    parser.add_argument('-u', '--usage', action='store_true', help='Print usage instructions.')
+    if args[0] is False:
+        cmdargs = parser.parse_args()
+    else:
+        cmdargs = parser.parse_args(args)
+
+    if cmdargs.usage:
+        usage()
+    idle=True
+    msg(cmdargs,"Checking system idle...")
+
+    try:
+        from MythTV import MythDB
+        mythDB = MythDB()
+        cursor = mythDB.cursor()
+        db_conn=True
+    except:
+        msg(cmdargs,"Couldn't connect to MythTV database.")
+        db_conn=False
+
+    try:
+        from MythTV import MythBE
+        mythBE = MythBE()
+        be_conn=True
+    except:
+        msg(cmdargs,"Couldn't connect to MythTV backend.")
+        be_conn=False
+
+    if ( db_conn ):
+        if (mythshutdownlock_check(cmdargs,cursor) and dailywake_check(cmdargs,cursor) and schemalock_check(cmdargs,cursor) and in_use(cmdargs,cursor) and job_check(cmdargs,cursor)):
+            idle=True
+        else:
+            idle=False
+
+    if ( be_conn and idle ):
+        if (mfd_check(cmdargs) and mythtvsetup_check(cmdargs) and upcoming_check(cmdargs,mythBE)):
+            idle=True
+        else:
+            idle=False
+
+    if ( db_conn and idle ):
+        if ( mythfe_check(cmdargs,cursor,mythDB) ):
+            idle=True
+        else:
+            idle=False
+
+    if ( idle ):
+        msg(cmdargs,"System is idle.")
+    else:
+        msg(cmdargs,"System is busy.")
+    return idle
+
+if __name__ == "__main__":
+    idle=main()
+    if ( idle ):
+        exit(0)
+    else:
+        exit(1)
diff --git a/abs/core/LinHES-system/myth_mtc.py b/abs/core/LinHES-system/myth_mtc.py
index 7847313..c33a888 100755
--- a/abs/core/LinHES-system/myth_mtc.py
+++ b/abs/core/LinHES-system/myth_mtc.py
@@ -6,6 +6,7 @@ import socket
 import os
 import datetime,time
 import shlex
+import idle
 
 try:
     from MythTV import MythBE
@@ -21,9 +22,7 @@ def get_timestamp():
     date = (now.strftime('%Y-%m-%d %H:%M')) 
     return date
 
-
 def optimize():
-   
     try:
         cursor = mythtv.db.cursor()
         cursor.execute("SHOW tables")
@@ -39,96 +38,6 @@ def optimize():
             cmd= "%s  table %s" %(op,ctable)
             cursor.execute(cmd)
 
-
-def upcoming_check():
-    print "    Checking for upcoming shows"
-    try:
-        upcoming = mythtv.getUpcomingRecordings()
-    except:
-        return True
-    try:
-        show=str(upcoming[0])
-        show=show.strip()
-        showtime=show.partition("(")[2].strip(")")
-        now=time.time()
-        rec_time=time.strptime( showtime ,"%Y-%m-%d %H:%M:%S" )
-        r=time.mktime(rec_time)
-        time_diff= ( r - now ) / 60
-    except:
-        time_diff=100
-        show="No show"
-    if ( time_diff  >  30) :
-        return True
-    else:
-        print "      %s is upcoming in %s" %(show,time_diff)
-        return False
-
-
-def schemalock_check():
-    print "    Checking if schema is locked"
-    try:
-        c = mythtv.db.cursor()
-        c.execute("select count(*) from schemalock")
-        results=c.fetchone()
-        schemalock=results[0]
-    except:
-        return True
-
-    if schemalock == 0:
-        return True
-    else:
-        print "      schema is locked"
-        return False
-
-def job_check():
-    print "    Checking jobqueue"
-    try:
-        c = mythtv.db.cursor()
-        c.execute("select count(*) from jobqueue where status = 4")
-        results=c.fetchone()
-    except:
-        return True
-    jobs= results[0]
-    if jobs == 0 :
-        return True
-    else:
-        print "      jobs are running"
-        return False
-
-
-def in_use():
-    print "    Checking if programs are in use"
-    try:
-        c = mythtv.db.cursor()
-        c.execute("select count(*) from inuseprograms")
-        results=c.fetchone()
-    except:
-        return True
-    prginuse=results[0]
-    if prginuse == 0 :
-        return True
-    else:
-        print "      Programs in use"
-        return False
-
-def mfd_check():
-    print "    Checking is mythfilldatabase is running"
-    ps = subprocess.Popen("ps ax -o pid= -o args= ", shell=True, stdout=subprocess.PIPE)
-    ps_pid = ps.pid
-    output = ps.stdout.read()
-    ps.stdout.close()
-    ps.wait()
-    proc_name="mythfilldatabase"
-    for line in output.split("\n"):
-        res = re.findall("(\d+) (.*)", line)
-        if res:
-            pid = int(res[0][0])
-            if proc_name in res[0][1] and pid != os.getpid() and pid != ps_pid:
-                print "      mythfilldatabase is running"
-                return False
-
-    return True
-
 def bail_if_another_is_running():
     cmd = shlex.split("pgrep -u {} -f {}".format(os.getuid(), __file__))
     pids = subprocess.check_output(cmd).strip().split('\n')
@@ -138,19 +47,9 @@ def bail_if_another_is_running():
             __file__, " ".join(pids))
         raise SystemExit(1)
 
-
-def idle_check():
-    print "\n%s Checking Idle" %(get_timestamp())
-    if  (   upcoming_check() and schemalock_check() and job_check()  and in_use() and  mfd_check()  ):
-        idle=True
-        print "\n%s Myth is idle" %(get_timestamp())
-    else:
-        idle=False
-        print "\n%s Myth is NOT idle" %(get_timestamp())
-    return idle
-
 def run_stuff():
-    if idle_check():
+    print "\n%s" %get_timestamp()
+    if idle.main():
         print "\n#######################################"
         print "\n%s Running Optimize" %(get_timestamp())
         optimize()
diff --git a/abs/core/LinHES-system/mythwelcome-config.py b/abs/core/LinHES-system/mythwelcome-config.py
index 5ab24b0..8cf78c2 100755
--- a/abs/core/LinHES-system/mythwelcome-config.py
+++ b/abs/core/LinHES-system/mythwelcome-config.py
@@ -24,4 +24,4 @@ if mythdb.settings[localhostname].idleTimeoutSecs == u'0':
 mythdb.settings.NULL.WakeupTimeFormat = u'yyyy-MM-ddThh:mm:ss'
 mythdb.settings.NULL.SetWakeuptimeCommand = u'/usr/bin/mythshutdown --setwakeup $time'
 mythdb.settings.NULL.ServerHaltCommand = u'/usr/bin/mythshutdown --shutdown'
-mythdb.settings.NULL.preSDWUCheckCommand = u'/usr/LH/bin/idle.sh -s -m -r'
+mythdb.settings.NULL.preSDWUCheckCommand = u'/usr/LH/bin/idle.py -s -d -l -r'
diff --git a/abs/core/LinHES-system/system.install b/abs/core/LinHES-system/system.install
index 9f8aa45..6975070 100644
--- a/abs/core/LinHES-system/system.install
+++ b/abs/core/LinHES-system/system.install
@@ -13,6 +13,9 @@ post_install() {
         rm -f /etc/cron.daily/myth_mtc
     fi
 
+    #run mythwelcome-config.py to update shutdown check to use idle.py
+    /usr/LH/bin/mythwelcome-config.py
+
     sv restart msg_daemon
 }
 
-- 
cgit v0.12

