diff --git a/octoprint/printer.py b/octoprint/printer.py index 4bac804..de14b6d 100644 --- a/octoprint/printer.py +++ b/octoprint/printer.py @@ -20,8 +20,8 @@ def getConnectionOptions(): return { "ports": comm.serialList(), "baudrates": comm.baudrateList(), - "portPreference": settings().get("serial", "port"), - "baudratePreference": settings().getInt("serial", "baudrate") + "portPreference": settings().get(["serial", "port"]), + "baudratePreference": settings().getInt(["serial", "baudrate"]) } class Printer(): diff --git a/octoprint/server.py b/octoprint/server.py index 3c0f07e..6c38e67 100644 --- a/octoprint/server.py +++ b/octoprint/server.py @@ -29,9 +29,9 @@ printer = Printer(gcodeManager) def index(): return render_template( "index.html", - webcamStream=settings().get("webcam", "stream"), - enableTimelapse=(settings().get("webcam", "snapshot") is not None and settings().get("webcam", "ffmpeg") is not None), - enableGCodeVisualizer=settings().get("feature", "gCodeVisualizer") + webcamStream=settings().get(["webcam", "stream"]), + enableTimelapse=(settings().get(["webcam", "snapshot"]) is not None and settings().get(["webcam", "ffmpeg"]) is not None), + enableGCodeVisualizer=settings().get(["feature", "gCodeVisualizer"]) ) #~~ Printer state @@ -111,13 +111,13 @@ def connectionOptions(): def connect(): port = None baudrate = None - if request.values.has_key("port"): + if "port" in request.values.keys(): port = request.values["port"] - if request.values.has_key("baudrate"): + if "baudrate" in request.values.keys(): baudrate = request.values["baudrate"] - if request.values.has_key("save"): - settings().set("serial", "port", port) - settings().set("serial", "baudrate", baudrate) + if "save" in request.values.keys(): + settings().set(["serial", "port"], port) + settings().setInt(["serial", "baudrate"], baudrate) settings().save() printer.connect(port=port, baudrate=baudrate) return jsonify(state="Connecting") @@ -181,21 +181,22 @@ def setTargetTemperature(): @app.route(BASEURL + "control/jog", methods=["POST"]) def jog(): if not printer.isOperational() or printer.isPrinting(): - # do not jog when a print job is running or we don"t have a connection + # do not jog when a print job is running or we don't have a connection return jsonify(SUCCESS) + (movementSpeedX, movementSpeedY, movementSpeedZ, movementSpeedE) = settings().get(["printerParameters", "movementSpeed", ["x", "y", "z", "e"]]) if "x" in request.values.keys(): # jog x x = request.values["x"] - printer.commands(["G91", "G1 X" + x + " F3000", "G90"]) + printer.commands(["G91", "G1 X%s F%d" % (x, movementSpeedX), "G90"]) if "y" in request.values.keys(): # jog y y = request.values["y"] - printer.commands(["G91", "G1 Y" + y + " F3000", "G90"]) + printer.commands(["G91", "G1 Y%s F%d" % (y, movementSpeedY), "G90"]) if "z" in request.values.keys(): # jog z z = request.values["z"] - printer.commands(["G91", "G1 Z" + z + " F200", "G90"]) + printer.commands(["G91", "G1 Z%s F%d" % (z, movementSpeedZ), "G90"]) if "homeXY" in request.values.keys(): # home x/y printer.command("G28 X0 Y0") @@ -205,7 +206,7 @@ def jog(): if "extrude" in request.values.keys(): # extrude/retract length = request.values["extrude"] - printer.commands(["G91", "G1 E" + length + " F300", "G90"]) + printer.commands(["G91", "G1 E%s F%d" % (length, movementSpeedE), "G90"]) return jsonify(SUCCESS) @@ -227,7 +228,7 @@ def speed(): @app.route(BASEURL + "control/custom", methods=["GET"]) def getCustomControls(): - customControls = settings().getObject("controls") + customControls = settings().get(["controls"]) return jsonify(controls=customControls) #~~ GCODE file handling @@ -393,8 +394,8 @@ def initLogging(): def main(): from optparse import OptionParser - defaultHost = settings().get("server", "host") - defaultPort = settings().get("server", "port") + defaultHost = settings().get(["server", "host"]) + defaultPort = settings().get(["server", "port"]) parser = OptionParser(usage="usage: %prog [options]") parser.add_option("-d", "--debug", action="store_true", dest="debug", diff --git a/octoprint/settings.py b/octoprint/settings.py index c3fb1c0..d23994c 100644 --- a/octoprint/settings.py +++ b/octoprint/settings.py @@ -45,9 +45,19 @@ old_default_settings = { default_settings = old_default_settings.copy() default_settings.update({ - "controls": [] + "controls": [], + "printerParameters": { + "movementSpeed": { + "x": 6000, + "y": 6000, + "z": 200, + "e": 300 + } + } }) +valid_boolean_trues = ["true", "yes", "y", "1"] + class Settings(object): def __init__(self): @@ -56,10 +66,10 @@ class Settings(object): self._config = None self._dirty = False - self.init_settings_dir() + self._init_settings_dir() self.load() - def init_settings_dir(self): + def _init_settings_dir(self): self.settings_dir = _resolveSettingsDir(APPNAME) # migration due to rename @@ -67,6 +77,8 @@ class Settings(object): if os.path.exists(old_settings_dir) and os.path.isdir(old_settings_dir) and not os.path.exists(self.settings_dir): os.rename(old_settings_dir, self.settings_dir) + #~~ load and save + def load(self): filename = os.path.join(self.settings_dir, "config.yaml") oldFilename = os.path.join(self.settings_dir, "config.ini") @@ -102,29 +114,48 @@ class Settings(object): self._dirty = False self.load() - def getObject(self, key): - if key not in default_settings.keys(): + #~~ getter + + def get(self, path): + if len(path) == 0: return None - if key in self._config.keys(): - return self._config[key] + config = self._config + defaults = default_settings - return default_settings[key] + while len(path) > 1: + key = path.pop(0) + if key in config.keys() and key in defaults.keys(): + config = config[key] + defaults = defaults[key] + elif key in defaults.keys(): + config = {} + defaults = defaults[key] + else: + return None - def get(self, section, key): - if section not in default_settings.keys(): - return None + k = path.pop(0) + if not isinstance(k, (list, tuple)): + keys = [k] + else: + keys = k - if self._config.has_key(section) and self._config[section].has_key(key): - return self._config[section][key] + results = [] + for key in keys: + if key in config.keys(): + results.append(config[key]) + elif key in defaults: + results.append(defaults[key]) + else: + results.append(None) - if default_settings.has_key(section) and default_settings[section].has_key(key): - return default_settings[section][key] + if not isinstance(k, (list, tuple)): + return results.pop() + else: + return results - return None - - def getInt(self, section, key): - value = self.get(section, key) + def getInt(self, path): + value = self.get(path) if value is None: return None @@ -133,19 +164,19 @@ class Settings(object): except ValueError: return None - def getBoolean(self, section, key): - value = self.get(section, key) + def getBoolean(self, path): + value = self.get(path) if value is None: return None if isinstance(value, bool): return value - return value.lower() in ["true", "yes", "y", "1"] + return value.lower() in valid_boolean_trues def getBaseFolder(self, type): if type not in old_default_settings["folder"].keys(): return None - folder = self.get("folder", type) + folder = self.get(["folder", type]) if folder is None: folder = os.path.join(self.settings_dir, type.replace("_", os.path.sep)) @@ -154,25 +185,49 @@ class Settings(object): return folder - def set(self, section, key, value): - if section not in default_settings.keys(): + #~~ setter + + def set(self, path, value): + if len(path) == 0: return - if self._config.has_key(section): - sectionConfig = self._config[section] + config = self._config + defaults = default_settings + + while len(path) > 1: + key = path.pop(0) + if key in config.keys(): + config = config[key] + elif key in defaults.keys(): + config[key] = {} + config = config[key] + else: + return + + key = path.pop(0) + config[key] = value + self._dirty = True + + def setInt(self, path, value): + if value is None: + return + + try: + intValue = int(value) + except ValueError: + return + + self.set(path, intValue) + + def setBoolean(self, path, value): + if value is None: + return + elif isinstance(value, bool): + self.set(path, value) + elif value.lower() in valid_boolean_trues: + self.set(path, True) else: - sectionConfig = {} - - sectionConfig[key] = value - self._config[section] = sectionConfig - self._dirty = True - - def setObject(self, key, value): - if key not in default_settings.keys(): - return - - self._config[key] = value - self._dirty = True + self.set(path, False) def _resolveSettingsDir(applicationName): # taken from http://stackoverflow.com/questions/1084697/how-do-i-store-desktop-application-data-in-a-cross-platform-way-for-python diff --git a/octoprint/timelapse.py b/octoprint/timelapse.py index 048d820..ac9e4f3 100644 --- a/octoprint/timelapse.py +++ b/octoprint/timelapse.py @@ -31,7 +31,7 @@ class Timelapse(object): self._captureDir = settings().getBaseFolder("timelapse_tmp") self._movieDir = settings().getBaseFolder("timelapse") - self._snapshotUrl = settings().get("webcam", "snapshot") + self._snapshotUrl = settings().get(["webcam", "snapshot"]) self._renderThread = None self._captureMutex = threading.Lock() @@ -79,8 +79,8 @@ class Timelapse(object): urllib.urlretrieve(self._snapshotUrl, filename) def _createMovie(self): - ffmpeg = settings().get("webcam", "ffmpeg") - bitrate = settings().get("webcam", "bitrate") + ffmpeg = settings().get(["webcam", "ffmpeg"]) + bitrate = settings().get(["webcam", "bitrate"]) if ffmpeg is None or bitrate is None: return diff --git a/octoprint/util/comm.py b/octoprint/util/comm.py index c842c31..dd257c9 100644 --- a/octoprint/util/comm.py +++ b/octoprint/util/comm.py @@ -38,7 +38,7 @@ def serialList(): except: pass baselist = baselist + glob.glob("/dev/ttyUSB*") + glob.glob("/dev/ttyACM*") + glob.glob("/dev/tty.usb*") + glob.glob("/dev/cu.*") + glob.glob("/dev/rfcomm*") - prev = settings().get("serial", "port") + prev = settings().get(["serial", "port"]) if prev in baselist: baselist.remove(prev) baselist.insert(0, prev) @@ -48,7 +48,7 @@ def serialList(): def baudrateList(): ret = [250000, 230400, 115200, 57600, 38400, 19200, 9600] - prev = settings().getInt("serial", "baudrate") + prev = settings().getInt(["serial", "baudrate"]) if prev in ret: ret.remove(prev) ret.insert(0, prev) @@ -144,9 +144,9 @@ class MachineCom(object): def __init__(self, port = None, baudrate = None, callbackObject = None): if port == None: - port = settings().get("serial", "port") + port = settings().get(["serial", "port"]) if baudrate == None: - settingsBaudrate = settings().getInt("serial", "baudrate") + settingsBaudrate = settings().getInt(["serial", "baudrate"]) if settingsBaudrate is None: baudrate = 0 else: