Updated to 3.4.0. Don's sleep wehile HDD is active
[enigma2-plugins.git] / elektro / src / plugin.py
1 #
2 # Power Save Plugin by gutemine
3 # Rewritten by Morty (morty@gmx.net)
4 # HDD Mod by joergm6
5 #
6 # Deep standby will be called sleep. Normal standby will be named standby!
7 # All calculations are in the local timezone, or in the relative Timezone.
8 # In the relative timezone the day starts at "nextday". If it is before nextday the last day will be used.
9 #
10 #
11
12
13 #from enigma import *
14
15
16 from Screens.InfoBarGenerics import *
17 # from RecordTimer import *
18
19
20 import calendar 
21 #################
22
23 # Plugin
24 from Plugins.Plugin import PluginDescriptor
25
26 # GUI (Screens)
27 from Screens.Screen import Screen
28 from Components.ConfigList import ConfigListScreen
29 from Screens.MessageBox import MessageBox
30 from Screens.Console import Console
31 from Screens import Standby 
32
33 # GUI (Summary)
34 # from Screens.Setup import SetupSummary
35
36 # GUI (Components)
37 from Components.ActionMap import ActionMap
38 from Components.Button import Button
39
40 from Components.Harddisk import harddiskmanager
41
42 # Configuration
43 from Components.config import getConfigListEntry, ConfigEnableDisable, \
44         ConfigYesNo, ConfigText, ConfigClock, ConfigNumber, ConfigSelection, \
45         config, ConfigSubsection, ConfigSubList, ConfigSubDict
46
47 # Startup/shutdown notification
48 from Tools import Notifications
49
50 import os
51 # Timer, etc
52
53 #import time
54 from time import localtime, asctime, time, gmtime
55 # import datetime
56 # import codecs
57
58
59 # Enigma system functions
60 from enigma import quitMainloop, eTimer
61
62
63 # import Wakeup?!
64 from Tools.DreamboxHardware import getFPWasTimerWakeup
65
66
67
68 # from Tools import Directories
69 import gettext
70 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
71 try:
72         _ = gettext.translation('elektro', resolveFilename(SCOPE_PLUGINS, "Extensions/Elektro/locale"), [config.osd.language.getText()]).gettext
73 except IOError:
74         print "[Elektro] Locale not found!"
75         pass
76
77 #############
78
79 # Globals
80 session = None
81 ElektroWakeUpTime = -1
82 elektro_pluginversion = "3.4.0"
83 elektro_readme = "/usr/lib/enigma2/python/Plugins/Extensions/Elektro/readme.txt"
84 elektrostarttime = 60 
85 elektrosleeptime = 5
86 elektroShutdownThreshold = 60 * 20
87
88
89 #Configuration
90 config.plugins.elektro = ConfigSubsection()
91 config.plugins.elektro.nextday = ConfigClock(default = ((6 * 60 + 0) * 60) )
92
93 config.plugins.elektro.sleep = ConfigSubDict()
94 for i in range(7):
95         config.plugins.elektro.sleep[i] = ConfigClock(default = ((1 * 60 + 0) * 60) )
96
97 config.plugins.elektro.wakeup = ConfigSubDict()
98 for i in range(7):
99         config.plugins.elektro.wakeup[i] = ConfigClock(default = ((9 * 60 + 0) * 60) )
100
101 config.plugins.elektro.standbyOnBoot = ConfigEnableDisable(default = False)
102 config.plugins.elektro.standbyOnManualBoot =  ConfigEnableDisable(default = True)
103 config.plugins.elektro.standbyOnBootTimeout = ConfigNumber(default = 60)
104 config.plugins.elektro.enable = ConfigEnableDisable(default = False)
105 config.plugins.elektro.nextwakeup = ConfigNumber(default = 0)
106 config.plugins.elektro.force = ConfigEnableDisable(default = False)
107 config.plugins.elektro.dontwakeup = ConfigEnableDisable(default = False)
108 config.plugins.elektro.holiday =  ConfigEnableDisable(default = False)
109 config.plugins.elektro.hddsleep =  ConfigEnableDisable(default = False)
110
111
112
113 weekdays = [
114         _("Monday"),
115         _("Tuesday"),
116         _("Wednesday"),
117         _("Thursday"),
118         _("Friday"),
119         _("Saturday"),
120         _("Sunday"),
121 ]
122
123
124 #global ElektroWakeUpTime
125 ElektroWakeUpTime = -1
126
127 def autostart(reason, **kwargs):
128         global session  
129         if reason == 0 and kwargs.has_key("session"):
130                 session = kwargs["session"]
131                 session.open(DoElektro)
132
133 def getNextWakeup():
134         global ElektroWakeUpTime
135         
136         #it might happen, that session does not exist. I don't know why. :-(
137         if session is None:
138                 return ElektroWakeUpTime;
139         
140         nextTimer = session.nav.RecordTimer.getNextRecordingTime()
141         print "[Elektro] Now: " + strftime("%a:%H:%M:%S",  gmtime(time()))
142         if (nextTimer < 1) or (nextTimer > ElektroWakeUpTime):
143                 print "[Elektro] will wake up " + strftime("%a:%H:%M:%S",  gmtime(ElektroWakeUpTime))
144                 return ElektroWakeUpTime
145         
146         #We have to make sure, that the Box will wake up because of us
147         # and not because of the timer
148         print "[Elektro] will wake up due to the next timer" + strftime("%a:%H:%M:%S",  gmtime(nextTimer))
149         return nextTimer - 1
150            
151         
152         
153         
154 def Plugins(**kwargs):
155         return [
156                 PluginDescriptor(
157                         name="Elektro", 
158                         description="Elektro Power Save Plugin Ver. " + elektro_pluginversion, 
159                         where = [
160                                 PluginDescriptor.WHERE_SESSIONSTART, 
161                                 PluginDescriptor.WHERE_AUTOSTART
162                         ], 
163                         fnc = autostart, 
164                         wakeupfnc=getNextWakeup
165                 ),
166                 PluginDescriptor(
167                         name="Elektro", 
168                         description="Elektro Power Save Plugin Ver. " + elektro_pluginversion, 
169                         where = PluginDescriptor.WHERE_PLUGINMENU, 
170                         icon="elektro.png", 
171                         fnc=main
172                 )
173         ]
174
175         
176 def main(session,**kwargs):
177         try:    
178                 session.open(Elektro)
179         except:
180                 print "[Elektro] Pluginexecution failed"
181
182 class Elektro(ConfigListScreen,Screen):
183         skin = """
184                         <screen position="center,center" size="550,400" title="Elektro Power Save Ver. """ + elektro_pluginversion + """" >
185                         <widget name="config" position="0,0" size="550,360" scrollbarMode="showOnDemand" />
186                         
187                         <widget name="key_red" position="0,360" size="140,40" valign="center" halign="center" zPosition="4"  foregroundColor="white" font="Regular;18" transparent="1"/> 
188                         <widget name="key_green" position="140,360" size="140,40" valign="center" halign="center" zPosition="4"  foregroundColor="white" font="Regular;18" transparent="1"/> 
189                         <widget name="key_yellow" position="280,360" size="140,40" valign="center" halign="center" zPosition="4"  foregroundColor="white" font="Regular;18" transparent="1"/>
190                         
191                         <ePixmap name="red"    position="0,360"   zPosition="2" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
192                         <ePixmap name="green"  position="140,360" zPosition="2" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
193                         <ePixmap name="yellow" position="280,360" zPosition="2" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" /> 
194                 </screen>"""
195                 
196         def __init__(self, session, args = 0):
197                 self.session = session
198                 Screen.__init__(self, session)
199         
200                 
201                 self.list = []
202                 
203                 
204                 self.list.append(getConfigListEntry(_("Enable Elektro Power Save"),config.plugins.elektro.enable))
205                 self.list.append(getConfigListEntry(_("Standby on boot"), config.plugins.elektro.standbyOnBoot ))
206                 self.list.append(getConfigListEntry(_("Standby on manual boot"), config.plugins.elektro.standbyOnManualBoot ))
207                 self.list.append(getConfigListEntry(_("Standby on boot screen timeout"), config.plugins.elektro.standbyOnBootTimeout))
208                 self.list.append(getConfigListEntry(_("Force sleep (even when not in standby)"), config.plugins.elektro.force ))
209                 self.list.append(getConfigListEntry(_("Don't sleep while hdd is active (e.g. ftp)"), config.plugins.elektro.hddsleep ))
210                 self.list.append(getConfigListEntry(_("Dont wake up"), config.plugins.elektro.dontwakeup ))
211                 self.list.append(getConfigListEntry(_("Holiday mode (experimental)"), config.plugins.elektro.holiday ))
212                 
213                 self.list.append(getConfigListEntry(_("Next day starts at"), config.plugins.elektro.nextday))
214
215                 for i in range(7):
216                         self.list.append(getConfigListEntry(weekdays[i] + ": "  + _("Wakeup"), config.plugins.elektro.wakeup[i]))
217                         self.list.append(getConfigListEntry(weekdays[i] + ": "  + _("Sleep"), config.plugins.elektro.sleep[i]))
218                         
219                 ConfigListScreen.__init__(self, self.list)
220                 
221                 self["key_red"] = Button(_("Cancel"))
222                 self["key_green"] = Button(_("Ok"))
223                 self["key_yellow"] = Button(_("Help"))
224                 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
225                 {
226                         "red": self.cancel,
227                         "green": self.save,
228                         "yellow": self.help,
229                         "save": self.save,
230                         "cancel": self.cancel,
231                         "ok": self.save,
232                 }, -2)
233         
234         def save(self):
235                 #print "saving"
236                 for x in self["config"].list:
237                         x[1].save()
238                 self.close(True,self.session)
239
240         def cancel(self):
241                 #print "cancel"
242                 for x in self["config"].list:
243                         x[1].cancel()
244                 self.close(False,self.session)
245                 
246         def help(self):
247                 self.session.open(Console,_("Showing Elektro readme.txt"),["cat %s" % elektro_readme])
248
249
250 class DoElektro(Screen):
251         skin = """ <screen position="center,center" size="300,300" title="Elektro Plugin Menu" > </screen>"""
252         
253         def __init__(self,session):
254                 Screen.__init__(self,session)
255                 
256                 print "[Elektro] Starting up Version " + elektro_pluginversion
257                 
258                 self.session = session
259                 
260                 # Make sure wakeup time is set.
261                 self.setNextWakeuptime()
262                 
263                 # If we didn't wake up by a timer we don't want to go to sleep any more.
264                 # Unforturnately it is not possible to use getFPWasTimerWakeup()
265                 # Therfore we're checking wheter there is a recording starting within
266                 # the next five min             
267                 self.dontsleep = False
268                 
269                 #Let's assume we got woken up manually
270                 timerWakeup = False
271                 
272                 #Is a recording already runniong ->woken up by a timer
273                 if self.session.nav.RecordTimer.isRecording():
274                         timerWakeup = True
275                 # Is the next timer within 5 min -> woken up by a timer 
276                 if abs(self.session.nav.RecordTimer.getNextRecordingTime() - time()) <= 360:
277                         timerWakeup = True
278                         
279                 # Did we wake up by Elektro?
280                 # Let's hope this get's run early enaugh, and this get's run
281                 # before the requested wakeup-time (should be the case)
282                 #
283                 if abs(ElektroWakeUpTime - time()) <= 360:
284                         timerWakeup = True      
285                         
286                 # If the was a manual wakeup: Don't go to sleep 
287                 if timerWakeup == False:
288                         self.dontsleep = True
289                 
290                 
291                 #Check whether we should try to sleep:
292                 trysleep = config.plugins.elektro.standbyOnBoot.value
293                 
294                 #Don't go to sleep when this was a manual wakeup and the box shouldn't go to standby
295                 if timerWakeup == False and     config.plugins.elektro.standbyOnManualBoot.value == False:
296                         trysleep = False
297                         
298         
299                 #if waken up by timer and configured ask whether to go to sleep.
300                 if trysleep:
301                         self.TimerStandby = eTimer()
302                         self.TimerStandby.callback.append(self.CheckStandby)
303                         self.TimerStandby.startLongTimer(elektrosleeptime)
304                         print "[Elektro] Set up standby timer"
305
306                 self.TimerSleep = eTimer()
307                 self.TimerSleep.callback.append(self.CheckElektro)
308                 self.TimerSleep.startLongTimer(elektrostarttime)
309                 print "[Elektro] Set up sleep timer"
310                 print "[Elektro] Translation test: " + _("Standby on boot")
311                 
312         def clkToTime(self, clock):
313                 return ( (clock.value[0]) * 60 + (int)(clock.value[1]) )  * 60
314                 
315         def getTime(self):
316                 ltime = localtime();
317                 return ( (int)(ltime.tm_hour) * 60 + (int)(ltime.tm_min) ) * 60
318         
319         def getPrintTime(self, secs):
320                 return strftime("%H:%M:%S", gmtime(secs))
321
322         
323         # This function converts the time into the relative Timezone where the day starts at "nextday"
324         # This is done by substracting nextday from the current time. Negative times are corrected using the mod-operator
325         def getReltime(self, time):
326                 nextday = self.clkToTime(config.plugins.elektro.nextday)
327                 return (time - nextday) %  (24 * 60 * 60)
328                 
329         
330         def CheckStandby(self):
331                 print "[Elektro] Showing Standby Sceen "
332                 try:
333                         self.session.openWithCallback(self.DoElektroStandby,MessageBox,_("Go to Standby now?"),type = MessageBox.TYPE_YESNO,
334                                         timeout = config.plugins.elektro.standbyOnBootTimeout.value)            
335                 except:
336                         # Couldn't be shown. Restart timer.
337                         print "[Elektro] Failed Showing Standby Sceen "
338                         self.TimerStandby.startLongTimer(elektrostarttime)
339
340
341         def DoElektroStandby(self,retval):
342                 if (retval):
343                         #Yes, go to sleep
344                         Notifications.AddNotification(Standby.Standby)
345                 
346
347                         
348         def setNextWakeuptime(self):
349                 # Do not set a wakeup time if
350                 #  - Elektro isn't enabled
351                 #  - Elektro shouldn't wake up
352                 #  - Holiday mode is turned on
353                 if ((config.plugins.elektro.enable.value == False) 
354                       or (config.plugins.elektro.dontwakeup.value == True)
355                       or config.plugins.elektro.holiday.value == True): 
356                         global ElektroWakeUpTime
357                         ElektroWakeUpTime = -1
358                         return
359                         
360                 time_s = self.getTime()
361                 ltime = localtime()
362                 
363                 #print "Nextday:" + time.ctime(self.clkToTime(config.plugins.elektro.nextday))
364                 # If it isn't past next-day time we need yesterdays settings
365                 if time_s < self.clkToTime(config.plugins.elektro.nextday):
366                         day = (ltime.tm_wday - 1) % 7
367                 else:
368                         day = ltime.tm_wday
369                 
370                 #Check whether we wake up today or tomorrow
371                 # Relative Time is needed for this
372                 time_s = self.getReltime(time_s)
373                 wakeuptime = self.getReltime(self.clkToTime(config.plugins.elektro.wakeup[day]))
374                 
375                 # Lets see if we already woke up today
376                 if wakeuptime < time_s:
377                         #yes we did -> Next wakeup is tomorrow
378                         #print "Elektro: Wakeup tomorrow"
379                         day = (day + 1) % 7
380                         wakeuptime = self.getReltime(self.clkToTime(config.plugins.elektro.wakeup[day]))
381                 
382                 # Tomorrow we'll wake up erly-> Add a full day.
383                 if wakeuptime < time_s:
384                         wakeuptime = wakeuptime + 24 * 60 * 60
385                 
386                 # The next wakeup will be in wakupin seconds
387                 wakeupin = wakeuptime - time_s
388                 
389                 # Now add this to the current time to get the wakeuptime
390                 wakeuptime = (int)(time()) + wakeupin
391                 
392                 #Write everything to the global variable
393                 ElektroWakeUpTime = wakeuptime
394                         
395                         
396         def CheckElektro(self):
397                 # first set the next wakeuptime - it would be much better to call that function on sleep. This will be a todo!
398                 self.setNextWakeuptime()
399         
400                 #convert to seconds
401                 time_s = self.getTime()
402                 ltime = localtime()
403                 
404                 print "[Elektro] Testtime; " + self.getPrintTime(2 * 60 * 60)
405                 
406                 #Which day is it? The next day starts at nextday
407                 print "[Elektro] wday 1: " + str(ltime.tm_wday)
408                 if time_s < self.clkToTime(config.plugins.elektro.nextday):
409                         day = (ltime.tm_wday - 1) % 7
410                 else:
411                         day = ltime.tm_wday
412                         
413                 print "[Elektro] wday 2: " + str(day)
414                 
415                 #Let's get the day
416                 wakeuptime = self.clkToTime(config.plugins.elektro.wakeup[day])
417                 sleeptime = self.clkToTime(config.plugins.elektro.sleep[day])
418                 print "[Elektro] Current time: " + self.getPrintTime(time_s)
419                 print "[Elektro] Wakeup time: " + self.getPrintTime(wakeuptime)
420                 print "[Elektro] Sleep time: " + self.getPrintTime(sleeptime)
421                 
422                 #convert into relative Times
423                 time_s = self.getReltime(time_s)
424                 wakeuptime  = self.getReltime(wakeuptime)
425                 sleeptime = self.getReltime(sleeptime)
426                 
427                 print "[Elektro] Current Rel-time: " + self.getPrintTime(time_s)
428                 print "[Elektro] Wakeup Rel-time: " + self.getPrintTime(wakeuptime)
429                 print "[Elektro] Sleep Rel-time: " + self.getPrintTime(sleeptime)
430                 
431                 
432                 #let's see if we should be sleeping
433                 trysleep = False
434                 if time_s < (wakeuptime - elektroShutdownThreshold): # Wakeup is in the future -> sleep!
435                         trysleep = True
436                         print "[Elektro] Wakeup!" + str(time_s) + " < " + str(wakeuptime)
437                 if sleeptime < time_s : #Sleep is in the past -> sleep!
438                         trysleep = True
439                         print "[Elektro] Sleep: " + str(sleeptime) + " < " + str(time_s)
440                 
441                 #We are not tying to go to sleep anymore -> maybe go to sleep again the next time
442                 if trysleep == False:
443                         self.dontsleep = False
444                 
445                 #The User aborted to got to sleep -> Don't go to sleep.
446                 if self.dontsleep:
447                         trysleep = False
448                         
449                 # If we are in holydaymode we should try to got to sleep anyway
450                 # This should be set after self.dontsleep has been handled
451                 if config.plugins.elektro.holiday.value:
452                         trysleep = True
453                 
454                 # We are not enabled -> Dont go to sleep (This could have been catched earlier!)
455                 if config.plugins.elektro.enable.value == False:
456                         trysleep = False
457                 
458                 # Only go to sleep if we are in standby or sleep is forced by settings
459                 if  not ((Standby.inStandby) or (config.plugins.elektro.force.value == True) ):
460                         trysleep = False
461                 
462                 # No Sleep while recording
463                 if self.session.nav.RecordTimer.isRecording():
464                         trysleep = False
465                 
466                 # No Sleep on HDD running - joergm6
467                 if (config.plugins.elektro.hddsleep.value == True) and (harddiskmanager.HDDCount() > 0):
468                         hddlist = harddiskmanager.HDDList()
469                         if not hddlist[0][1].isSleeping():
470                                 trysleep = False
471                 
472                 # Will there be a recording in a short while?
473                 nextRecTime = self.session.nav.RecordTimer.getNextRecordingTime()
474                 if  (nextRecTime > 0) and (nextRecTime - (int)(time()) <  elektroShutdownThreshold):
475                         trysleep = False
476                         
477                 # Looks like there really is a reason to go to sleep -> Lets try it!
478                 if trysleep:
479                         #self.();
480                         try:
481                                 self.session.openWithCallback(self.DoElektroSleep, MessageBox, _("Go to sleep now?"),type = MessageBox.TYPE_YESNO,timeout = 60) 
482                         except:
483                                 #reset the timer and try again
484                                 self.TimerSleep.startLongTimer(elektrostarttime) 
485                                 
486                 #set Timer, which calls this function again.
487                 self.TimerSleep.startLongTimer(elektrostarttime) 
488                 
489                 
490
491
492         def DoElektroSleep(self,retval):
493                 if (retval):
494                         # os.system("wall 'Powermanagent does Deepsleep now'")
495                         #  Notifications.AddNotification(TryQuitMainloop,1)
496                         # 1 = Deep Standby -> enigma2:/doc/RETURNCODES
497                         
498                         global inTryQuitMainloop
499                         if Standby.inTryQuitMainloop == False:
500                                 self.session.open(Standby.TryQuitMainloop, 1) # <- This might not work reliably
501                                 #quitMainloop(1)
502                 else:
503                         # Dont try to sleep until next wakeup
504                         self.dontsleep = True
505                         #Start the timer again
506                         self.TimerSleep.startLongTimer(elektrostarttime) 
507