Hi everybody (mostly Dischi, Rob)!

Some time ago I promised to "finish" the nvram-wakeup integration. Currently, 
I am still running the 1.5 branch with the old (again attached), only 
slightly improved patch. The following problems still exist / features I 
wanna do (I will go into detail later):
- Freevo should shutdown after the recording.
- One might need to reboot the machine to make changes take effect.
- One must use the freevo shutdown option to start the programming.

What the patch does, is adding some user feedback, if he/she selects 
"Shutdown" during/before a recording. This will also be useful without 
nvram-wakeup.

Shutdown after recording:
------------------------
I had a look at freevoscreensaver.py (BTW: why isn't it just screensaver.py?), 
which gave me enough insight to write something similar for the automatic 
shutdown. Some thoughts:
- One cannot be sure that the computer was powered up because of a previous 
nvram-wakeup programming. I planned to check on Freevo startup whether the 
computer boot-up happend in a sane range (depending on config settings) 
before the next recording, assuming that it's the programmed start.
- Furthermore, I wanna check for any events (similar to the screensaver) which 
tell me that a human has started playing with Freevo, and cancel that 
automatic shutdown.
- Else, I want to display a "waiting for recording to finish" message with a 
"cancel" button (possibly even telling the remaining number of minutes), 
which can also be activated manually: If the user presses "Shutdown" during 
the recording, he/she will get this dialog with "Cancel" and "Force Shutdown" 
buttons.
QUESTION: I digged into plugin.py, wondering about the implementation of 
Plugin and the subclasses. Am I right that it's not possible to have ONE 
plugin that has both menu items and a poll function? What's the expected way 
to do sth. like that?

Necessary Reboots:
-----------------
If nvram-wakeup is called to program an automatic startup, it may return an 
exitcode of 1 (which it does on my system), which means that the computer 
needs to be restarted, because the BIOS has to finish the programming. In 
this case, my patch currently creates a flag file (of configurable location), 
and I added a "rebootflag" helper which checks this flag and by default calls 
config.SHUTDOWN_SYS_CMD:

freevo rebootflag [-c|-d|-s] [-v]

-c      only CHECK for the flag, exitcode 0 if present, 1 otherwise
-d      check for flag (as -c), and DELETE afterwards if it existed
-s      like -d but also SHUTDOWN the system if the flag existed (default)
-v      be verbose

This way, "freevo rebootflag" can be integrated into the early boot sequence 
to shut the system down ASAP. There are two possible additions:
1. One could change grub.conf (or similar) on shutdown if "freevo rebootflag 
-d" returns 0, to further reduce the bootup time for this extra run. I think 
this can safely be left to the advanced Freevo user.
2. I think a useful addition would be to check the flag also on Freevo 
startup, in case that the user did not yet integrate "freevo rebootflag" into 
his/her boot sequence. This leads me to this other simple
QUESTION: How can I re-use code between plugins and helpers? (E.g. call a 
function from helpers/rebootflag.py from plugins/shutdown.py or vice versa, 
to prevent code duplication.) Is there a special Freevo-way?

Shutdown via Freevo:
-------------------
Something that struck me lately is that after being logged into my Freevo 
maching remotely and maintaining the Gentoo system, I issued "halt"... which 
was stupid because the next two recordings on the following days were not 
executed because the nvram-wakup call happens in shutdown.py. :-(
I have two options in my mind:
- Let the recordserver to the nvram-wakup programming. This would ensure that 
recordings will happen, as long as no reboot is needed. The rebootflag would 
have to be checked on Freevo _or_ system shutdown however - one could add 
another "freevo halt" helper, and/or check the rebootflag on system shutdown; 
does so. know whether it's possible to change a shutdown in progress from 
runlevel 0 to 6/reboot?
- Force the user to shutdown the machine through Freevo (probably the 
above-mentioned helper would be no bad idea, then).
QUESTION: Which option is better/preferred?

Looking at my code, there's much room for improvement, and I'd like to cleanup 
shutdown.py in some more respects, paving the way for better 
suspend-integration, too.

I would be glad if you could answer my Freevo-architecture-related questions; 
also I'd be interested how much of this code can be re-used (/has to be 
redone) for Freevo 2?

Ciao, /  /                                                    .o.
     /--/                                                     ..o
    /  / ANS                                                  ooo
Index: local_conf.py.example
===================================================================
RCS file: /cvsroot/freevo/freevo/local_conf.py.example,v
retrieving revision 1.37.2.2
diff -u -3 -p -d -b -r1.37.2.2 local_conf.py.example
--- local_conf.py.example	21 Oct 2004 13:54:31 -0000	1.37.2.2
+++ local_conf.py.example	14 Nov 2004 22:08:36 -0000
@@ -771,12 +771,25 @@ IMAGEVIEWER_BLEND_MODE = -1
 # TV_RECORD_SERVER_IP = 'localhost'
 # TV_RECORD_SERVER_PORT = 18001
 
-# start every recording X minutes before scheduled,
+# Start every recording X minutes before scheduled,
 # and stop X minutes after scheduled - default to zero minutes.
 # This must be a value in seconds although at the moment only has
 # the percision of one minute.
 # TV_RECORD_PADDING = 0 * 60
 
+# Warn before shutting down the system if the next recording is
+# scheduled for starting in less than this number of seconds:
+# WARN_SHUTDOWN = 15 * 60 # quarter hour
+# (This has no extra effect if CONFIRM_SHUTDOWN is set, since then
+#  the shutdown is already confirmed.)
+
+# On Freevo shutdown, use nvram-wakeup to program the computer to
+# wakeup / boot up right before the next recording:
+# USE_NVRAM_WAKEUP    = 1
+
+# If using nvram-wakeup, time in seconds to startup before recording:
+# BOOTTIME_PADDING    = 2 * 60
+
 # VCR_AUDIO = (':adevice=%s' % AUDIO_DEVICE +
 #              ':audiorate=32000' +         # 44100 for better sound
 #              ':forceaudio:forcechan=1:' + # Forced mono for bug in my driver
Index: freevo_config.py
===================================================================
RCS file: /cvsroot/freevo/freevo/freevo_config.py,v
retrieving revision 1.349.2.4
diff -u -3 -p -d -b -r1.349.2.4 freevo_config.py
--- freevo_config.py	1 Nov 2004 21:38:58 -0000	1.349.2.4
+++ freevo_config.py	14 Nov 2004 22:08:37 -0000
@@ -293,6 +293,24 @@ RESTART_SYS_CMD  = 'shutdown -r now'  # 
 ENABLE_SHUTDOWN_SYS = 0  # Performs a whole system shutdown at SHUTDOWN!
                          # For standalone boxes.
 
+# Warn before shutting down the system if the next recording is
+# scheduled for starting in less than this number of seconds:
+WARN_SHUTDOWN = 15 * 60
+
+# On Freevo shutdown, use nvram-wakeup to program the computer to
+# wakeup / boot up right before the next recording:
+USE_NVRAM_WAKEUP = 0
+
+# See SHUTDOWN_SYS_CMD for sudo comment.
+# If you change this, note that an exitcode of 1 means "reboot needed"
+# and should get through to Freevo
+NVRAM_WAKEUP_CMD = 'nvram-wakeup -s %d'
+
+# If using nvram-wakeup, time in seconds to startup before recording:
+BOOTTIME_PADDING = 150
+
+# Location of the reboot-flag used if nvram-wakeup returns 1:
+NVRAM_REBOOT_FLAG = '%s/reboot_flag' % FREEVO_CACHEDIR
 
 #
 # You can add more keybindings by adding them to the correct hash. 
Index: src/plugins/shutdown.py
===================================================================
RCS file: /cvsroot/freevo/freevo/src/plugins/shutdown.py,v
retrieving revision 1.7
diff -u -3 -p -d -b -r1.7 shutdown.py
--- src/plugins/shutdown.py	10 Jul 2004 12:33:40 -0000	1.7
+++ src/plugins/shutdown.py	14 Nov 2004 22:08:37 -0000
@@ -50,6 +50,9 @@ from gui import ConfirmBox
 from item import Item
 from plugin import MainMenuPlugin
 
+if config.WARN_SHUTDOWN or config.USE_NVRAM_WAKEUP:
+    import tv.record_client as record_client
+
 
 def shutdown(menuw=None, argshutdown=None, argrestart=None, exit=False):
     """
@@ -126,7 +129,6 @@ def shutdown(menuw=None, argshutdown=Non
         time.sleep(1)
         
 
-
 class ShutdownItem(Item):
     """
     Item for shutdown
@@ -146,7 +148,7 @@ class ShutdownItem(Item):
                           (self.confirm_system_restart, _('Restart system') ) ]
         else:
             items = [ (self.shutdown_freevo, _('Shutdown Freevo') ),
-                          (self.shutdown_system, _('Shutdown system') ),
+                      (self.check_shutdown_system, _('Shutdown system') ),
                           (self.shutdown_system_restart, _('Restart system') ) ]
         if config.ENABLE_SHUTDOWN_SYS:
             items = [ items[1], items[0], items[2] ]
@@ -154,12 +156,46 @@ class ShutdownItem(Item):
         return items
 
 
+    def next_scheduled_recording(self):
+        """
+        return starting time of next scheduled recording (or None)
+        """
+        (server_available, msg) = record_client.connectionTest()
+        if not server_available:
+            return None
+        (result, recordings) = record_client.getScheduledRecordings()
+        if result:
+            progs = recordings.getProgramList().values()
+            if len(progs):
+                progs.sort(lambda a, b: cmp(a.start, b.start))
+                return progs[0].start
+        return None
+
+
+    def next_recording_message(self, format, start_time = None):
+        if start_time == None:
+            start_time = self.next_scheduled_recording()
+        if start_time == None:
+            return ""
+        rec_distance = start_time - time.time() - config.TV_RECORD_PADDING
+        if rec_distance < 0:
+            result = _('A recording is in progress.')
+		elif rec_distance < 60*60:
+            result = _('The next scheduled recording begins in %d minutes.') % int(rec_distance/60)
+        elif rec_distance < 60*60*10:
+            result = _('The next scheduled recording begins at %s.') % time.strftime(config.TV_TIMEFORMAT, time.localtime(start_time))
+        else:
+            result = _('The next recording is scheduled for %s.') % time.strftime(config.TV_DATETIMEFORMAT, time.localtime(start_time))
+        return format % result
+
+
     def confirm_freevo(self, arg=None, menuw=None):
         """
         Pops up a ConfirmBox.
         """
         self.menuw = menuw
-        what = _('Do you really want to shut down Freevo?')
+        what = _('Do you really want to shut down Freevo?') \
+               + self.next_recording_message(" %s")
         ConfirmBox(text=what, handler=self.shutdown_freevo, default_choice=1).show()
         
         
@@ -168,41 +204,87 @@ class ShutdownItem(Item):
         Pops up a ConfirmBox.
         """
         self.menuw = menuw
-        what = _('Do you really want to shut down the system?')
+        what = _('Do you really want to shut down the system?') \
+               + self.next_recording_message(" %s")
         ConfirmBox(text=what, handler=self.shutdown_system, default_choice=1).show()
 
+
     def confirm_system_restart(self, arg=None, menuw=None):
         """
         Pops up a ConfirmBox.
         """
         self.menuw = menuw
-        what = _('Do you really want to restart the system?')
+        what = _('Do you really want to restart the system?') \
+               + self.next_recording_message(" %s")
         ConfirmBox(text=what, handler=self.shutdown_system_restart, default_choice=1).show()
 
 
+    def check_shutdown_system(self, arg=None, menuw=None):
+        """
+        Shutdown the complete system if the next recording is not too far away
+        """
+        if config.WARN_SHUTDOWN:
+            start_time = self.next_scheduled_recording()
+            if start_time != None:
+                if start_time - config.TV_RECORD_PADDING - time.time() \
+                       < config.WARN_SHUTDOWN:
+                    what = self.next_recording_message("%s ", start_time) + \
+                           _('Do you really want to shut down the system?')
+                    ConfirmBox(text=what, handler=self.shutdown_system, default_choice=1).show()
+                    return
+        self.shutdown_system(arg, menuw)
+
+
     def shutdown_freevo(self, arg=None, menuw=None):
         """
-        shutdown freevo, don't shutdown the system
+        Shutdown freevo, don't shutdown the system
         """
         shutdown(menuw=menuw, argshutdown=False, argrestart=False)
 
         
     def shutdown_system(self, arg=None, menuw=None):
         """
-        shutdown the complete system
+        Shutdown the complete system, use nvram-wakeup to schedule
+        boot-up before next recording (if configured to do so).
+        nvram-wakup may signal that an additional reboot is needed
+        (with exitcode 1), in this case a flag file is created and the
+        system is rebooted.
+        """
+        doShutdown = True
+        if config.USE_NVRAM_WAKEUP:
+            start_time = self.next_scheduled_recording()
+            if start_time != None:
+                wakeupTime = start_time \
+                             - config.TV_RECORD_PADDING \
+                             - config.BOOTTIME_PADDING
+                _debug_("calling nvram-wakeup with %d" % wakeupTime)
+                ec = os.system(config.NVRAM_WAKEUP_CMD % (wakeupTime,))
+                _debug_(".. exitcode was %d" % ec)
+                if ec == 256:
+                    doShutdown = False
+                    file(config.NVRAM_REBOOT_FLAG, "w").close()
+                elif ec > 0:
+                    ConfirmBox(text=_('Could not program computer to boot up before next recording. Shutdown anyway?'),
+                               handler=self.shutdown_system_anyway, default_choice=1).show()
+                    return
+        shutdown(menuw=menuw, argshutdown=doShutdown, argrestart=not doShutdown)
+
+
+    def shutdown_system_anyway(self, arg=None, menuw=None):
+        """
+        Shutdown freevo, don't shutdown the system
         """
         shutdown(menuw=menuw, argshutdown=True, argrestart=False)
 
+
     def shutdown_system_restart(self, arg=None, menuw=None):
         """
-        restart the complete system
+        Restart the complete system
         """
         shutdown(menuw=menuw, argshutdown=False, argrestart=True)
 
         
         
-
-
 #
 # the plugins defined here
 #
@@ -214,5 +296,3 @@ class PluginInterface(MainMenuPlugin):
 
     def items(self, parent):
         return [ ShutdownItem(parent) ]
-
-

Attachment: rebootflag.py
Description: helpers/rebootflag.py

Reply via email to