diff --git a/src/octoprint/printer/standard.py b/src/octoprint/printer/standard.py index 6912e1f4..a301e117 100644 --- a/src/octoprint/printer/standard.py +++ b/src/octoprint/printer/standard.py @@ -62,10 +62,6 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback): self._currentZ = None - self._progress = None - self._printTime = None - self._printTimeLeft = None - self._printAfterSelect = False self._posAfterSelect = None @@ -93,7 +89,8 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback): on_update=self._sendCurrentDataCallbacks, on_add_temperature=self._sendAddTemperatureCallbacks, on_add_log=self._sendAddLogCallbacks, - on_add_message=self._sendAddMessageCallbacks + on_add_message=self._sendAddMessageCallbacks, + on_get_progress=self._updateProgressDataCallback ) self._stateMonitor.reset( state={"text": self.get_state_string(), "flags": self._getStateFlags()}, @@ -597,7 +594,24 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback): return result - def _setProgressData(self, progress, filepos, printTime, cleanedPrintTime): + def _setProgressData(self, completion=None, filepos=None, printTime=None, printTimeLeft=None): + self._stateMonitor.set_progress(dict(completion=int(completion * 100) if completion is not None else None, + filepos=filepos, + printTime=int(printTime) if printTime is not None else None, + printTimeLeft=int(printTimeLeft) if printTimeLeft is not None else None)) + + def _updateProgressDataCallback(self): + if self._comm is None: + progress = None + filepos = None + printTime = None + cleanedPrintTime = None + else: + progress = self._comm.getPrintProgress() + filepos = self._comm.getPrintFilepos() + printTime = self._comm.getPrintTime() + cleanedPrintTime = self._comm.getCleanedPrintTime() + estimatedTotalPrintTime = self._estimateTotalPrintTime(progress, cleanedPrintTime) totalPrintTime = estimatedTotalPrintTime @@ -613,16 +627,7 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback): sub_progress = 1.0 totalPrintTime = (1 - sub_progress) * statisticalTotalPrintTime + sub_progress * estimatedTotalPrintTime - self._progress = progress - self._printTime = printTime - self._printTimeLeft = totalPrintTime - cleanedPrintTime if (totalPrintTime is not None and cleanedPrintTime is not None) else None - - self._stateMonitor.set_progress({ - "completion": self._progress * 100 if self._progress is not None else None, - "filepos": filepos, - "printTime": int(self._printTime) if self._printTime is not None else None, - "printTimeLeft": int(self._printTimeLeft) if self._printTimeLeft is not None else None - }) + printTimeLeft = totalPrintTime - cleanedPrintTime if (totalPrintTime is not None and cleanedPrintTime is not None) else None if progress: progress_int = int(progress * 100) @@ -630,6 +635,10 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback): self._lastProgressReport = progress_int self._reportPrintProgressToPlugins(progress_int) + return dict(completion=progress * 100 if progress is not None else None, + filepos=filepos, + printTime=int(printTime) if printTime is not None else None, + printTimeLeft=int(printTimeLeft) if printTimeLeft is not None else None) def _addTemperatureData(self, temp, bedTemp): currentTimeUtc = int(time.time()) @@ -808,7 +817,7 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback): Triggers storage of new values for printTime, printTimeLeft and the current progress. """ - self._setProgressData(self._comm.getPrintProgress(), self._comm.getPrintFilepos(), self._comm.getPrintTime(), self._comm.getCleanedPrintTime()) + self._stateMonitor.trigger_progress_update() def on_comm_z_change(self, newZ): """ @@ -874,12 +883,13 @@ class Printer(PrinterInterface, comm.MachineComPrintCallback): self._logger.exception("Error while trying to persist print recovery data") class StateMonitor(object): - def __init__(self, interval=0.5, on_update=None, on_add_temperature=None, on_add_log=None, on_add_message=None): + def __init__(self, interval=0.5, on_update=None, on_add_temperature=None, on_add_log=None, on_add_message=None, on_get_progress=None): self._interval = interval self._update_callback = on_update self._on_add_temperature = on_add_temperature self._on_add_log = on_add_log self._on_add_message = on_add_message + self._on_get_progress = on_get_progress self._state = None self._job_data = None @@ -888,16 +898,24 @@ class StateMonitor(object): self._current_z = None self._progress = None + self._progress_dirty = False + self._offsets = {} self._change_event = threading.Event() self._state_lock = threading.Lock() + self._progress_lock = threading.Lock() self._last_update = time.time() self._worker = threading.Thread(target=self._work) self._worker.daemon = True self._worker.start() + def _get_current_progress(self): + if callable(self._on_get_progress): + return self._on_get_progress() + return self._progress + def reset(self, state=None, job_data=None, progress=None, current_z=None): self.set_state(state) self.set_job_data(job_data) @@ -929,9 +947,16 @@ class StateMonitor(object): self._job_data = job_data self._change_event.set() + def trigger_progress_update(self): + with self._progress_lock: + self._progress_dirty = True + self._change_event.set() + def set_progress(self, progress): - self._progress = progress - self._change_event.set() + with self._progress_lock: + self._progress_dirty = False + self._progress = progress + self._change_event.set() def set_temp_offsets(self, offsets): self._offsets = offsets @@ -941,19 +966,24 @@ class StateMonitor(object): while True: self._change_event.wait() - with self._state_lock: - now = time.time() - delta = now - self._last_update - additional_wait_time = self._interval - delta - if additional_wait_time > 0: - time.sleep(additional_wait_time) + now = time.time() + delta = now - self._last_update + additional_wait_time = self._interval - delta + if additional_wait_time > 0: + time.sleep(additional_wait_time) + with self._state_lock: data = self.get_current_data() self._update_callback(data) self._last_update = time.time() self._change_event.clear() def get_current_data(self): + with self._progress_lock: + if self._progress_dirty: + self._progress = self._get_current_progress() + self._progress_dirty = False + return { "state": self._state, "job": self._job_data,