diff --git a/src/octoprint/filemanager/__init__.py b/src/octoprint/filemanager/__init__.py index 193705fc..55e6b1be 100644 --- a/src/octoprint/filemanager/__init__.py +++ b/src/octoprint/filemanager/__init__.py @@ -9,6 +9,7 @@ import logging import os from octoprint.events import eventManager, Events +from octoprint.plugin import plugin_manager, ProgressPlugin from .destinations import FileDestinations from .analysis import QueueEntry, AnalysisQueue @@ -113,6 +114,8 @@ class FileManager(object): self._slicing_progress_callbacks = [] self._last_slicing_progress = None + self._progress_plugins = plugin_manager().get_implementations(ProgressPlugin) + for storage_type, storage_manager in self._storage_managers.items(): self._determine_analysis_backlog(storage_type, storage_manager) @@ -246,14 +249,25 @@ class FileManager(object): return progress_int = int(_progress * 100) - if self._last_slicing_progress == progress_int: - return - else: + if self._last_slicing_progress != progress_int: self._last_slicing_progress = progress_int + for callback in self._slicing_progress_callbacks: + try: callback.sendSlicingProgress(slicer, source_location, source_path, dest_location, dest_path, progress_int) + except: self._logger.exception("Exception while pushing slicing progress") + + if progress_int: + def call_plugins(slicer, source_location, source_path, dest_location, dest_path, progress): + for name, plugin in self._progress_plugins.items(): + try: + plugin.on_slicing_progress(slicer, source_location, source_path, dest_location, dest_path, progress) + except: + self._logger.exception("Exception while sending slicing progress to plugin %s" % name) + + import threading + thread = threading.Thread(target=call_plugins, args=(slicer, source_location, source_path, dest_location, dest_path, progress_int)) + thread.daemon = False + thread.start() - for callback in self._slicing_progress_callbacks: - try: callback.sendSlicingProgress(slicer, source_location, source_path, dest_location, dest_path, progress_int) - except: self._logger.exception("Exception while pushing slicing progress") def get_busy_files(self): return self._slicing_jobs.keys() diff --git a/src/octoprint/plugin/__init__.py b/src/octoprint/plugin/__init__.py index 402e00e9..d0de0ad9 100644 --- a/src/octoprint/plugin/__init__.py +++ b/src/octoprint/plugin/__init__.py @@ -30,7 +30,8 @@ def plugin_manager(init=False, plugin_folders=None, plugin_types=None, plugin_en BlueprintPlugin, EventHandlerPlugin, SlicerPlugin, - AppPlugin] + AppPlugin, + ProgressPlugin] if plugin_entry_points is None: plugin_entry_points = "octoprint.plugin" if plugin_disabled_list is None: diff --git a/src/octoprint/plugin/types.py b/src/octoprint/plugin/types.py index 2819e560..ba79106e 100644 --- a/src/octoprint/plugin/types.py +++ b/src/octoprint/plugin/types.py @@ -228,6 +228,36 @@ class SlicerPlugin(Plugin): pass +class ProgressPlugin(Plugin): + """ + Via the ``ProgressPlugin`` mixing plugins can let themselves be called upon progress in print jobs or slicing jobs, + limited to minimally 1% steps. + """ + + def on_print_progress(self, storage, path, progress): + """ + Called by OctoPrint on minimally 1% increments during a running print job. + + :param location string: Location of the file + :param path string: Path of the file + :param progress int: Current progress as a value between 0 and 100 + """ + pass + + def on_slicing_progress(self, slicer, source_location, source_path, destination_location, destination_path, progress): + """ + Called by OctoPrint on minimally 1% increments during a running slicing job. + + :param slicer string: Key of the slicer reporting the progress + :param source_location string: Location of the source file + :param source_path string: Path of the source file + :param destination_location string: Location the destination file + :param destination_path string: Path of the destination file + :param progress int: Current progress as a value between 0 and 100 + """ + pass + + class AppPlugin(Plugin): def get_additional_apps(self): return [] diff --git a/src/octoprint/printer/__init__.py b/src/octoprint/printer/__init__.py index 5b8ee750..542c55bd 100644 --- a/src/octoprint/printer/__init__.py +++ b/src/octoprint/printer/__init__.py @@ -16,6 +16,8 @@ from octoprint.events import eventManager, Events from octoprint.filemanager.destinations import FileDestinations +from octoprint.plugin import plugin_manager, ProgressPlugin + def getConnectionOptions(): """ Retrieves the available ports, baudrates, prefered port and baudrate for connecting to the printer. @@ -80,7 +82,10 @@ class Printer(): # callbacks self._callbacks = [] + + # progress plugins self._lastProgressReport = None + self._progressPlugins = plugin_manager().get_implementations(ProgressPlugin) self._stateMonitor = StateMonitor( ratelimit=0.5, @@ -159,6 +164,26 @@ class Printer(): self._selectedFile["filesize"], self._selectedFile["sd"]) + #~~ progress plugin reporting + + def _reportPrintProgressToPlugins(self, progress): + if not progress or not self._selectedFile or not "sd" in self._selectedFile or not "filename" in self._selectedFile: + return + + storage = "sdcard" if self._selectedFile["sd"] else "local" + filename = self._selectedFile["filename"] + + def call_plugins(storage, filename, progress): + for name, plugin in self._progressPlugins.items(): + try: + plugin.on_print_progress(storage, filename, progress) + except: + self._logger.exception("Exception while sending print progress to plugin %s" % name) + + thread = threading.Thread(target=call_plugins, args=(storage, filename, progress)) + thread.daemon = False + thread.start() + #~~ printer commands def connect(self, port=None, baudrate=None, profile=None): @@ -285,6 +310,7 @@ class Printer(): return self._timeEstimationData = TimeEstimationHelper() + self._lastProgressReport = None self._setCurrentZ(None) self._comm.startPrint() @@ -377,6 +403,13 @@ class Printer(): "printTimeLeft": int(self._printTimeLeft) if self._printTimeLeft is not None else None }) + if progress: + progress_int = int(progress * 100) + if self._lastProgressReport != progress_int: + self._lastProgressReport = progress_int + self._reportPrintProgressToPlugins(progress_int) + + def _addTemperatureData(self, temp, bedTemp): currentTimeUtc = int(time.time())