1.4.3: Bugfix: Timespan-init called every plugin-start (saved timespans
[enigma2-plugins.git] / advhdmi / src / plugin.py
1 # -*- coding: utf-8 -*-
2
3 from traceback import print_exc
4 from sys import stdout, exc_info
5 from . import _
6
7 # Plugin
8 from Plugins.Plugin import PluginDescriptor
9 from Components.config import config, configfile, ConfigSelection, ConfigSubsection, getConfigListEntry, ConfigSubList, \
10         ConfigClock, ConfigInteger, ConfigYesNo 
11 from Components.ConfigList import ConfigListScreen
12
13 # for function
14 from time import localtime, mktime
15 from Components.HdmiCec import hdmi_cec
16
17 def _print(outtxt):
18         ltim = localtime()
19         headerstr = "[AdvHdmiCec] %04d%02d%02d-%02d%02d%02d " %(ltim[0],ltim[1],ltim[2],ltim[3],ltim[4],ltim[5])
20         outtxt = headerstr + outtxt
21         print outtxt
22
23 try:
24         from Plugins.SystemPlugins.AdvHdmi.AdvHdmiCecSetup import AdvHdmiCecSetup
25         g_AdvHdmi_setup_available = True
26 except ImportError:
27         g_AdvHdmi_setup_available = False
28         _print("error while loading AdvHdmiCecSetup")
29         print_exc(file=stdout) 
30
31 # overwrite functions
32 from Plugins.SystemPlugins.HdmiCec.plugin import Cec
33 try:
34         from Plugins.Extensions.WebInterface.WebComponents.Sources.RemoteControl import RemoteControl
35         from Plugins.Extensions.WebInterface.WebComponents.Sources.PowerState import PowerState
36         g_AdvHdmi_webif_available = True
37 except ImportError:
38         _print("No Webinterface-Plugin installed")
39         g_AdvHdmi_webif_available = False
40
41 WEEKDAYS = [ 
42         _("Monday"),
43         _("Tuesday"),
44         _("Wednesday"),
45         _("Thursday"),
46         _("Friday"),
47         _("Saturday"),
48         _("Sunday")]
49
50 # Timespans
51 def initTimeSpanEntryList():
52         count = config.plugins.AdvHdmiCec.entriescount.value
53         if count != 0:
54                 i = 0
55                 while i < count:
56                         TimeSpanEntryInit()
57                         i += 1
58
59 def TimeSpanEntryInit():
60         now = localtime()
61         begin = mktime((now.tm_year, now.tm_mon, now.tm_mday, 8, 00, 0, now.tm_wday, now.tm_yday, now.tm_isdst))
62         end = mktime((now.tm_year, now.tm_mon, now.tm_mday, 16, 00, 0, now.tm_wday, now.tm_yday, now.tm_isdst))
63         
64         config.plugins.AdvHdmiCec.Entries.append(ConfigSubsection())
65         i = len(config.plugins.AdvHdmiCec.Entries) -1
66         config.plugins.AdvHdmiCec.Entries[i].fromWD = ConfigSelection(choices=[
67                 ("0", WEEKDAYS[0]),
68                 ("1", WEEKDAYS[1]),
69                 ("2", WEEKDAYS[2]),
70                 ("3", WEEKDAYS[3]),
71                 ("4", WEEKDAYS[4]),
72                 ("5", WEEKDAYS[5]),
73                 ("6", WEEKDAYS[6]),
74         ], default = "0")
75         config.plugins.AdvHdmiCec.Entries[i].toWD = ConfigSelection(choices=[
76                 ("0", WEEKDAYS[0]),
77                 ("1", WEEKDAYS[1]),
78                 ("2", WEEKDAYS[2]),
79                 ("3", WEEKDAYS[3]),
80                 ("4", WEEKDAYS[4]),
81                 ("5", WEEKDAYS[5]),
82                 ("6", WEEKDAYS[6]),
83         ], default = "6")
84         config.plugins.AdvHdmiCec.Entries[i].begin = ConfigClock(default = int(begin))
85         config.plugins.AdvHdmiCec.Entries[i].end = ConfigClock(default = int(end))
86         return config.plugins.AdvHdmiCec.Entries[i]
87
88 config.plugins.AdvHdmiCec = ConfigSubsection()
89 config.plugins.AdvHdmiCec.enable = ConfigYesNo(default = False)
90 config.plugins.AdvHdmiCec.debug = ConfigYesNo(default = False)
91 config.plugins.AdvHdmiCec.enable_power_on = ConfigYesNo(default = True)
92 config.plugins.AdvHdmiCec.enable_power_off = ConfigYesNo(default = True)
93 config.plugins.AdvHdmiCec.disable_after_enigmastart = ConfigYesNo(default = False)
94 config.plugins.AdvHdmiCec.disable_from_webif = ConfigYesNo(default = False)
95 config.plugins.AdvHdmiCec.entriescount =  ConfigInteger(0)
96 config.plugins.AdvHdmiCec.Entries = ConfigSubList()
97 config.plugins.AdvHdmiCec.show_in = ConfigSelection(choices=[
98                 ("system", _("systemmenue")),
99                 ("plugin", _("pluginmenue")),
100                 ("extension", _("extensions")),
101         ], default = "system")
102 initTimeSpanEntryList()
103
104 ADVHDMI_VERSION = "1.4.3"
105
106 # HDMI-Hook-Events
107 # To implement a hook, just instantiate a AdvHdmiCecIF, 
108 # and overwrite the methods before_event and/or after_event
109
110 # Events with boolean-return, that means if the CEC-signal has to be send / handled
111 ADVHDMI_BEFORE_POWERON = "BEFORE_POWERON"
112 ADVHDMI_BEFORE_POWEROFF = "BEFORE_POWEROFF"
113 ADVHDMI_BEFORE_RECEIVED_STANDBY = "BEFORE_RECEIVED_STANDBY"
114 ADVHDMI_BEFORE_RECEIVED_NOWACTIVE = "BEFORE_RECEIVED_NOWACTIVE"
115 # Events without return-value
116 ADVHDMI_AFTER_POWERON = "AFTER_POWERON"
117 ADVHDMI_AFTER_POWEROFF = "AFTER_POWEROFF"
118 ADVHDMI_AFTER_RECEIVED_STANDBY = "AFTER_RECEIVED_STANDBY"
119 ADVHDMI_AFTER_RECEIVED_NOWACTIVE = "AFTER_RECEIVED_NOWACTIVE"
120
121 # registered Hooks
122 advhdmiHooks = {}
123
124 def callHook(advhdmi_event):
125         if config.plugins.AdvHdmiCec.debug.value: _print("Debug: call Hooks for Event '" + str(advhdmi_event) + "'")
126         if advhdmiHooks:
127                 for hookKey,hook in advhdmiHooks.iteritems():
128                         if config.plugins.AdvHdmiCec.debug.value: _print("Debug: call Hook '" + str(hookKey) + "'")
129                         try: 
130                                 if advhdmi_event in (ADVHDMI_BEFORE_POWERON, ADVHDMI_BEFORE_POWEROFF, ADVHDMI_BEFORE_RECEIVED_STANDBY, ADVHDMI_BEFORE_RECEIVED_NOWACTIVE):
131                                         if not hook.before_event(advhdmi_event):
132                                                 _print("Hook '" + str(hookKey) + "' prevents sending HDMI-Cec-signal!")
133                                                 return False
134                                 else:
135                                         hook.after_event(advhdmi_event)
136                         except:
137                                 _print("Error while calling Hook " + str(hookKey))
138                                 print_exc(file=stdout)
139         if advhdmi_event in (ADVHDMI_BEFORE_POWERON, ADVHDMI_BEFORE_POWEROFF, ADVHDMI_BEFORE_RECEIVED_STANDBY, ADVHDMI_BEFORE_RECEIVED_NOWACTIVE):
140                 return True
141
142 def TimeSpanPresenter(confsection):
143         presenter = [
144                 WEEKDAYS[int(confsection.fromWD.value)],
145                 WEEKDAYS[int(confsection.toWD.value)] ]
146         timestr = "%02d:%02d" % tuple(confsection.begin.value)
147         presenter.append(str(timestr))
148         timestr = "%02d:%02d" % tuple(confsection.end.value)
149         presenter.append(str(timestr))
150         return presenter
151
152 # functionality
153 def autostart(reason, **kwargs):
154         global g_AdvHdmi_sessionstarted
155         if reason == 0:
156                 g_AdvHdmi_sessionstarted = True
157
158 def main(session, **kwargs):
159         global g_AdvHdmi_setup_available
160         if g_AdvHdmi_setup_available:
161                 session.open(AdvHdmiCecSetup)
162
163 def showinSetup(menuid):
164         if menuid != "system":
165                 return []
166         return [(_("Advanced HDMI-Cec Setup"), main, "", 46)]
167
168 def Plugins(**kwargs):
169         list = [
170                 PluginDescriptor(
171                         where = PluginDescriptor.WHERE_AUTOSTART,
172                         fnc = autostart)
173         ]
174         if config.plugins.AdvHdmiCec.show_in.value == "system":
175                 list.append (PluginDescriptor(
176                         name="Advanced HDMI-Cec Control", 
177                         description=_("manage when HDMI Cec is enabled"), 
178                         where = PluginDescriptor.WHERE_MENU, 
179                         fnc=showinSetup)
180                 )
181         if config.plugins.AdvHdmiCec.show_in.value == "plugin":
182                 list.append (PluginDescriptor(
183                         name = "Advanced HDMI-Cec Control",
184                         description = _("manage when HDMI Cec is enabled"),
185                         where = PluginDescriptor.WHERE_PLUGINMENU,
186                         fnc = main,
187                         needsRestart = False)
188                 )
189         if config.plugins.AdvHdmiCec.show_in.value == "extension":
190                 list.append (PluginDescriptor(
191                                 name = "Advanced HDMI-Cec Control",
192                                 description = _("manage when HDMI Cec is enabled"),
193                                 where = PluginDescriptor.WHERE_EXTENSIONSMENU,
194                                 fnc = main,
195                                 needsRestart = False)
196                 )
197         
198         return list
199         
200 def checkTimespan(lt, begin, end):
201         # Check if we span a day
202         if begin[0] > end[0] or (begin[0] == end[0] and begin[1] >= end[1]):
203                 # Check if begin of event is later than our timespan starts
204                 if lt.tm_hour > begin[0] or (lt.tm_hour == begin[0] and lt.tm_min >= begin[1]):
205                         # If so, event is in our timespan
206                         return True
207                 # Check if begin of event is earlier than our timespan end
208                 if lt.tm_hour < end[0] or (lt.tm_hour == end[0] and lt.tm_min <= end[1]):
209                         # If so, event is in our timespan
210                         return True
211                 return False
212         else:
213                 # Check if event begins earlier than our timespan starts
214                 if lt.tm_hour < begin[0] or (lt.tm_hour == begin[0] and lt.tm_min < begin[1]):
215                         # Its out of our timespan then
216                         return False
217                 # Check if event begins later than our timespan ends
218                 if lt.tm_hour > end[0] or (lt.tm_hour == end[0] and lt.tm_min > end[1]):
219                         # Its out of our timespan then
220                         return False
221                 return True
222
223 def AdvHdmiCecDOIT():
224         global g_AdvHdmi_sessionstarted
225         global g_AdvHdmi_fromwebif
226         ret_val = True
227         if config.plugins.AdvHdmiCec.enable.value:
228                 if g_AdvHdmi_sessionstarted and config.plugins.AdvHdmiCec.disable_after_enigmastart.value:
229                         _print("prevent sending HDMICec, because of enigmastart")
230                         ret_val = False
231
232                 if ret_val and g_AdvHdmi_fromwebif and config.plugins.AdvHdmiCec.disable_from_webif.value:
233                         _print("prevent sending HDMICec, because it was from webif")
234                         ret_val = False
235                 
236                 if ret_val and int(config.plugins.AdvHdmiCec.entriescount.value) > 0:
237                         lt = localtime()
238                         for e in config.plugins.AdvHdmiCec.Entries:
239                                 entr = [e]
240                                 if config.plugins.AdvHdmiCec.debug.value:
241                                         presenter = TimeSpanPresenter(e)
242                                         _print("Debug: Checking timespan '" + ", ".join( str(x) for x in presenter ) + "'")
243                                 if int(e.fromWD.getValue()) <=  int(lt[6]) \
244                                         and int(e.toWD.getValue()) >= int(lt[6]) :
245                                         presenter = TimeSpanPresenter(e)
246                                         if checkTimespan(lt, e.begin.getValue(), e.end.getValue()):
247                                                 _print("prevent sending HDMICec, because of timespan '" + ", ".join( str(x) for x in presenter ) + "'")
248                                                 ret_val = False
249                                         else:
250                                                 if config.plugins.AdvHdmiCec.debug.value: _print("Debug: Local Time is not between " + str(presenter[2]) + " and " + str(presenter[3]))
251                                 else:
252                                         if config.plugins.AdvHdmiCec.debug.value: _print("Debug: Local weekday (" + str(lt[6]) + ") is not between " + str(presenter[0]) + " and " + str(presenter[1]))
253                                 if not ret_val:
254                                         if config.plugins.AdvHdmiCec.debug.value: _print("Debug: Found matching Timespan, exit loop!")
255                                         break
256         g_AdvHdmi_sessionstarted = False
257         g_AdvHdmi_fromwebif = False
258
259         return ret_val
260
261 # Overwrite CEC-Base
262 def Cec__receivedStandby(self):
263         if config.plugins.cec.receivepower.value:
264                 from Screens.Standby import Standby, inStandby
265                 if not inStandby and self.session.current_dialog and self.session.current_dialog.ALLOW_SUSPEND and self.session.in_exec:
266                         if callHook(ADVHDMI_BEFORE_RECEIVED_STANDBY):
267                                 self.session.open(Standby)
268                                 callHook(ADVHDMI_AFTER_RECEIVED_STANDBY)
269
270 def Cec__receivedNowActive(self):
271         if config.plugins.cec.receivepower.value:
272                 from Screens.Standby import inStandby
273                 if inStandby != None:
274                         if callHook(ADVHDMI_BEFORE_RECEIVED_NOWACTIVE):
275                                 inStandby.Power()
276                                 callHook(ADVHDMI_AFTER_RECEIVED_NOWACTIVE)
277
278 def Cec_powerOn(self):
279         global g_AdvHdmi_initalized
280         if config.plugins.cec.sendpower.value:
281                 if self.session.shutdown:
282                         self.idle_to_standby = True
283                 else:
284                         if config.plugins.AdvHdmiCec.enable_power_on.value and AdvHdmiCecDOIT():
285                                 g_AdvHdmi_initalized = True
286                                 if callHook(ADVHDMI_BEFORE_POWERON):
287                                         _print("power on")
288                                         hdmi_cec.otp_source_enable()
289                                         callHook(ADVHDMI_AFTER_POWERON)
290
291 def Cec_powerOff(self):
292         global g_AdvHdmi_initalized
293         if config.plugins.cec.sendpower.value and config.plugins.AdvHdmiCec.enable_power_off.value and AdvHdmiCecDOIT():
294                 if callHook(ADVHDMI_BEFORE_POWEROFF):
295                         _print("power off")
296                         if not g_AdvHdmi_initalized:
297                                 _print("Workaround: enable Hdmi-Cec-Source (^=poweron)")
298                                 hdmi_cec.otp_source_enable()
299                         hdmi_cec.ss_standby()
300                         callHook(ADVHDMI_AFTER_POWEROFF)
301
302 # Overwrite WebIf
303 def RemoteControl_handleCommand(self, cmd):
304         global g_AdvHdmi_fromwebif
305         g_AdvHdmi_fromwebif = True
306         self.cmd = cmd
307         self.res = self.sendEvent()
308
309 def PowerState_handleCommand(self, cmd):
310         global g_AdvHdmi_fromwebif
311         g_AdvHdmi_fromwebif = True
312         self.cmd = cmd
313
314 g_AdvHdmi_sessionstarted = False
315 g_AdvHdmi_fromwebif = False
316 g_AdvHdmi_initalized = False
317
318 if config.plugins.AdvHdmiCec.enable.value:
319         _print("enabled")
320         Cec.__receivedStandby = Cec__receivedStandby
321         Cec.__receivedNowActive = Cec__receivedNowActive
322         Cec.powerOn = Cec_powerOn
323         Cec.powerOff = Cec_powerOff
324         if g_AdvHdmi_webif_available:
325                 RemoteControl.handleCommand = RemoteControl_handleCommand
326                 PowerState.handleCommand = PowerState_handleCommand