diff --git a/cura/PrinterOutput/ExtruderOuputModel.py b/cura/PrinterOutput/ExtruderOuputModel.py index b0be6cbbe4..befde28f99 100644 --- a/cura/PrinterOutput/ExtruderOuputModel.py +++ b/cura/PrinterOutput/ExtruderOuputModel.py @@ -17,14 +17,23 @@ class ExtruderOutputModel(QObject): targetHotendTemperatureChanged = pyqtSignal() hotendTemperatureChanged = pyqtSignal() activeMaterialChanged = pyqtSignal() + isPreheatingChanged = pyqtSignal() - def __init__(self, printer: "PrinterOutputModel", parent=None): + def __init__(self, printer: "PrinterOutputModel", position: int, parent=None): super().__init__(parent) self._printer = printer + self._position = position self._target_hotend_temperature = 0 self._hotend_temperature = 0 self._hotend_id = "" self._active_material = None # type: Optional[MaterialOutputModel] + self._is_preheating = False + + def getPrinter(self): + return self._printer + + def getPosition(self): + return self._position @pyqtProperty(QObject, notify = activeMaterialChanged) def activeMaterial(self) -> "MaterialOutputModel": @@ -68,3 +77,25 @@ class ExtruderOutputModel(QObject): if self._hotend_id != id: self._hotend_id = id self.hotendIDChanged.emit() + + def updateIsPreheating(self, pre_heating): + if self._is_preheating != pre_heating: + self._is_preheating = pre_heating + self.isPreheatingChanged.emit() + + @pyqtProperty(bool, notify=isPreheatingChanged) + def isPreheating(self): + return self._is_preheating + + ## Pre-heats the extruder before printer. + # + # \param temperature The temperature to heat the extruder to, in degrees + # Celsius. + # \param duration How long the bed should stay warm, in seconds. + @pyqtSlot(float, float) + def preheatHotend(self, temperature, duration): + self._printer._controller.preheatHotend(self, temperature, duration) + + @pyqtSlot() + def cancelPreheatHotend(self): + self._printer._controller.cancelPreheatHotend(self) \ No newline at end of file diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 6bfe562f1a..512ac4aa02 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -15,7 +15,7 @@ class PrinterOutputController: self.can_pause = True self.can_abort = True self.can_pre_heat_bed = True - self.can_pre_heat_extruders = True + self.can_pre_heat_hotends = True self.can_control_manually = True self._output_device = output_device diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index cbed44fa65..f510829101 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -32,7 +32,7 @@ class PrinterOutputModel(QObject): self._name = "" self._key = "" # Unique identifier self._controller = output_controller - self._extruders = [ExtruderOutputModel(printer=self) for i in range(number_of_extruders)] + self._extruders = [ExtruderOutputModel(printer=self, position=i) for i in range(number_of_extruders)] self._head_position = Vector(0, 0, 0) self._active_print_job = None # type: Optional[PrintJobOutputModel] self._firmware_version = firmware_version @@ -220,9 +220,9 @@ class PrinterOutputModel(QObject): # Does the printer support pre-heating the bed at all @pyqtProperty(bool, constant=True) - def canPreHeatExtruders(self): + def canPreHeatHotends(self): if self._controller: - return self._controller.can_pre_heat_extruders + return self._controller.can_pre_heat_hotends return False # Does the printer support pause at all diff --git a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py index 8909a15d2c..076c4584af 100644 --- a/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py +++ b/plugins/UM3NetworkPrinting/ClusterUM3PrinterOutputController.py @@ -13,7 +13,7 @@ class ClusterUM3PrinterOutputController(PrinterOutputController): def __init__(self, output_device): super().__init__(output_device) self.can_pre_heat_bed = False - self.can_pre_heat_extruders = False + self.can_pre_heat_hotends = False self.can_control_manually = False def setJobState(self, job: "PrintJobOutputModel", state: str): diff --git a/plugins/USBPrinting/USBPrinterOutputController.py b/plugins/USBPrinting/USBPrinterOutputController.py index ba45e7b0ca..5640db4a63 100644 --- a/plugins/USBPrinting/USBPrinterOutputController.py +++ b/plugins/USBPrinting/USBPrinterOutputController.py @@ -19,6 +19,11 @@ class USBPrinterOuptutController(PrinterOutputController): self._preheat_bed_timer.timeout.connect(self._onPreheatBedTimerFinished) self._preheat_printer = None + self._preheat_extruders_timer = QTimer() + self._preheat_extruders_timer.setSingleShot(True) + self._preheat_extruders_timer.timeout.connect(self._onPreheatHotendsTimerFinished) + self._preheat_extruders = set() + def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed): self._output_device.sendCommand("G91") self._output_device.sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed)) @@ -42,6 +47,9 @@ class USBPrinterOuptutController(PrinterOutputController): self._output_device.cancelPrint() pass + def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): + self._output_device.sendCommand("M140 S%s" % temperature) + def preheatBed(self, printer: "PrinterOutputModel", temperature, duration): try: temperature = round(temperature) # The API doesn't allow floating point. @@ -60,9 +68,42 @@ class USBPrinterOuptutController(PrinterOutputController): self._preheat_bed_timer.stop() printer.updateIsPreheating(False) - def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): - self._output_device.sendCommand("M140 S%s" % temperature) - def _onPreheatBedTimerFinished(self): self.setTargetBedTemperature(self._preheat_printer, 0) - self._preheat_printer.updateIsPreheating(False) \ No newline at end of file + self._preheat_printer.updateIsPreheating(False) + + def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: int): + self._output_device.sendCommand("M104 S%s T%s" % (temperature, position)) + + def _onPreheatHotendsTimerFinished(self): + for extruder in self._preheat_extruders: + self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0) + self._preheat_extruders = set() + self._preheat_printer.updateIsPreheating(False) + + def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): + self.preheatHotend(extruder, temperature=0, duration=0) + self._preheat_extruders_timer.stop() + try: + self._preheat_extruders.remove(extruder) + except KeyError: + pass + extruder.updateIsPreheating(False) + + def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration): + position = extruder.getPosition() + number_of_extruders = len(extruder.getPrinter().extruders) + if position >= number_of_extruders: + return # Got invalid extruder nr, can't pre-heat. + + try: + temperature = round(temperature) # The API doesn't allow floating point. + duration = round(duration) + except ValueError: + return # Got invalid values, can't pre-heat. + + self.setTargetHotendTemperature(extruder.getPrinter(), position, temperature=temperature) + self._preheat_extruders_timer.setInterval(duration * 1000) + self._preheat_extruders_timer.start() + self._preheat_extruders.add(extruder) + extruder.updateIsPreheating(True) \ No newline at end of file diff --git a/resources/qml/PrinterOutput/ExtruderBox.qml b/resources/qml/PrinterOutput/ExtruderBox.qml index 171fbf2013..dee9377425 100644 --- a/resources/qml/PrinterOutput/ExtruderBox.qml +++ b/resources/qml/PrinterOutput/ExtruderBox.qml @@ -95,7 +95,7 @@ Item base.showTooltip( base, {x: 0, y: parent.mapToItem(base, 0, Math.floor(-parent.height / 4)).y}, - catalog.i18nc("@tooltip", "The current temperature of this extruder.") + catalog.i18nc("@tooltip", "The current temperature of this hotend.") ); } else @@ -144,7 +144,7 @@ Item anchors.bottomMargin: UM.Theme.getSize("default_margin").height width: Math.floor(UM.Theme.getSize("setting_control").width * 0.75) height: UM.Theme.getSize("setting_control").height - visible: extruderModel != null ? extruderModel.canPreHeatExtruders: true + visible: extruderModel != null ? extruderModel.canPreHeatHotends: true Rectangle //Highlight of input field. { anchors.fill: parent @@ -166,7 +166,7 @@ Item base.showTooltip( base, {x: 0, y: preheatTemperatureInputMouseArea.mapToItem(base, 0, 0).y}, - catalog.i18nc("@tooltip of temperature input", "The temperature to pre-heat the extruder to.") + catalog.i18nc("@tooltip of temperature input", "The temperature to pre-heat the hotend to.") ); } else @@ -208,7 +208,7 @@ Item { id: preheatButton height: UM.Theme.getSize("setting_control").height - visible: extruderModel != null ? extruderModel.canPreHeatExtruders: true + visible: extruderModel != null ? extruderModel.canPreHeatHotends: true enabled: { if (!preheatTemperatureControl.enabled) @@ -333,11 +333,11 @@ Item { if (!extruderModel.isPreheating) { - extruderModel.preheatExtruder(preheatTemperatureInput.text, 900); + extruderModel.preheatHotend(preheatTemperatureInput.text, 900); } else { - extruderModel.cancelPreheatExtruder(); + extruderModel.cancelPreheatHotend(); } } @@ -348,7 +348,7 @@ Item base.showTooltip( base, {x: 0, y: preheatButton.mapToItem(base, 0, 0).y}, - catalog.i18nc("@tooltip of pre-heat", "Heat the extruder in advance before printing. You can continue adjusting your print while it is heating, and you won't have to wait for the extruder to heat up when you're ready to print.") + catalog.i18nc("@tooltip of pre-heat", "Heat the hotend in advance before printing. You can continue adjusting your print while it is heating, and you won't have to wait for the hotend to heat up when you're ready to print.") ); } else