Now using watchdog to monitor a "watchdog" folder for gcode or stl files being added

Use this to define a folder on your system from which to automatically import/move added files into OctoPrint.

Also now monitoring the uploads folder so that if files are removed externally during runtime, the metadata.yaml will be cleaned up.
This commit is contained in:
Gina Häußge 2014-05-16 11:36:23 +02:00
parent 030ffe6dce
commit 4739c71ee0
3 changed files with 86 additions and 3 deletions

View file

@ -10,6 +10,7 @@ from sockjs.tornado import SockJSRouter
from flask import Flask, render_template, send_from_directory, make_response
from flask.ext.login import LoginManager
from flask.ext.principal import Principal, Permission, RoleNeed, identity_loaded, UserNeed
from watchdog.observers import Observer
import os
import logging
@ -33,7 +34,7 @@ user_permission = Permission(RoleNeed("user"))
# only import the octoprint stuff down here, as it might depend on things defined above to be initialized already
from octoprint.server.util import LargeResponseHandler, ReverseProxied, restricted_access, PrinterStateConnection, admin_validator, \
UrlForwardHandler, user_validator
UrlForwardHandler, user_validator, GcodeWatchdogHandler, UploadCleanupWatchdogHandler
from octoprint.printer import Printer, getConnectionOptions
from octoprint.settings import settings
import octoprint.gcodefiles as gcodefiles
@ -220,6 +221,13 @@ class Server():
connectionOptions = getConnectionOptions()
if port in connectionOptions["ports"]:
printer.connect(port, baudrate)
# start up watchdogs
observer = Observer()
observer.schedule(GcodeWatchdogHandler(gcodeManager, printer), settings().getBaseFolder("watchdog"))
observer.schedule(UploadCleanupWatchdogHandler(gcodeManager), settings().getBaseFolder("uploads"))
observer.start()
try:
IOLoop.instance().start()
except KeyboardInterrupt:
@ -227,6 +235,9 @@ class Server():
except:
logger.fatal("Now that is embarrassing... Something really really went wrong here. Please report this including the stacktrace below in OctoPrint's bugtracker. Thanks!")
logger.exception("Stacktrace follows:")
finally:
observer.stop()
observer.join()
def _createSocketConnection(self, session):
global printer, gcodeManager, userManager, eventManager

View file

@ -1,4 +1,6 @@
# coding=utf-8
from octoprint.filemanager.destinations import FileDestinations
__author__ = "Gina Häußge <osd@foosel.net>"
__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
@ -19,13 +21,15 @@ import os
import threading
import logging
from functools import wraps
from watchdog.events import PatternMatchingEventHandler
from octoprint.settings import settings
import octoprint.timelapse
import octoprint.server
from octoprint.users import ApiUser
from octoprint.events import Events
from octoprint import gcodefiles
import octoprint.util as util
def restricted_access(func, apiEnabled=True):
"""
@ -485,3 +489,70 @@ def redirectToTornado(request, target):
redirectUrl += fragment
return redirect(redirectUrl)
class UploadCleanupWatchdogHandler(PatternMatchingEventHandler):
"""
Takes care of automatically deleting metadata entries for files that get deleted from the uploads folder
"""
patterns = map(lambda x: "*.%s" % x, gcodefiles.GCODE_EXTENSIONS)
def __init__(self, gcode_manager):
PatternMatchingEventHandler.__init__(self)
self._gcode_manager = gcode_manager
def on_deleted(self, event):
filename = self._gcode_manager._getBasicFilename(event.src_path)
if not filename:
return
self._gcode_manager.removeFileFromMetadata(filename)
class GcodeWatchdogHandler(PatternMatchingEventHandler):
"""
Takes care of automatically "uploading" files that get added to the watchdog folder.
"""
patterns = map(lambda x: "*.%s" % x, gcodefiles.SUPPORTED_EXTENSIONS)
def __init__(self, gcodeManager, printer):
PatternMatchingEventHandler.__init__(self)
self._gcodeManager = gcodeManager
self._printer = printer
def _upload(self, path):
class WatchdogFileWrapper(object):
def __init__(self, path):
self._path = path
self.filename = os.path.basename(self._path)
def save(self, target):
util.safeRename(self._path, target)
fileWrapper = WatchdogFileWrapper(path)
# determine current job
currentFilename = None
currentSd = None
currentJob = self._printer.getCurrentJob()
if currentJob is not None and "filename" in currentJob.keys() and "sd" in currentJob.keys():
currentFilename = currentJob["filename"]
currentSd = currentJob["sd"]
# determine future filename of file to be uploaded, abort if it can't be uploaded
futureFilename = self._gcodeManager.getFutureFilename(fileWrapper)
if futureFilename is None or (not settings().getBoolean(["cura", "enabled"]) and not gcodefiles.isGcodeFileName(futureFilename)):
return # Invalid file
# prohibit overwriting currently selected file while it's being printed
if futureFilename == currentFilename and not currentSd and self._printer.isPrinting() or self._printer.isPaused():
return # Trying to overwrite file that is currently being printed
self._gcodeManager.addFile(fileWrapper, FileDestinations.LOCAL)
def on_created(self, event):
self._upload(event.src_path)

View file

@ -77,7 +77,8 @@ default_settings = {
"timelapse": None,
"timelapse_tmp": None,
"logs": None,
"virtualSd": None
"virtualSd": None,
"watchdog": None
},
"temperature": {
"profiles":