def __proc_command(self): """ Called when it is time to execute another command. This function simply returns if the queue is empty. Otherwise it pops the next command, executes that command, and then sets a Timer to go off the given number of milliseconds and call __proc_command again to process the next command. """ # No more commands if self.commands.empty(): self.timer = None return # Pop the next command and run it cmd = self.commands.get() funct = cmd[1] before = DateTime.now().millis funct() after = DateTime.now().millis # Calculate how long to sleep delta = after - before pause = to_datetime(cmd[0]) trigger_time = to_datetime(cmd[0]).minusMillis(delta) # Create/reschedule the Timer if not self.timer: self.timer = ScriptExecution.createTimer(trigger_time, self.__proc_command) else: self.timer.reschedule(trigger_time)
def defer(target, value, when, log, is_command=True): """ Use this function to schedule a command to be sent to an Item at the specified time or after the speficied delay. If the passed in time or delay ends up in the past, the command is sent immediately. Arguments: - target: Item name to send the command to - value: the command to send the Item - when: at what time to delay to action until, see to_datetime in the timer_utils library - is_command: whether to send value to target as an update or command, defaults to True - log: logger passed in from the Rule """ trigger_time = to_datetime(when, log) if not trigger_time: log.error( "Cannot schedule a deferred action, {} is not a valid date time or duration" .format(when)) # If trigger_time is in the past, schedule for now if trigger_time.isBefore(DateTime.now()): trigger_time = DateTime.now() # Schedule the timer func = lambda: timer_body(target, value, is_command, when, log) flap = lambda: log.debug( "there is already a timer set for {}, rescheduling".format(target)) timers.check(target, trigger_time, function=func, flapping_function=flap, reschedule=True)
def __expired(self): """Called when the timer expired, reschedules if necessary""" when = self.function() if when: dt = to_datetime(when) self.timer = ScriptExecution.createTimer(dt, self.__expired)
def check(self, key, when, function=None, flapping_function=None, reschedule=False): """Call to check whether a key has a Timer. If no Timer exists, creates a new timer to run the passed in function. If a Timer exists, reschedule it if reschedule is True and if a flapping_function was passed, run it. Arguments: - key: The key to set a Timer for. - when: The time for when the timer should go off. Supports: - DateTime objects - ISO 8601 formatted Strings - Python int, treated as number of seconds into the future - DecimalType, PercentType, or QuantityType (intValue() is called), treated as number of seconds into the future - Duration string of the format Xd Xh Xm Xs where: - d: days - h: hours - m: minutes - s: seconds - X: integer or floating point number for the amount e.g. 1h3s represents one hour and three seconds - function: Optional function to call when the Timer expires - flapping_function: Optional function to call if the key already has a Timer running. Defaults to None. - reschedule: Optional flag that causes the Timer to be rescheduled when the key already has a Timer. Defaults to False. """ timeout = to_datetime(when) TimerMgr_logger.debug("timeout is: " + str(timeout)) # Timer exists: if the reschedule flag is set, reschedule it, otherwise # cancel it. If a flapping function was passed to us, call the flapping # function. if key in self.timers: if reschedule: self.timers[key]['timer'].reschedule(timeout) TimerMgr_logger.debug("rescheduling timer for: " + str(key)) else: self.cancel(key) TimerMgr_logger.debug("Timer cancelled for: " + str(key)) if flapping_function: flapping_function() TimerMgr_logger.debug("Running flapping function for: " + str(key)) # No timer exists, create the Timer else: TimerMgr_logger.debug("Creating timer for: " + str(key)) timer = ScriptExecution.createTimer( timeout, lambda: self.__not_flapping(key)) self.timers[key] = { 'timer': timer, 'flapping': flapping_function, 'not_flapping': function if function else self.__noop } TimerMgr_logger.debug("Timer created: " + str(self.timers[key]))
def run(self, func, when): """If it has been long enough since the last time that run was called, execute the passed in func. Otherwise ignore the call. Arguments: - func: The lambda or function to call if allowed. - when: When the rate limit will expire. Can be a DateTime type object, a number which is treated as seconds, or a duration string (e.g. 5m 2.5s), or an ISO 8601 formatted date string. See time_utils for details """ now = DateTime().now() if now.isAfter(self.until): self.until = to_datetime(when) func()
def __init__(self, function, when=None): """Initializes and kicks off the looping timer. Arguments: - function: The function to call when the timer goes off. The function must return the time for the next time the timer should run (see when below). If None is returned the timer will not be rescheduled. - when: Optional time when to kick off the first call to function. It can be any of the forms supported by to_datetime in time_utils (e.g. "1s"). If None is passed the lambda will be called immediately. """ self.function = function self.timer = None if not when: self.__expired() else: self.timer = ScriptExecution.createTimer(to_datetime(when), self.__expired)
def __init__(self, log, time, func, count_item): """Initializes the CountdownTimer Object and starts the Timer running. Arguments: - log: The logger from the Rule that created the Timer. - time: The DateTime when the Timer should expire. - func: The function or lambda to call when the Timer expires. - count_item: The name of the Item to update with the amount of time until the Timer expires. """ self.log = log self.func = func self.count_item = count_item self.timer = None self.start = to_python_datetime(DateTime().now()) try: self.end_time = to_python_datetime(to_datetime(time)) except TypeError: self.log.error("Time is not a recognized DateTime type") return self.time_left = self.end_time - self.start self.__iterate__()
str(today_ZonedDateTime.toLocalTime())) #Test other format test_dict = { 'integer: ': int(5000), 'duration: ': "5s", 'Decimal type: ': DecimalType(5000), #'Percent type: ': PercentType(100), 'Quantity Type: ': QuantityType('5000ms'), 'ISO 8601 format': DateTime().now().plusSeconds(5).toString() } #Test other format to Joda for keys in test_dict: log.info("Checking " + keys + " to Joda DateTime") assert abs(seconds_between(ZonedDateTime.now().plus(5000, ChronoUnit.MILLIS), to_datetime(test_dict[keys], log = log))) < 1, \ "failed to return a datetime with offset of {} from {}" \ .format(str(test_dict[keys]),str(keys)) #Test other format to python test_dict['ISO 8601 format'] = DateTime().now().plusSeconds(5).toString() for keys in test_dict: log.info("Checking " + keys + " to Python datetime") assert abs(seconds_between(ZonedDateTime.now().plus(5000, ChronoUnit.MILLIS), to_datetime(test_dict[keys], output='Python', log = log))) < 1, \ "failed to return a datetime with offset of {} from {}" \ .format(str(test_dict[keys]),str(keys)) #Test other format to Java test_dict['ISO 8601 format'] = DateTime().now().plusSeconds(5).toString() for keys in test_dict: