plugins/Timer/__init__.py
eg.RegisterPlugin(
name = "Timer",
author = "Bartman",
version = "2.0",
guid = "{6149CA99-1FCD-4450-9160-7543BC20CFD3}",
description = (
"Triggers an event after an adjustable time and optionally repeats it "
"after an interval."
),
url = "http://www.eventghost.net/forum/viewtopic.php?t=572",
)
import time
class Text:
stopped = "Plugin stopped"
timerFinished = "Timer finished"
listhl = "Currently active Timers:"
colLabels = ("Timer Name",
"Start time",
"Next event",
"Event Name",
"Loop Counter",
"Loops",
"Interval")
class TimerAction:
name = "Start new or control running timer"
description = "Allows starting, stopping or resetting timers, which can trigger an event after a given time"
timerName = "Timer name:"
start = "Start new timer (currently running timer with the same name will be aborted)"
startTime = "Start:"
startTimeTypes = (
"immediately",
"after interval time",
"at given time (HH:MM:SS)",
"after given duration (HH:MM:SS)",
"next full minute",
"next full five minutes",
"next full 15 minutes",
"next full 30 minutes",
"next hour"
)
actions = (
"Restart timer with existing settings",
"Restart timer (when running only)",
"Reset the loop counter",
"Abort")
loop1 = "Loops: "
loop2 = "(0 = unlimited)"
showRemaingLoopsText = "loop counter shows remaining loops"
interval1 = "Interval:"
interval2 = "seconds"
eventName = "Event name:"
addCounterToName = "add loop counter to event name" #(otherwise payload only)"
labelStartUnlimited = 'Start timer "%s" (unlimited loops, %.2f seconds interval)'
labelStartOneTime = 'Start timer "%s"'
labelStart = 'Start timer "%s" (%s loops, %.2f seconds interval)'
labels = (
'Restart timer "%s"',
'Restart timer "%s" if it is still running' ,
'Reset counter of timer "%s"',
'Abort timer "%s"'
)
class TimerObject():
def __init__(self,
plugin,
name,
loops,
interval,
eventName,
addCounterToName,
showRemainingLoops,
startTimeType,
startTime
):
#copy settings to instance variables
self.plugin = plugin
self.name = name
self.interval = interval
if self.interval <= 0:
self.loops = 1 #prevent constant eventTriggering
else:
self.loops = loops
self.eventName = eventName
self.addCounterToName = addCounterToName
self.showRemainingLoops = showRemainingLoops
self.startTimeType = startTimeType
self.startTime = startTime
self.ScheduleFirst()
def ScheduleFirst(self):
self.loopCounter = 0
self.active = True
self.startedAt = time.time()
#immediately
if self.startTimeType == 0:
self.nextEventAt = self.startedAt
self.TriggerScheduledEvent(self.nextEventAt)
return
#after interval time
if self.startTimeType == 1:
self.nextEventAt = self.startedAt + self.interval
#at given time (HH:MM:SS)
elif self.startTimeType == 2:
hoursStr, minutesStr, secondsStr = self.startTime.split(":")
hours = int(hoursStr)
minutes = int(minutesStr)
seconds = int(secondsStr)
#check if we have to schedule today or tomorrow
now = time.localtime(self.startedAt)
self.nextEventAt = time.mktime((now[0], now[1], now[2], hours, minutes, seconds, now[6], now[7], -1))
if (self.nextEventAt <= self.startedAt):
#have to start tomorrow
self.nextEventAt = time.mktime((now[0], now[1], now[2] + 1, hours, minutes, seconds, now[6], now[7], -1))
#after given duration (HH:MM:SS)
elif self.startTimeType == 3:
hoursStr, minutesStr, secondsStr = self.startTime.split(":")
self.nextEventAt = self.startedAt + int(hoursStr) * 3600 + int(minutesStr) * 60 + int(secondsStr)
#next full x minute
elif self.startTimeType > 3 and self.startTimeType < 9:
now = time.localtime(self.startedAt)
times = (1, 5, 15, 30, 60)
fullMinutes = times[self.startTimeType - 4]
minutes = ((now[4] / fullMinutes) + 1) * fullMinutes
self.nextEventAt = time.mktime((now[0], now[1], now[2], now[3], minutes, 0, now[6], now[7], now[8]))
else:
raise ValueError("unknown startTimeType")
eg.scheduler.AddShortTaskAbsolute(self.nextEventAt, self.TriggerScheduledEvent, self.nextEventAt)
def TriggerScheduledEvent(self, scheduledTime):
if not self.plugin.started or not self.active or self.nextEventAt != scheduledTime:
#timer has changed in some way
return
if self.showRemainingLoops and self.loops != 0:
loopDisplay = self.loops - self.loopCounter - 1
else:
loopDisplay = self.loopCounter
eventNameTmp = self.eventName
if self.addCounterToName:
eventNameTmp += str(loopDisplay)
self.plugin.TriggerEvent(eventNameTmp, (loopDisplay, time.strftime("%c")))
self.loopCounter += 1
self.ScheduleNext()
def ScheduleNext(self):
if not self.IsActive():
#no more event to schedule
return
self.nextEventAt += self.interval
eg.scheduler.AddShortTaskAbsolute(self.nextEventAt, self.TriggerScheduledEvent, self.nextEventAt)
def Restart(self):
#just reschedule
self.ScheduleFirst()
def Abort(self):
self.active = False
def ResetCounter(self):
self.loopCounter = 0
def IsActive(self):
return self.plugin.started and self.active and not self.HasFinished()
def HasFinished(self):
return self.loops != 0 and self.loopCounter >= self.loops
class Timer(eg.PluginClass):
text = Text
started = False
def __init__(self):
self.AddAction(TimerAction)
#timer names are kept for usability reasons
self.timerNames = []
self.lastTimerName = ""
self.timerObjects = {}
def __start__(self):
self.started = True
def __stop__(self):
self.started = False
#end all running timers
self.AbortAllTimers()
def __close__(self):
self.AbortAllTimers()
def OnComputerSuspend(self, suspendType):
self.AbortAllTimers()
#methods to Control timers
def StartTimer(self,
timerName,
loops,
interval,
eventName,
addCounterToName,
showRemainingLoops,
startTimeType,
startTime
):
timer = self.timerObjects.get(timerName)
if timer:
timer.Abort()
timer = TimerObject(self,
timerName,
loops,
interval,
eventName,
addCounterToName,
showRemainingLoops,
startTimeType,
startTime)
self.timerObjects[timerName] = timer
def ResetTimerCounter(self, timerName):
timer = self.timerObjects.get(timerName)
if timer:
if timer.IsActive():
timer.ResetCounter()
else:
eg.PrintError(Text.timerFinished + timerName)
return False
def AbortTimer(self, timerName):
timer = self.timerObjects.get(timerName)
if timer:
del self.timerObjects[timerName]
timer.Abort()
def AbortAllTimers(self):
for timer in self.timerObjects.itervalues():
timer.Abort()
self.timerObjects = {}
def RestartTimer(self, timerName, startNewIfNotAlive = False):
timer = self.timerObjects.get(timerName)
if timer:
if timer.IsActive() or startNewIfNotAlive:
timer.Restart()
def RestartAllTimers(self, startNewIfNotAlive = False):
for timer in self.timerObjects.itervalues():
if timer.IsActive() or startNewIfNotAlive:
timer.Restart()
def Configure(self, *args):
panel = eg.ConfigPanel(self, resizable=True)
panel.sizer.Add(
wx.StaticText(panel, -1, Text.listhl),
flag = wx.ALIGN_CENTER_VERTICAL
)
mySizer = wx.GridBagSizer(5, 5)
timerListCtrl = wx.ListCtrl(panel, -1, style=wx.LC_REPORT | wx.VSCROLL | wx.HSCROLL)
for i, colLabel in enumerate(Text.colLabels):
timerListCtrl.InsertColumn(i, colLabel)
#setting column width to fit label
#insert date to get size
timerListCtrl.InsertStringItem(0, "Test EventName")
timerListCtrl.SetStringItem(0, 1, time.strftime("%c"))
size = 0
for i in range(7):
timerListCtrl.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER) #wx.LIST_AUTOSIZE
size += timerListCtrl.GetColumnWidth(i)
timerListCtrl.SetMinSize((size, -1))
mySizer.Add(timerListCtrl, (0,0), (1, 5), flag = wx.EXPAND)
#buttons
abortButton = wx.Button(panel, -1, "Abort")
mySizer.Add(abortButton, (1,0))
abortAllButton = wx.Button(panel, -1, "Abort all")
mySizer.Add(abortAllButton, (1,1), flag = wx.ALIGN_CENTER_HORIZONTAL)
restartButton = wx.Button(panel, -1, "Restart")
mySizer.Add(restartButton, (1,2), flag = wx.ALIGN_CENTER_HORIZONTAL)
restartAllButton = wx.Button(panel, -1, "Restart All")
mySizer.Add(restartAllButton, (1,3), flag = wx.ALIGN_CENTER_HORIZONTAL)
refreshButton = wx.Button(panel, -1, "Refresh")
mySizer.Add(refreshButton, (1,4), flag = wx.ALIGN_RIGHT)
mySizer.AddGrowableRow(0)
mySizer.AddGrowableCol(1)
mySizer.AddGrowableCol(2)
mySizer.AddGrowableCol(3)
panel.sizer.Add(mySizer, 1, flag = wx.EXPAND)
def PopulateList (event):
timerListCtrl.DeleteAllItems()
row = 0
for timer in self.timerObjects.itervalues():
if timer.IsActive():
timerListCtrl.InsertStringItem(row, timer.name)
#print "Timer", t.name, t.eventName, t.loopCounter
timerListCtrl.SetStringItem(row,
1, time.strftime("%c", time.localtime(timer.startedAt)))
timerListCtrl.SetStringItem(row,
2, time.strftime("%X", time.localtime(timer.nextEventAt)))
timerListCtrl.SetStringItem(row,
3, timer.eventName)
timerListCtrl.SetStringItem(row,
4, str(timer.loopCounter))
timerListCtrl.SetStringItem(row,
5, str(timer.loops))
timerListCtrl.SetStringItem(row,
6, str(timer.interval) + " sec")
row += 1
ListSelection(wx.CommandEvent())
def OnAbortButton(event):
item = timerListCtrl.GetFirstSelected()
while item != -1:
name = timerListCtrl.GetItemText(item)
self.AbortTimer(name)
item = timerListCtrl.GetNextSelected(item)
PopulateList(wx.CommandEvent())
event.Skip()
def OnAbortAllButton(event):
self.AbortAllTimers()
PopulateList(wx.CommandEvent())
event.Skip()
def OnRestartButton(event):
item = timerListCtrl.GetFirstSelected()
while item != -1:
name = timerListCtrl.GetItemText(item)
self.RestartTimer(name)
item = timerListCtrl.GetNextSelected(item)
PopulateList(wx.CommandEvent())
event.Skip()
def OnRestartAllButton(event):
self.RestartAllTimers()
PopulateList(wx.CommandEvent())
event.Skip()
def ListSelection(event):
flag = timerListCtrl.GetFirstSelected() != -1
abortButton.Enable(flag)
restartButton.Enable(flag)
event.Skip()
def OnSize(event):
timerListCtrl.SetColumnWidth(6, wx.LIST_AUTOSIZE_USEHEADER) #wx.LIST_AUTOSIZE
event.Skip()
PopulateList(wx.CommandEvent())
#timerListCtrl.SetMinSize(timerListCtrl.GetBestFittingSize())
abortButton.Bind(wx.EVT_BUTTON, OnAbortButton)
abortAllButton.Bind(wx.EVT_BUTTON, OnAbortAllButton)
restartButton.Bind(wx.EVT_BUTTON, OnRestartButton)
restartAllButton.Bind(wx.EVT_BUTTON, OnRestartAllButton)
refreshButton.Bind(wx.EVT_BUTTON, PopulateList)
timerListCtrl.Bind(wx.EVT_LIST_ITEM_SELECTED, ListSelection)
timerListCtrl.Bind(wx.EVT_LIST_ITEM_DESELECTED, ListSelection)
panel.Bind(wx.EVT_SIZE, OnSize)
while panel.Affirmed():
panel.SetResult(*args)
#function to fill the timer name ComboBox
def GetTimerNames(self):
self.timerNames.sort(lambda a,b: cmp(a.lower(), b.lower()) )
return self.timerNames
#function to collect timer names for ComboBox
def AddTimerName(self, timerName):
#self.lastTimerName = timerName
if not timerName in self.timerNames:
self.timerNames.append(timerName)
class TimerAction(eg.ActionClass):
def __call__(self,
timerName,
action,
loops,
interval,
eventName,
addCounterToName,
showRemainingLoops,
startTimeType,
startTime
):
if not self.plugin.started:
self.PrintError(Text.stopped)
return False
if action == 0:#start
self.plugin.StartTimer(timerName,
loops,
interval,
eventName,
addCounterToName,
showRemainingLoops,
startTimeType,
startTime)
elif action == 1:#restart
self.plugin.RestartTimer(timerName, True)
elif action == 2:#restart, when running only
self.plugin.RestartTimer(timerName, False)
elif action == 3:#reset counter
self.plugin.ResetTimerCounter(timerName)
elif action == 4:#abort
self.plugin.AbortTimer(timerName)
else:
raise ValueError("unknown action index")
def GetLabel(self,
timerName,
action,
loops,
interval,
eventName,
addCounterToName,
showRemainingLoops,
startTimeType,
startTime
):
self.plugin.AddTimerName(timerName)
if action == 0:
if loops == 0:
return Text.labelStartUnlimited % (timerName, interval)
if loops == 1:
return Text.labelStartOneTime % timerName
return Text.labelStart % (timerName, loops, interval)
return Text.labels[action-1] % timerName
def Configure(self,
timerName = None,
action = 0,
loops = 1,
interval = 1,
eventName = "",
addCounterToName = False,
showRemainingLoops = True,
startTimeType = 1,
startTime = "00:00:00"
):
plugin = self.plugin
panel = eg.ConfigPanel(self)
#name
nameSizer = wx.BoxSizer(wx.HORIZONTAL)
nameSizer.Add(
wx.StaticText(panel, -1, Text.TimerAction.timerName),
flag = wx.ALIGN_CENTER_VERTICAL
)
if not timerName:
timerName = plugin.lastTimerName
timerNameCtrl = wx.ComboBox(panel, -1,
timerName,
choices = plugin.GetTimerNames(),
size=(200,-1))
nameSizer.Add(timerNameCtrl, flag = wx.EXPAND)
panel.sizer.Add(nameSizer)
panel.sizer.Add(wx.Size(5,5))
#action and settings
#sizer = wx.GridBagSizer(5, 5)
#sizer.SetEmptyCellSize((0,0))
choices = len(Text.TimerAction.actions)
rb = range(0, choices + 1)
rb[0] = wx.RadioButton(panel, -1, Text.TimerAction.start, style = wx.RB_GROUP)
rb[0].SetValue(action == 0)
panel.sizer.Add(wx.Size(5,5))
panel.sizer.Add(rb[0], flag = wx.ALIGN_CENTER_VERTICAL)
#space to indent the settings
startSettingsSizer = wx.GridBagSizer(5, 5)
rowCount = 0 #used to find the correct row of the gridbagsizer
startSettingsSizer.Add(wx.Size(rowCount,1), (1, 0))
#loop
startSettingsSizer.Add(
wx.StaticText(panel, -1, Text.TimerAction.loop1),
(rowCount, 0), flag = wx.ALIGN_CENTER_VERTICAL)
loopCtrl = eg.SpinIntCtrl(panel, -1, loops, 0, size=(200,-1))
startSettingsSizer.Add(loopCtrl, (rowCount, 1), flag = wx.EXPAND)
startSettingsSizer.Add(
wx.StaticText(panel, -1, Text.TimerAction.loop2),
(rowCount, 2), (1, 2),
flag = wx.ALIGN_CENTER_VERTICAL)
#showRemaingLoopsText
rowCount += 1
showRemaingLoopsCtrl = wx.CheckBox(panel, -1, Text.TimerAction.showRemaingLoopsText)
showRemaingLoopsCtrl.SetValue(showRemainingLoops)
startSettingsSizer.Add(showRemaingLoopsCtrl, (rowCount, 1), (1, 3))
#intervall
rowCount += 1
startSettingsSizer.Add(
wx.StaticText(panel, -1, Text.TimerAction.interval1),
(rowCount, 0), flag = wx.ALIGN_CENTER_VERTICAL)
intervalCtrl = eg.SpinNumCtrl(
panel, -1, interval, size=(200,-1), integerWidth=7
)
startSettingsSizer.Add(intervalCtrl, (rowCount, 1), flag = wx.EXPAND)
startSettingsSizer.Add(
wx.StaticText(panel, -1, Text.TimerAction.interval2),
(rowCount, 2), (1, 2),
flag = wx.ALIGN_CENTER_VERTICAL)
#startTime
rowCount += 1
startSettingsSizer.Add(
wx.StaticText(panel, -1, Text.TimerAction.startTime),
(rowCount, 0), flag = wx.ALIGN_CENTER_VERTICAL)
startTimeTypeCtrl = wx.Choice(panel, -1, choices = Text.TimerAction.startTimeTypes)
startTimeTypeCtrl.SetSelection(startTimeType)
startSettingsSizer.Add(startTimeTypeCtrl, (rowCount, 1), (1, 2), flag = wx.EXPAND)
startTimeCtrl = wx.lib.masked.timectrl.TimeCtrl(
panel,
format = "24HHMMSS"
)
startTimeCtrl.SetValue(startTime)
startSettingsSizer.Add(startTimeCtrl, (rowCount, 3), flag = wx.EXPAND)
#eventName
rowCount += 1
startSettingsSizer.Add(
wx.StaticText(panel, -1, Text.TimerAction.eventName),
(rowCount, 0), flag = wx.ALIGN_CENTER_VERTICAL)
eventNameCtrl = wx.TextCtrl(panel, -1, eventName, size=(200,-1))
startSettingsSizer.Add(eventNameCtrl, (rowCount, 1), (1, 3), flag = wx.EXPAND)
#addCounterToName
rowCount += 1
addCounterToNameCtrl = wx.CheckBox(panel, -1, Text.TimerAction.addCounterToName)
addCounterToNameCtrl.SetValue(addCounterToName)
startSettingsSizer.Add(addCounterToNameCtrl, (rowCount, 1), (1, 3))
settingsSizer = wx.BoxSizer(wx.HORIZONTAL)
settingsSizer.Add(wx.Size(20,20))
settingsSizer.Add(startSettingsSizer)
panel.sizer.Add(wx.Size(5,5))
panel.sizer.Add(settingsSizer)
#remaining radio buttons
for i in range(1, len(rb)):
rowCount += 1
rb[i] = wx.RadioButton(panel, -1, Text.TimerAction.actions[i - 1])
rb[i].SetValue(action == i)
panel.sizer.Add(wx.Size(5,5))
panel.sizer.Add(rb[i], flag = wx.ALIGN_CENTER_VERTICAL)
def onRadioButton(event):
flag = rb[0].GetValue()
loopCtrl.Enable(flag)
showRemaingLoopsCtrl.Enable(flag)
intervalCtrl.Enable(flag)
eventNameCtrl.Enable(flag)
addCounterToNameCtrl.Enable(flag)
startTimeTypeCtrl.Enable(flag)
tmp = startTimeTypeCtrl.GetSelection()
startTimeCtrl.Enable(flag and (tmp == 2 or tmp == 3))
event.Skip()
def onChoiceChange(event):
tmp = startTimeTypeCtrl.GetSelection()
startTimeCtrl.Enable(tmp == 2 or tmp == 3)
event.Skip()
onRadioButton(wx.CommandEvent())
for i in range(len(rb)):
rb[i].Bind(wx.EVT_RADIOBUTTON, onRadioButton)
startTimeTypeCtrl.Bind(wx.EVT_CHOICE, onChoiceChange)
#panel.sizer.Add(sizer)
while panel.Affirmed():
timerName = timerNameCtrl.GetValue()
plugin.lastTimerName = timerName
plugin.AddTimerName(timerName)
for i in range(len(rb)):
if rb[i].GetValue():
action = i
break
loops = loopCtrl.GetValue()
showRemainingLoops = showRemaingLoopsCtrl.GetValue()
eventName = eventNameCtrl.GetValue()
interval = intervalCtrl.GetValue()
startTimeType = startTimeTypeCtrl.GetSelection()
addCounterToName = addCounterToNameCtrl.GetValue()
startTime = startTimeCtrl.GetValue()
panel.SetResult(
timerName,
action,
loops,
interval,
eventName,
addCounterToName,
showRemainingLoops,
startTimeType,
startTime
)