diff --git a/src/octoprint/plugins/virtual_printer/virtual.py b/src/octoprint/plugins/virtual_printer/virtual.py index afd4179a..ac8d7ed5 100644 --- a/src/octoprint/plugins/virtual_printer/virtual.py +++ b/src/octoprint/plugins/virtual_printer/virtual.py @@ -54,8 +54,12 @@ class VirtualPrinter(object): self._send(item) self.currentExtruder = 0 - self.temp = [0.0] * settings().getInt(["devel", "virtualPrinter", "numExtruders"]) - self.targetTemp = [0.0] * settings().getInt(["devel", "virtualPrinter", "numExtruders"]) + self.extruderCount = settings().getInt(["devel", "virtualPrinter", "numExtruders"]) + self.sharedNozzle = settings().getBoolean(["devel", "virtualPrinter", "sharedNozzle"]) + self.temperatureCount = (1 if self.sharedNozzle else self.extruderCount) + + self.temp = [0.0] * self.temperatureCount + self.targetTemp = [0.0] * self.temperatureCount self.lastTempAt = time.time() self.bedTemp = 1.0 self.bedTargetTemp = 1.0 @@ -301,8 +305,10 @@ class VirtualPrinter(object): ##~~ command implementations def _gcode_T(self, code, data): - self.currentExtruder = int(code) - self._send("Active Extruder: %d" % self.currentExtruder) + t = int(code) + if 0 <= t <= self.extruderCount: + self.currentExtruder = t + self._send("Active Extruder: %d" % self.currentExtruder) def _gcode_F(self, code, data): if self._supportF: @@ -628,7 +634,7 @@ class VirtualPrinter(object): includeOk = not self._okBeforeCommandOutput # send simulated temperature data - if settings().getInt(["devel", "virtualPrinter", "numExtruders"]) > 1: + if self.temperatureCount > 1: allTemps = [] for i in range(len(self.temp)): allTemps.append((i, self.temp[i], self.targetTemp[i])) @@ -672,7 +678,7 @@ class VirtualPrinter(object): except: pass - if tool >= settings().getInt(["devel", "virtualPrinter", "numExtruders"]): + if tool >= self.temperatureCount: return try: diff --git a/src/octoprint/printer/profile.py b/src/octoprint/printer/profile.py index 304e0c98..fb8f8980 100644 --- a/src/octoprint/printer/profile.py +++ b/src/octoprint/printer/profile.py @@ -124,7 +124,10 @@ class PrinterProfileManager(object): - Extruder offsets relative to first extruder, list of (x, y) tuples, first is always (0,0) * - ``extruder.nozzleDiameter`` - ``float`` - - Diameter of the printer nozzle + - Diameter of the printer nozzle(s) + * - ``extruder.sharedNozzle`` + - ``boolean`` + - Whether there's only one nozzle shared among all extruders (true) or one nozzle per extruder (false). * - ``axes`` - ``dict`` - Information about the printer axes @@ -185,7 +188,8 @@ class PrinterProfileManager(object): offsets = [ (0, 0) ], - nozzleDiameter = 0.4 + nozzleDiameter = 0.4, + sharedNozzle = False ), axes=dict( x = dict(speed=6000, inverted=False), @@ -390,6 +394,13 @@ class PrinterProfileManager(object): def _load_default(self): default_overrides = settings().get(["printerProfiles", "defaultProfile"]) + if self._migrate_profile(default_overrides): + try: + settings().set(["printerProfiles", "defaultProfile"], default_overrides) + settings().save() + except: + self._logger.exception("Tried to save default profile after migrating it while loading, ran into exception") + profile = self._ensure_valid_profile(dict_merge(copy.deepcopy(self.__class__.default), default_overrides)) if not profile: self._logger.warn("Invalid default profile after applying overrides") @@ -424,6 +435,14 @@ class PrinterProfileManager(object): profile["volume"]["custom_box"] = False modified = True + if "extruder" in profile and not "sharedNozzle" in profile["extruder"]: + profile["extruder"]["sharedNozzle"] = False + modified = True + + if "extruder" in profile and "sharedNozzle" in profile["extruder"] and profile["extruder"]["sharedNozzle"]: + profile["extruder"]["offsets"] = [(0.0, 0.0)] + modified = True + return modified def _ensure_valid_profile(self, profile): @@ -462,7 +481,7 @@ class PrinterProfileManager(object): return False # convert booleans - for path in (("axes", "x", "inverted"), ("axes", "y", "inverted"), ("axes", "z", "inverted")): + for path in (("axes", "x", "inverted"), ("axes", "y", "inverted"), ("axes", "z", "inverted"), ("extruder", "sharedNozzle")): try: convert_value(profile, path, bool) except Exception as e: diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index 9a80273b..7d677ac0 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -356,7 +356,8 @@ default_settings = { "echoOnM117": True, "brokenM29": True, "supportF": False, - "firmwareName": "Virtual Marlin 1.0" + "firmwareName": "Virtual Marlin 1.0", + "sharedNozzle": False } } } diff --git a/src/octoprint/static/js/app/viewmodels/gcode.js b/src/octoprint/static/js/app/viewmodels/gcode.js index d167fb14..d4ae7c31 100644 --- a/src/octoprint/static/js/app/viewmodels/gcode.js +++ b/src/octoprint/static/js/app/viewmodels/gcode.js @@ -174,7 +174,7 @@ $(function() { currentProfileData = self.settings.printerProfiles.currentProfileData(); } - if (currentProfileData && currentProfileData.extruder && currentProfileData.extruder.offsets()) { + if (currentProfileData && currentProfileData.extruder && currentProfileData.extruder.offsets() && !currentProfileData.extruder.sharedNozzle()) { var offsets = []; _.each(currentProfileData.extruder.offsets(), function(offset) { offsets.push({x: offset[0], y: offset[1]}) diff --git a/src/octoprint/static/js/app/viewmodels/printerprofiles.js b/src/octoprint/static/js/app/viewmodels/printerprofiles.js index 61ab6906..b4d76e22 100644 --- a/src/octoprint/static/js/app/viewmodels/printerprofiles.js +++ b/src/octoprint/static/js/app/viewmodels/printerprofiles.js @@ -25,7 +25,8 @@ $(function() { offsets: [ [0,0] ], - nozzleDiameter: 0.4 + nozzleDiameter: 0.4, + sharedNozzle: false } } }; @@ -63,6 +64,7 @@ $(function() { self.nozzleDiameter = ko.observable(); self.extruders = ko.observable(); self.extruderOffsets = ko.observableArray(); + self.sharedNozzle = ko.observable(); self.axisXSpeed = ko.observable(); self.axisYSpeed = ko.observable(); @@ -209,6 +211,7 @@ $(function() { self.heatedBed(data.heatedBed); self.nozzleDiameter(data.extruder.nozzleDiameter); + self.sharedNozzle(data.extruder.sharedNozzle); self.extruders(data.extruder.count); var offsets = []; if (data.extruder.count > 1) { @@ -271,7 +274,8 @@ $(function() { offsets: [ [0.0, 0.0] ], - nozzleDiameter: validFloat(self.nozzleDiameter(), defaultProfile.extruder.nozzleDiameter) + nozzleDiameter: validFloat(self.nozzleDiameter(), defaultProfile.extruder.nozzleDiameter), + sharedNozzle: self.sharedNozzle() }, axes: { x: { diff --git a/src/octoprint/static/js/app/viewmodels/temperature.js b/src/octoprint/static/js/app/viewmodels/temperature.js index 9dbd4991..e0f221c7 100644 --- a/src/octoprint/static/js/app/viewmodels/temperature.js +++ b/src/octoprint/static/js/app/viewmodels/temperature.js @@ -49,7 +49,8 @@ $(function() { // tools var currentProfileData = self.settingsViewModel.printerProfiles.currentProfileData(); var numExtruders = (currentProfileData ? currentProfileData.extruder.count() : 0); - if (numExtruders && numExtruders > 1) { + var sharedNozzle = (currentProfileData ? currentProfileData.extruder.sharedNozzle() : false); + if (numExtruders && numExtruders > 1 && !sharedNozzle) { // multiple extruders for (var extruder = 0; extruder < numExtruders; extruder++) { color = graphColors.shift(); @@ -62,7 +63,7 @@ $(function() { tools[extruder]["name"](gettext("Tool") + " " + extruder); tools[extruder]["key"]("tool" + extruder); } - } else if (numExtruders == 1) { + } else if (numExtruders == 1 || sharedNozzle) { // only one extruder, no need to add numbers color = graphColors[0]; heaterOptions["tool0"] = {name: "T", color: color}; diff --git a/src/octoprint/templates/snippets/settings/printerprofiles/profileEditorExtruder.jinja2 b/src/octoprint/templates/snippets/settings/printerprofiles/profileEditorExtruder.jinja2 index 2e09ad58..d509f117 100644 --- a/src/octoprint/templates/snippets/settings/printerprofiles/profileEditorExtruder.jinja2 +++ b/src/octoprint/templates/snippets/settings/printerprofiles/profileEditorExtruder.jinja2 @@ -17,28 +17,38 @@