diff --git a/src/octoprint/filemanager/__init__.py b/src/octoprint/filemanager/__init__.py index 753e8112..b541eaa7 100644 --- a/src/octoprint/filemanager/__init__.py +++ b/src/octoprint/filemanager/__init__.py @@ -94,7 +94,7 @@ class NoSuchStorage(Exception): class FileManager(object): - def __init__(self, analysis_queue, slicing_manager, initial_storage_managers=None): + def __init__(self, analysis_queue, slicing_manager, printer_profile_manager, initial_storage_managers=None): self._logger = logging.getLogger(__name__) self._analysis_queue = analysis_queue self._analysis_queue.register_finish_callback(self._on_analysis_finished) @@ -104,6 +104,7 @@ class FileManager(object): self._storage_managers.update(initial_storage_managers) self._slicing_manager = slicing_manager + self._printer_profile_manager = printer_profile_manager import threading self._slicing_jobs = dict() @@ -123,10 +124,11 @@ class FileManager(object): def _determine_analysis_backlog(self, storage_type, storage_manager): self._logger.info("Adding backlog items from {storage_type} to analysis queue".format(**locals())) - for entry, path in storage_manager.analysis_backlog: + for entry, path, printer_profile in storage_manager.analysis_backlog: file_type = get_file_type(path)[-1] - queue_entry = QueueEntry(entry, file_type, storage_type, path) + # we'll use the default printer profile for the backlog since we don't know better + queue_entry = QueueEntry(entry, file_type, storage_type, path, self._printer_profile_manager.get_default()) self._analysis_queue.enqueue(queue_entry, high_priority=False) def add_storage(self, storage_type, storage_manager): @@ -153,7 +155,7 @@ class FileManager(object): def slice(self, slicer_name, source_location, source_path, dest_location, dest_path, profile=None, printer_profile_id=None, overrides=None, callback=None, callback_args=None): absolute_source_path = self.get_absolute_path(source_location, source_path) - def stlProcessed(source_location, source_path, tmp_path, dest_location, dest_path, start_time, callback, callback_args, _error=None, _cancelled=False): + def stlProcessed(source_location, source_path, tmp_path, dest_location, dest_path, start_time, printer_profile_id, callback, callback_args, _error=None, _cancelled=False): try: if _error: eventManager().fire(Events.SLICING_FAILED, {"stl": source_path, "gcode": dest_path, "reason": _error}) @@ -179,7 +181,9 @@ class FileManager(object): links = [("model", dict(name=source_path))] _, stl_name = self.split_path(source_location, source_path) file_obj = Wrapper(stl_name, temp_path, hash) - self.add_file(dest_location, dest_path, file_obj, links=links, allow_overwrite=True) + + printer_profile = self._printer_profile_manager.get(printer_profile_id) + self.add_file(dest_location, dest_path, file_obj, links=links, allow_overwrite=True, printer_profile=printer_profile) end_time = time.time() eventManager().fire(Events.SLICING_DONE, {"stl": source_path, "gcode": dest_path, "time": end_time - start_time}) @@ -222,7 +226,7 @@ class FileManager(object): self._slicing_jobs[dest_job_key] = self._slicing_jobs[source_job_key] = (slicer_name, absolute_source_path, temp_path) - args = (source_location, source_path, temp_path, dest_location, dest_path, start_time, callback, callback_args) + args = (source_location, source_path, temp_path, dest_location, dest_path, start_time, printer_profile_id, callback, callback_args) return self._slicing_manager.slice( slicer_name, absolute_source_path, @@ -266,13 +270,16 @@ class FileManager(object): result[dst] = self._storage_managers[dst].list_files(path=path, filter=filter, recursive=recursive) return result - def add_file(self, destination, path, file_object, links=None, allow_overwrite=False): - file_path = self._storage(destination).add_file(path, file_object, links=links, allow_overwrite=allow_overwrite) + def add_file(self, destination, path, file_object, links=None, allow_overwrite=False, printer_profile=None): + if printer_profile is None: + printer_profile = self._printer_profile_manager.get_current_or_default() + + file_path = self._storage(destination).add_file(path, file_object, links=links, printer_profile=printer_profile, allow_overwrite=allow_overwrite) absolute_path = self._storage(destination).get_absolute_path(file_path) file_type = get_file_type(absolute_path) if file_type: - queue_entry = QueueEntry(file_path, file_type[-1], destination, absolute_path) + queue_entry = QueueEntry(file_path, file_type[-1], destination, absolute_path, printer_profile) self._analysis_queue.enqueue(queue_entry, high_priority=True) eventManager().fire(Events.UPDATED_FILES, dict(type="printables")) diff --git a/src/octoprint/filemanager/analysis.py b/src/octoprint/filemanager/analysis.py index 638325c9..f746c228 100644 --- a/src/octoprint/filemanager/analysis.py +++ b/src/octoprint/filemanager/analysis.py @@ -17,7 +17,7 @@ from octoprint.events import Events, eventManager import octoprint.util.gcodeInterpreter as gcodeInterpreter -class QueueEntry(collections.namedtuple("QueueEntry", "path, type, location, absolute_path")): +class QueueEntry(collections.namedtuple("QueueEntry", "path, type, location, absolute_path, printer_profile")): def __str__(self): return "{location}:{path}".format(location=self.location, path=self.path) @@ -145,7 +145,7 @@ class GcodeAnalysisQueue(AbstractAnalysisQueue): def _do_analysis(self): try: self._gcode = gcodeInterpreter.gcode() - self._gcode.load(self._current.absolute_path) + self._gcode.load(self._current.absolute_path, self._current.printer_profile) result = dict() if self._gcode.totalMoveTimeMinute: diff --git a/src/octoprint/filemanager/storage.py b/src/octoprint/filemanager/storage.py index ee796e52..b078034f 100644 --- a/src/octoprint/filemanager/storage.py +++ b/src/octoprint/filemanager/storage.py @@ -33,7 +33,7 @@ class StorageInterface(object): def remove_folder(self, path, recursive=True): raise NotImplementedError() - def add_file(self, path, file_object, links=None, allow_overwrite=False): + def add_file(self, path, file_object, printer_profile=None, links=None, allow_overwrite=False): raise NotImplementedError() def remove_file(self, path): @@ -111,10 +111,16 @@ class LocalFileStorage(StorageInterface): absolute_path = os.path.join(path, entry) if os.path.isfile(absolute_path): if not entry in metadata or not isinstance(metadata[entry], dict) or not "analysis" in metadata[entry]: - yield entry, absolute_path + printer_profile_rels = self.get_link(absolute_path, "printerprofile") + if printer_profile_rels: + printer_profile_id = printer_profile_rels[0]["id"] + else: + printer_profile_id = None + + yield entry, absolute_path, printer_profile_id elif os.path.isdir(absolute_path): for sub_entry in self._analysis_backlog_generator(absolute_path): - yield self.join_path(entry, sub_entry), os.path.join(absolute_path, sub_entry) + yield self.join_path(entry, sub_entry[0]), sub_entry[1], sub_entry[2] def file_exists(self, path): path, name = self.sanitize(path) @@ -221,13 +227,14 @@ class LocalFileStorage(StorageInterface): import shutil shutil.rmtree(folder_path) - def add_file(self, path, file_object, links=None, allow_overwrite=False): + def add_file(self, path, file_object, printer_profile=None, links=None, allow_overwrite=False): """ Adds the file ``file_object`` as ``path`` :param path: the file's new path, will be sanitized :param file_object: a file object that provides a ``save`` method which will be called with the destination path where the object should then store its contents + :param printer_profile: the printer profile associated with this file (if any) :param links: any links to add with the file :param allow_overwrite: if set to True no error will be raised if the file already exists and the existing file and its metadata will just be silently overwritten @@ -266,8 +273,13 @@ class LocalFileStorage(StorageInterface): self._save_metadata(path, metadata) # process any links that were also provided for adding to the file - if links: - self._add_links(name, path, links) + if not links: + links = [] + + if printer_profile is not None: + links.append(("printerprofile", dict(id=printer_profile["id"], name=printer_profile["name"]))) + + self._add_links(name, path, links) return self.rel_path((path, name)) @@ -322,6 +334,11 @@ class LocalFileStorage(StorageInterface): else: return None + def get_link(self, path, rel): + path, name = self.sanitize(path) + return self._get_links(name, path, rel) + + def add_link(self, path, rel, data): """ Adds a link of relation ``rel`` to file ``path`` with the given ``data``. @@ -510,6 +527,22 @@ class LocalFileStorage(StorageInterface): except IndexError: pass + def _get_links(self, name, path, searched_rel): + metadata = self._get_metadata(path) + result = [] + + if not name in metadata: + return result + + if not "links" in metadata[name]: + return result + + for data in metadata[name]["links"]: + if not "rel" in data or not data["rel"] == searched_rel: + continue + result.append(data) + return result + def _add_links(self, name, path, links): file_type = octoprint.filemanager.get_file_type(name) if file_type: diff --git a/src/octoprint/plugins/cura/profile.py b/src/octoprint/plugins/cura/profile.py index 9f96a27d..199846de 100644 --- a/src/octoprint/plugins/cura/profile.py +++ b/src/octoprint/plugins/cura/profile.py @@ -642,7 +642,7 @@ class Profile(object): return int(value * 1000) def get_gcode_template(self, key): - extruder_count = s.globalGetInt(["printerParameters", "numExtruders"]) + extruder_count = self.get_int("extruder_amount") if key in self._profile: gcode = self._profile[key] @@ -654,14 +654,6 @@ class Profile(object): else: return gcode - def get_machine_extruder_offset(self, extruder, axis): - extruder_offsets = s.globalGet(["printerParameters", "extruderOffsets"]) - if extruder >= len(extruder_offsets): - return 0.0 - if axis.lower() not in ("x", "y"): - return 0.0 - return extruder_offsets[extruder][axis.lower()] - def get_profile_string(self): import base64 import zlib @@ -712,7 +704,7 @@ class Profile(object): return pre + str(f) def get_gcode(self, key): - extruder_count = s.globalGetInt(["printerParameters", "numExtruders"]) + extruder_count = self.get_int("extruder_amount") prefix = "" postfix = "" @@ -796,7 +788,7 @@ class Profile(object): return int(math.ceil(solid_thickness / (layer_height - 0.0001))) def calculate_minimal_extruder_count(self): - extruder_count = s.globalGetInt(["printerParameters", "numExtruders"]) + extruder_count = self.get("extruder_amount") if extruder_count < 2: return 1 if self.get("support") == SupportLocationTypes.NONE: @@ -810,7 +802,7 @@ class Profile(object): edge_width, line_count = self.calculate_edge_width_and_line_count() solid_layer_count = self.calculate_solid_layer_count() - extruder_count = s.globalGetInt(["printerParameters", "numExtruders"]) + extruder_count = self.get_int("extruder_amount") minimal_extruder_count = self.calculate_minimal_extruder_count() settings = { @@ -868,7 +860,7 @@ class Profile(object): for extruder in range(1, extruder_count): for axis in ("x", "y"): - settings["extruderOffset[{extruder}].{axis}".format(extruder=extruder, axis=axis.upper())] = self.get_machine_extruder_offset(extruder, axis) + settings["extruderOffset[{extruder}].{axis}".format(extruder=extruder, axis=axis.upper())] = self.get("extruder_offset_{axis}{extruder}".format(extruder=extruder, axis=axis.lower())) fanFullHeight = self.get_microns("fan_full_height") settings["fanFullOnLayerNr"] = (fanFullHeight - settings["initialLayerThickness"] - 1) / settings["layerThickness"] + 1 diff --git a/src/octoprint/printer/__init__.py b/src/octoprint/printer/__init__.py index 8c93e66b..0dff1af4 100644 --- a/src/octoprint/printer/__init__.py +++ b/src/octoprint/printer/__init__.py @@ -197,15 +197,17 @@ class Printer(): self._comm.sendCommand(command) def jog(self, axis, amount): - movementSpeed = settings().get(["printerParameters", "movementSpeed", ["x", "y", "z"]], asdict=True) - self.commands(["G91", "G1 %s%.4f F%d" % (axis.upper(), amount, movementSpeed[axis]), "G90"]) + printer_profile = self._printerProfileManager.get_current_or_default() + movement_speed = printer_profile["axes"][axis]["speed"] + self.commands(["G91", "G1 %s%.4f F%d" % (axis.upper(), amount, movement_speed), "G90"]) def home(self, axes): self.commands(["G91", "G28 %s" % " ".join(map(lambda x: "%s0" % x.upper(), axes)), "G90"]) def extrude(self, amount): - extrusionSpeed = settings().get(["printerParameters", "movementSpeed", "e"]) - self.commands(["G91", "G1 E%s F%d" % (amount, extrusionSpeed), "G90"]) + printer_profile = self._printerProfileManager.get_current_or_default() + extrusion_speed = printer_profile["axes"]["e"]["speed"] + self.commands(["G91", "G1 E%s F%d" % (amount, extrusion_speed), "G90"]) def changeTool(self, tool): try: @@ -216,7 +218,9 @@ class Printer(): def setTemperature(self, type, value): if type.startswith("tool"): - if settings().getInt(["printerParameters", "numExtruders"]) > 1: + printer_profile = self._printerProfileManager.get_current_or_default() + extruder_count = printer_profile["extruder"]["count"] + if extruder_count > 1: try: toolNum = int(type[len("tool"):]) self.command("M104 T%d S%f" % (toolNum, value)) @@ -301,9 +305,12 @@ class Printer(): self._comm.cancelPrint() if disableMotorsAndHeater: + printer_profile = self._printerProfileManager.get_current_or_default() + extruder_count = printer_profile["extruder"]["count"] + # disable motors, switch off hotends, bed and fan commands = ["M84"] - commands.extend(map(lambda x: "M104 T%d S0" % x, range(settings().getInt(["printerParameters", "numExtruders"])))) + commands.extend(map(lambda x: "M104 T%d S0" % x, range(extruder_count))) commands.extend(["M140 S0", "M106 S0"]) self.commands(commands) diff --git a/src/octoprint/server/__init__.py b/src/octoprint/server/__init__.py index ba9f271f..7f3c13de 100644 --- a/src/octoprint/server/__init__.py +++ b/src/octoprint/server/__init__.py @@ -235,7 +235,7 @@ class Server(): slicingManager = octoprint.slicing.SlicingManager(settings().getBaseFolder("slicingProfiles"), printerProfileManager) storage_managers = dict() storage_managers[octoprint.filemanager.FileDestinations.LOCAL] = octoprint.filemanager.storage.LocalFileStorage(settings().getBaseFolder("uploads")) - fileManager = octoprint.filemanager.FileManager(analysisQueue, slicingManager, initial_storage_managers=storage_managers) + fileManager = octoprint.filemanager.FileManager(analysisQueue, slicingManager, printerProfileManager, initial_storage_managers=storage_managers) printer = Printer(fileManager, analysisQueue, printerProfileManager) appSessionManager = util.flask.AppSessionManager() diff --git a/src/octoprint/server/api/settings.py b/src/octoprint/server/api/settings.py index c0efc0dc..b8283d51 100644 --- a/src/octoprint/server/api/settings.py +++ b/src/octoprint/server/api/settings.py @@ -27,9 +27,6 @@ import octoprint.plugin def getSettings(): s = settings() - [movementSpeedX, movementSpeedY, movementSpeedZ, movementSpeedE] \ - = s.get(["printerParameters", "movementSpeed", ["x", "y", "z", "e"]]) - connectionOptions = getConnectionOptions() data = { @@ -43,14 +40,6 @@ def getSettings(): "color": s.get(["appearance", "color"]) }, "printer": { - "movementSpeedX": movementSpeedX, - "movementSpeedY": movementSpeedY, - "movementSpeedZ": movementSpeedZ, - "movementSpeedE": movementSpeedE, - "invertAxes": s.get(["printerParameters", "invertAxes"]), - "numExtruders": s.get(["printerParameters", "numExtruders"]), - "extruderOffsets": s.get(["printerParameters", "extruderOffsets"]), - "bedDimensions": s.get(["printerParameters", "bedDimensions"]), "defaultExtrusionLength": s.getInt(["printerParameters", "defaultExtrusionLength"]) }, "webcam": { @@ -140,14 +129,6 @@ def setSettings(): if "color" in data["appearance"].keys(): s.set(["appearance", "color"], data["appearance"]["color"]) if "printer" in data.keys(): - if "movementSpeedX" in data["printer"].keys(): s.setInt(["printerParameters", "movementSpeed", "x"], data["printer"]["movementSpeedX"]) - if "movementSpeedY" in data["printer"].keys(): s.setInt(["printerParameters", "movementSpeed", "y"], data["printer"]["movementSpeedY"]) - if "movementSpeedZ" in data["printer"].keys(): s.setInt(["printerParameters", "movementSpeed", "z"], data["printer"]["movementSpeedZ"]) - if "movementSpeedE" in data["printer"].keys(): s.setInt(["printerParameters", "movementSpeed", "e"], data["printer"]["movementSpeedE"]) - if "invertAxes" in data["printer"].keys(): s.set(["printerParameters", "invertAxes"], data["printer"]["invertAxes"]) - if "numExtruders" in data["printer"].keys(): s.setInt(["printerParameters", "numExtruders"], data["printer"]["numExtruders"]) - if "extruderOffsets" in data["printer"].keys(): s.set(["printerParameters", "extruderOffsets"], data["printer"]["extruderOffsets"]) - if "bedDimensions" in data["printer"].keys(): s.set(["printerParameters", "bedDimensions"], data["printer"]["bedDimensions"]) if "defaultExtrusionLength" in data["printer"]: s.setInt(["printerParameters", "defaultExtrusionLength"], data["printer"]["defaultExtrusionLength"]) if "webcam" in data.keys(): diff --git a/src/octoprint/static/js/app/viewmodels/control.js b/src/octoprint/static/js/app/viewmodels/control.js index be36a426..654d9dc7 100644 --- a/src/octoprint/static/js/app/viewmodels/control.js +++ b/src/octoprint/static/js/app/viewmodels/control.js @@ -26,10 +26,14 @@ function ControlViewModel(loginStateViewModel, settingsViewModel) { self.feedbackControlLookup = {}; - self.settings.printer_numExtruders.subscribe(function(oldVal, newVal) { + self.settings.printerProfiles.currentProfileData.subscribe(function() { + self._updateExtruderCount(); + self.settings.printerProfiles.currentProfileData().extruder.count.subscribe(self._updateExtruderCount); + }); + self._updateExtruderCount = function() { var tools = []; - var numExtruders = self.settings.printer_numExtruders(); + var numExtruders = self.settings.printerProfiles.currentProfileData().extruder.count(); if (numExtruders > 1) { // multiple extruders for (var extruder = 0; extruder < numExtruders; extruder++) { @@ -45,7 +49,7 @@ function ControlViewModel(loginStateViewModel, settingsViewModel) { } self.tools(tools); - }); + }; self.fromCurrentData = function(data) { self._processStateData(data.state); diff --git a/src/octoprint/static/js/app/viewmodels/settings.js b/src/octoprint/static/js/app/viewmodels/settings.js index 7b7524db..67bfd645 100644 --- a/src/octoprint/static/js/app/viewmodels/settings.js +++ b/src/octoprint/static/js/app/viewmodels/settings.js @@ -46,83 +46,8 @@ function SettingsViewModel(loginStateViewModel, usersViewModel, printerProfilesV } }; - self.printer_movementSpeedX = ko.observable(undefined); - self.printer_movementSpeedY = ko.observable(undefined); - self.printer_movementSpeedZ = ko.observable(undefined); - self.printer_movementSpeedE = ko.observable(undefined); - self.printer_invertAxes = ko.observable(undefined); - self.printer_numExtruders = ko.observable(undefined); self.printer_defaultExtrusionLength = ko.observable(undefined); - self._printer_extruderOffsets = ko.observableArray([]); - self.printer_extruderOffsets = ko.computed({ - read: function() { - var extruderOffsets = self._printer_extruderOffsets(); - var result = []; - for (var i = 0; i < extruderOffsets.length; i++) { - result[i] = { - x: parseFloat(extruderOffsets[i].x()), - y: parseFloat(extruderOffsets[i].y()) - } - } - return result; - }, - write: function(value) { - var result = []; - if (value && Array.isArray(value)) { - for (var i = 0; i < value.length; i++) { - result[i] = { - x: ko.observable(value[i].x), - y: ko.observable(value[i].y) - } - } - } - self._printer_extruderOffsets(result); - }, - owner: self - }); - self.ko_printer_extruderOffsets = ko.computed(function() { - var extruderOffsets = self._printer_extruderOffsets(); - var numExtruders = self.printer_numExtruders(); - if (!numExtruders) { - numExtruders = 1; - } - - if (numExtruders > extruderOffsets.length) { - for (var i = extruderOffsets.length; i < numExtruders; i++) { - extruderOffsets[i] = { - x: ko.observable(0), - y: ko.observable(0) - } - } - self._printer_extruderOffsets(extruderOffsets); - } - - return extruderOffsets.slice(0, numExtruders); - }); - - self.printer_bedDimensionX = ko.observable(undefined); - self.printer_bedDimensionY = ko.observable(undefined); - self.printer_bedDimensionR = ko.observable(undefined); - self.printer_bedCircular = ko.observable(undefined); - self.printer_bedDimensions = ko.computed({ - read: function () { - return { - x: parseFloat(self.printer_bedDimensionX()), - y: parseFloat(self.printer_bedDimensionY()), - r: parseFloat(self.printer_bedDimensionR()), - circular: self.printer_bedCircular() - }; - }, - write: function(value) { - self.printer_bedDimensionX(value.x); - self.printer_bedDimensionY(value.y); - self.printer_bedDimensionR(value.r); - self.printer_bedCircular(value.circular); - }, - owner: self - }); - self.webcam_streamUrl = ko.observable(undefined); self.webcam_snapshotUrl = ko.observable(undefined); self.webcam_ffmpegPath = ko.observable(undefined); @@ -186,31 +111,6 @@ function SettingsViewModel(loginStateViewModel, usersViewModel, printerProfilesV self.terminalFilters.remove(filter); }; - self.getPrinterInvertAxis = function(axis) { - return _.contains((self.printer_invertAxes() || []), axis.toLowerCase()); - }; - - self.setPrinterInvertAxis = function(axis, value) { - var currInvert = self.printer_invertAxes() || []; - var currValue = self.getPrinterInvertAxis(axis); - if (value && !currValue) { - currInvert.push(axis.toLowerCase()); - } else if (!value && currValue) { - currInvert = _.without(currInvert, axis.toLowerCase()); - } - self.printer_invertAxes(currInvert); - }; - - self.koInvertAxis = function (axis) { return ko.computed({ - read: function () { return self.getPrinterInvertAxis(axis); }, - write: function (value) { self.setPrinterInvertAxis(axis, value); }, - owner: self - })}; - - self.printer_invertX = self.koInvertAxis('x'); - self.printer_invertY = self.koInvertAxis('y'); - self.printer_invertZ = self.koInvertAxis('z'); - self.onSettingsShown = function() { self.requestData(); }; @@ -241,14 +141,6 @@ function SettingsViewModel(loginStateViewModel, usersViewModel, printerProfilesV self.appearance_name(response.appearance.name); self.appearance_color(response.appearance.color); - self.printer_movementSpeedX(response.printer.movementSpeedX); - self.printer_movementSpeedY(response.printer.movementSpeedY); - self.printer_movementSpeedZ(response.printer.movementSpeedZ); - self.printer_movementSpeedE(response.printer.movementSpeedE); - self.printer_invertAxes(response.printer.invertAxes); - self.printer_numExtruders(response.printer.numExtruders); - self.printer_extruderOffsets(response.printer.extruderOffsets); - self.printer_bedDimensions(response.printer.bedDimensions); self.printer_defaultExtrusionLength(response.printer.defaultExtrusionLength); self.webcam_streamUrl(response.webcam.streamUrl); @@ -311,14 +203,6 @@ function SettingsViewModel(loginStateViewModel, usersViewModel, printerProfilesV "color": self.appearance_color() }, "printer": { - "movementSpeedX": self.printer_movementSpeedX(), - "movementSpeedY": self.printer_movementSpeedY(), - "movementSpeedZ": self.printer_movementSpeedZ(), - "movementSpeedE": self.printer_movementSpeedE(), - "invertAxes": self.printer_invertAxes(), - "numExtruders": self.printer_numExtruders(), - "extruderOffsets": self.printer_extruderOffsets(), - "bedDimensions": self.printer_bedDimensions(), "defaultExtrusionLength": self.printer_defaultExtrusionLength() }, "webcam": { diff --git a/src/octoprint/static/js/app/viewmodels/temperature.js b/src/octoprint/static/js/app/viewmodels/temperature.js index 949001c9..aa4e6327 100644 --- a/src/octoprint/static/js/app/viewmodels/temperature.js +++ b/src/octoprint/static/js/app/viewmodels/temperature.js @@ -40,7 +40,7 @@ function TemperatureViewModel(loginStateViewModel, settingsViewModel) { var tools = self.tools(); // tools - var numExtruders = self.settingsViewModel.printer_numExtruders(); + var numExtruders = self.settingsViewModel.printerProfiles.currentProfileData().extruder.count(); if (numExtruders && numExtruders > 1) { // multiple extruders for (var extruder = 0; extruder < numExtruders; extruder++) { @@ -73,7 +73,10 @@ function TemperatureViewModel(loginStateViewModel, settingsViewModel) { self.heaterOptions(heaterOptions); self.tools(tools); }; - self.settingsViewModel.printer_numExtruders.subscribe(self._numExtrudersUpdated); + self.settingsViewModel.printerProfiles.currentProfileData.subscribe(function() { + self._numExtrudersUpdated(); + self.settingsViewModel.printerProfiles.currentProfileData().extruder.count.subscribe(self._numExtrudersUpdated); + }); self.temperatures = []; self.plotOptions = { diff --git a/src/octoprint/util/gcodeInterpreter.py b/src/octoprint/util/gcodeInterpreter.py index 901e3f80..c886999a 100644 --- a/src/octoprint/util/gcodeInterpreter.py +++ b/src/octoprint/util/gcodeInterpreter.py @@ -31,17 +31,17 @@ class gcode(object): self._abort = False self._filamentDiameter = 0 - def load(self, filename): + def load(self, filename, printer_profile): if os.path.isfile(filename): self.filename = filename self._fileSize = os.stat(filename).st_size with open(filename, "r") as f: - self._load(f) + self._load(f, printer_profile) def abort(self): self._abort = True - def _load(self, gcodeFile): + def _load(self, gcodeFile, printer_profile): filePos = 0 pos = [0.0, 0.0, 0.0] posOffset = [0.0, 0.0, 0.0] @@ -53,8 +53,8 @@ class gcode(object): absoluteE = True scale = 1.0 posAbs = True - feedRateXY = settings().getFloat(["printerParameters", "movementSpeed", "x"]) - offsets = settings().get(["printerParameters", "extruderOffsets"]) + feedRateXY = min(printer_profile["axes"]["x"], printer_profile["axes"]["y"]) + offsets = printer_profile["extruder"]["offsets"] for line in gcodeFile: if self._abort: @@ -198,13 +198,13 @@ class gcode(object): if T > settings().getInt(["gcodeAnalysis", "maxExtruders"]): self._logger.warn("GCODE tried to select tool %d, that looks wrong, ignoring for GCODE analysis" % T) else: - posOffset[0] -= offsets[currentExtruder]["x"] if currentExtruder < len(offsets) else 0 - posOffset[1] -= offsets[currentExtruder]["y"] if currentExtruder < len(offsets) else 0 + posOffset[0] -= offsets[currentExtruder][0] if currentExtruder < len(offsets) else 0 + posOffset[1] -= offsets[currentExtruder][1] if currentExtruder < len(offsets) else 0 currentExtruder = T - posOffset[0] += offsets[currentExtruder]["x"] if currentExtruder < len(offsets) else 0 - posOffset[1] += offsets[currentExtruder]["y"] if currentExtruder < len(offsets) else 0 + posOffset[0] += offsets[currentExtruder][0] if currentExtruder < len(offsets) else 0 + posOffset[1] += offsets[currentExtruder][1] if currentExtruder < len(offsets) else 0 if len(currentE) <= currentExtruder: for i in range(len(currentE), currentExtruder + 1): diff --git a/tests/filemanager/test_filemanager.py b/tests/filemanager/test_filemanager.py index 4201ac23..8681ffb2 100644 --- a/tests/filemanager/test_filemanager.py +++ b/tests/filemanager/test_filemanager.py @@ -16,6 +16,7 @@ class FileManagerTest(unittest.TestCase): def setUp(self): import octoprint.slicing import octoprint.filemanager.storage + import octoprint.printer.profile self.addCleanup(self.cleanUp) @@ -29,13 +30,15 @@ class FileManagerTest(unittest.TestCase): self.slicing_manager = mock.MagicMock(spec=octoprint.slicing.SlicingManager) + self.printer_profile_manager = mock.MagicMock(spec=octoprint.printer.profile.PrinterProfileManager) + self.local_storage = mock.MagicMock(spec=octoprint.filemanager.storage.LocalFileStorage) self.local_storage.analysis_backlog = iter([]) self.storage_managers = dict() self.storage_managers[octoprint.filemanager.FileDestinations.LOCAL] = self.local_storage - self.file_manager = octoprint.filemanager.FileManager(self.analysis_queue, self.slicing_manager, initial_storage_managers=self.storage_managers) + self.file_manager = octoprint.filemanager.FileManager(self.analysis_queue, self.slicing_manager, self.printer_profile_manager, initial_storage_managers=self.storage_managers) def cleanUp(self): self.event_manager_patcher.stop() @@ -46,10 +49,13 @@ class FileManagerTest(unittest.TestCase): self.local_storage.add_file.return_value = ("", "test.file") self.local_storage.get_absolute_path.return_value = "prefix/test.file" + test_profile = dict(id="_default", name="My Default Profile") + self.printer_profile_manager.get_current_or_default.return_value = test_profile + file_path = self.file_manager.add_file(octoprint.filemanager.FileDestinations.LOCAL, "test.file", wrapper) self.assertEquals(("", "test.file"), file_path) - self.local_storage.add_file.assert_called_once_with("test.file", wrapper, allow_overwrite=False, links=None) + self.local_storage.add_file.assert_called_once_with("test.file", wrapper, printer_profile=test_profile, allow_overwrite=False, links=None) self.fire_event.assert_called_once_with(octoprint.filemanager.Events.UPDATED_FILES, dict(type="printables")) def test_remove_file(self): @@ -114,6 +120,11 @@ class FileManagerTest(unittest.TestCase): metadata = dict(hash="aabbccddeeff") self.local_storage.get_metadata.return_value = metadata + # mock printer profile + expected_printer_profile = dict(id="_default", name="My Default Profile") + self.printer_profile_manager.get_current_or_default.return_value = expected_printer_profile + self.printer_profile_manager.get.return_value = None + # mock get_absolute_path method on local storage def get_absolute_path(path): if isinstance(path, tuple): @@ -131,13 +142,13 @@ class FileManagerTest(unittest.TestCase): self.local_storage.split_path.side_effect = split_path # mock add_file method on local storage - def add_file(path, file_obj, links=None, allow_overwrite=False): + def add_file(path, file_obj, printer_profile=None, links=None, allow_overwrite=False): file_obj.save("prefix/" + path) return "", path self.local_storage.add_file.side_effect = add_file # mock slice method on slicing manager - def slice(slicer_name, source_path, dest_path, profile, done_cb, callback_args=None, overrides=None, on_progress=None, on_progress_args=None, on_progress_kwargs=None): + def slice(slicer_name, source_path, dest_path, profile, done_cb, printer_profile_id=None, callback_args=None, overrides=None, on_progress=None, on_progress_args=None, on_progress_kwargs=None): self.assertEquals("some_slicer", slicer_name) self.assertEquals("prefix/source.file", source_path) self.assertEquals("tmp.file", dest_path) @@ -163,7 +174,7 @@ class FileManagerTest(unittest.TestCase): # assert that model links were added expected_links = [("model", dict(name="source.file"))] - self.local_storage.add_file.assert_called_once_with("dest.file", mock.ANY, allow_overwrite=True, links=expected_links) + self.local_storage.add_file.assert_called_once_with("dest.file", mock.ANY, printer_profile=expected_printer_profile, allow_overwrite=True, links=expected_links) # assert that the generated gcode was manipulated as required expected_open_calls = [mock.call("prefix/dest.file", "w"), mock.call("tmp.file", "r")] @@ -203,7 +214,7 @@ class FileManagerTest(unittest.TestCase): self.local_storage.get_absolute_path.side_effect = get_absolute_path # mock slice method on slicing manager - def slice(slicer_name, source_path, dest_path, profile, done_cb, callback_args=None, overrides=None, on_progress=None, on_progress_args=None, on_progress_kwargs=None): + def slice(slicer_name, source_path, dest_path, profile, done_cb, printer_profile_id=None, callback_args=None, overrides=None, on_progress=None, on_progress_args=None, on_progress_kwargs=None): self.assertEquals("some_slicer", slicer_name) self.assertEquals("prefix/source.file", source_path) self.assertEquals("tmp.file", dest_path)