Added RepeatedTime class to use for repeated tasks

Utilizing it for temperature and sd status polling in comm.py
This commit is contained in:
Gina Häußge 2015-03-25 16:48:30 +01:00
parent b3739c10cc
commit 1c1e6b45b6
2 changed files with 70 additions and 12 deletions

View file

@ -534,6 +534,69 @@ def address_for_client(host, port):
except:
continue
class RepeatedTimer(threading.Thread):
"""
This class represents an action that should be run repeatedly in a predefined interval. It is similar to python's
own :class:`threading.Timer` class, but instead of only running once the ``function`` will be run again and again,
sleeping the stated ``interval`` in between.
RepeatedTimers are started, as with threads, by calling their ``start()`` method. The timer can be stopped (in
between runs) by calling the :func:`cancel` method. The interval the time waited before execution of a loop may
not be exactly the same as the interval specified by the user.
For example:
.. code-block:: python
def hello():
print("Hello World!")
t = Timer(1.0, hello)
t.start() # prints "Hello World!" every second
Arguments:
interval (float): The interval between each ``function`` call, in seconds.
function (callable): The function to call.
args (list or tuple): The arguments for the ``function`` call.
kwargs (dict): The keyword arguments for the ``function`` call.
run_first (boolean): If set to True, the function will be run for the first time *before* the first wait period.
If set to False (the default), the function will be run for the first time *after* the first wait period.
"""
def __init__(self, interval, function, args=None, kwargs=None, run_first=False):
threading.Thread.__init__(self)
if args is None:
args = []
if kwargs is None:
kwargs = dict()
self.interval = interval
self.function = function
self.finished = threading.Event()
self.args = args
self.kwargs = kwargs
self.run_first = run_first
def cancel(self):
self.finished.set()
def run(self):
while True:
if self.run_first:
# if we are to run the function BEFORE waiting for the first time
self.function(*self.args, **self.kwargs)
# wait, but break if we are cancelled
self.finished.wait(self.interval)
if self.finished.is_set():
return
if not self.run_first:
# if we are to run the function AFTER waiting for the first time
self.function(*self.args, **self.kwargs)
class CountedEvent(object):
def __init__(self, value=0, max=None, name=None):

View file

@ -24,7 +24,7 @@ from octoprint.settings import settings, default_settings
from octoprint.events import eventManager, Events
from octoprint.filemanager import valid_file_type
from octoprint.filemanager.destinations import FileDestinations
from octoprint.util import get_exception_string, sanitize_ascii, filter_non_ascii, CountedEvent
from octoprint.util import get_exception_string, sanitize_ascii, filter_non_ascii, CountedEvent, RepeatedTimer
from octoprint.util.virtual import VirtualPrinter
try:
@ -165,8 +165,8 @@ class MachineCom(object):
self._clear_to_send = CountedEvent(max=10, name="comm.clear_to_send")
self._send_queue = TypedQueue()
self._sd_status_timer = None
self._temperature_timer = None
self._sd_status_timer = None
# hooks
self._pluginManager = octoprint.plugin.plugin_manager()
@ -510,7 +510,9 @@ class MachineCom(object):
self._currentFile.setFilepos(0)
self.sendCommand("M24")
self._poll_sd_status()
self._sd_status_timer = RepeatedTimer(get_interval("sdStatus"), self._poll_sd_status, run_first=True)
self._sd_status_timer.start()
else:
line = self._getNext()
if line is not None:
@ -1130,10 +1132,6 @@ class MachineCom(object):
if self.isOperational() and not self.isStreaming() and not self._blocking_command and not self._heating:
self.sendCommand("M105", cmd_type="temperature_poll")
interval = get_interval("temperature")
self._temperature_timer = threading.Timer(interval, self._poll_temperature)
self._temperature_timer.start()
def _poll_sd_status(self):
"""
Polls the sd printing status after the sd status timeout, re-enqueues itself.
@ -1145,12 +1143,9 @@ class MachineCom(object):
if self.isOperational() and self.isSdPrinting() and not self._blocking_command and not self._heating:
self.sendCommand("M27", cmd_type="sd_status_poll")
interval = get_interval("sdStatus")
self._sd_status_timer = threading.Timer(interval, self._poll_sd_status)
self._sd_status_timer.start()
def _onConnected(self):
self._poll_temperature()
self._temperature_timer = RepeatedTimer(get_interval("temperature"), self._poll_temperature, run_first=True)
self._temperature_timer.start()
self._changeState(self.STATE_OPERATIONAL)