From 3ac5342dfc0d37e7462ed77e9d9b7321ec769ef3 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 1 Aug 2018 15:51:10 +0200 Subject: [PATCH 01/34] Separate firmware updater from USBPrinterOutputDevice --- plugins/USBPrinting/AvrFirmwareUpdater.py | 122 ++++++++++++++++++ plugins/USBPrinting/USBPrinterOutputDevice.py | 118 ++--------------- 2 files changed, 130 insertions(+), 110 deletions(-) create mode 100644 plugins/USBPrinting/AvrFirmwareUpdater.py diff --git a/plugins/USBPrinting/AvrFirmwareUpdater.py b/plugins/USBPrinting/AvrFirmwareUpdater.py new file mode 100644 index 0000000000..5c2b8dc19e --- /dev/null +++ b/plugins/USBPrinting/AvrFirmwareUpdater.py @@ -0,0 +1,122 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import QObject, QUrl, pyqtSignal, pyqtProperty + +from cura.PrinterOutputDevice import PrinterOutputDevice + +from .avr_isp import stk500v2, intelHex + +from enum import IntEnum + +@signalemitter +class AvrFirmwareUpdater(QObject): + firmwareProgressChanged = pyqtSignal() + firmwareUpdateStateChanged = pyqtSignal() + + def __init__(self, output_device: PrinterOutputDevice) -> None: + self._output_device = output_device + + self._update_firmware_thread = Thread(target=self._updateFirmware, daemon = True) + + self._firmware_view = None + self._firmware_location = None + self._firmware_progress = 0 + self._firmware_update_state = FirmwareUpdateState.idle + + def updateFirmware(self, file): + # the file path could be url-encoded. + if file.startswith("file://"): + self._firmware_location = QUrl(file).toLocalFile() + else: + self._firmware_location = file + self.showFirmwareInterface() + self.setFirmwareUpdateState(FirmwareUpdateState.updating) + self._update_firmware_thread.start() + + def _updateFirmware(self): + # Ensure that other connections are closed. + if self._connection_state != ConnectionState.closed: + self.close() + + try: + hex_file = intelHex.readHex(self._firmware_location) + assert len(hex_file) > 0 + except (FileNotFoundError, AssertionError): + Logger.log("e", "Unable to read provided hex file. Could not update firmware.") + self.setFirmwareUpdateState(FirmwareUpdateState.firmware_not_found_error) + return + + programmer = stk500v2.Stk500v2() + programmer.progress_callback = self._onFirmwareProgress + + try: + programmer.connect(self._serial_port) + except: + programmer.close() + Logger.logException("e", "Failed to update firmware") + self.setFirmwareUpdateState(FirmwareUpdateState.communication_error) + return + + # Give programmer some time to connect. Might need more in some cases, but this worked in all tested cases. + sleep(1) + if not programmer.isConnected(): + Logger.log("e", "Unable to connect with serial. Could not update firmware") + self.setFirmwareUpdateState(FirmwareUpdateState.communication_error) + try: + programmer.programChip(hex_file) + except SerialException: + self.setFirmwareUpdateState(FirmwareUpdateState.io_error) + return + except: + self.setFirmwareUpdateState(FirmwareUpdateState.unknown_error) + return + + programmer.close() + + # Clean up for next attempt. + self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) + self._firmware_location = "" + self._onFirmwareProgress(100) + self.setFirmwareUpdateState(FirmwareUpdateState.completed) + + # Try to re-connect with the machine again, which must be done on the Qt thread, so we use call later. + CuraApplication.getInstance().callLater(self.connect) + + ## Show firmware interface. + # This will create the view if its not already created. + def showFirmwareInterface(self): + if self._firmware_view is None: + path = os.path.join(PluginRegistry.getInstance().getPluginPath("USBPrinting"), "FirmwareUpdateWindow.qml") + self._firmware_view = CuraApplication.getInstance().createQmlComponent(path, {"manager": self}) + + self._firmware_view.show() + + @pyqtProperty(float, notify = firmwareProgressChanged) + def firmwareProgress(self): + return self._firmware_progress + + @pyqtProperty(int, notify=firmwareUpdateStateChanged) + def firmwareUpdateState(self): + return self._firmware_update_state + + def setFirmwareUpdateState(self, state): + if self._firmware_update_state != state: + self._firmware_update_state = state + self.firmwareUpdateStateChanged.emit() + + # Callback function for firmware update progress. + def _onFirmwareProgress(self, progress, max_progress = 100): + self._firmware_progress = (progress / max_progress) * 100 # Convert to scale of 0-100 + self.firmwareProgressChanged.emit() + + +class FirmwareUpdateState(IntEnum): + idle = 0 + updating = 1 + completed = 2 + unknown_error = 3 + communication_error = 4 + io_error = 5 + firmware_not_found_error = 6 + diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 45b566fcab..bc2350e50f 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -13,15 +13,14 @@ from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from cura.PrinterOutput.GenericOutputController import GenericOutputController from .AutoDetectBaudJob import AutoDetectBaudJob -from .avr_isp import stk500v2, intelHex +from .AvrFirmwareUpdater import AvrFirmwareUpdater -from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty, QUrl +from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty from serial import Serial, SerialException, SerialTimeoutException from threading import Thread, Event from time import time, sleep from queue import Queue -from enum import IntEnum from typing import Union, Optional, List, cast import re @@ -32,9 +31,6 @@ catalog = i18nCatalog("cura") class USBPrinterOutputDevice(PrinterOutputDevice): - firmwareProgressChanged = pyqtSignal() - firmwareUpdateStateChanged = pyqtSignal() - def __init__(self, serial_port: str, baud_rate: Optional[int] = None) -> None: super().__init__(serial_port) self.setName(catalog.i18nc("@item:inmenu", "USB printing")) @@ -61,8 +57,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice): # Instead of using a timer, we really need the update to be as a thread, as reading from serial can block. self._update_thread = Thread(target=self._update, daemon = True) - self._update_firmware_thread = Thread(target=self._updateFirmware, daemon = True) - self._last_temperature_request = None # type: Optional[int] self._is_printing = False # A print is being sent. @@ -75,11 +69,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._paused = False - self._firmware_view = None - self._firmware_location = None - self._firmware_progress = 0 - self._firmware_update_state = FirmwareUpdateState.idle - self.setConnectionText(catalog.i18nc("@info:status", "Connected via USB")) # Queue for commands that need to be sent. @@ -88,6 +77,8 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._command_received = Event() self._command_received.set() + self._firmware_updater = AvrFirmwareUpdater(self) + CuraApplication.getInstance().getOnExitCallbackManager().addCallback(self._checkActivePrintingUponAppExit) # This is a callback function that checks if there is any printing in progress via USB when the application tries @@ -107,6 +98,10 @@ class USBPrinterOutputDevice(PrinterOutputDevice): application = CuraApplication.getInstance() application.triggerNextExitCheck() + @pyqtSlot(str) + def updateFirmware(self, file): + self._firmware_updater.updateFirmware(file) + ## Reset USB device settings # def resetDeviceSettings(self): @@ -135,93 +130,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._printGCode(gcode_list) - ## Show firmware interface. - # This will create the view if its not already created. - def showFirmwareInterface(self): - if self._firmware_view is None: - path = os.path.join(PluginRegistry.getInstance().getPluginPath("USBPrinting"), "FirmwareUpdateWindow.qml") - self._firmware_view = CuraApplication.getInstance().createQmlComponent(path, {"manager": self}) - - self._firmware_view.show() - - @pyqtSlot(str) - def updateFirmware(self, file): - # the file path could be url-encoded. - if file.startswith("file://"): - self._firmware_location = QUrl(file).toLocalFile() - else: - self._firmware_location = file - self.showFirmwareInterface() - self.setFirmwareUpdateState(FirmwareUpdateState.updating) - self._update_firmware_thread.start() - - def _updateFirmware(self): - # Ensure that other connections are closed. - if self._connection_state != ConnectionState.closed: - self.close() - - try: - hex_file = intelHex.readHex(self._firmware_location) - assert len(hex_file) > 0 - except (FileNotFoundError, AssertionError): - Logger.log("e", "Unable to read provided hex file. Could not update firmware.") - self.setFirmwareUpdateState(FirmwareUpdateState.firmware_not_found_error) - return - - programmer = stk500v2.Stk500v2() - programmer.progress_callback = self._onFirmwareProgress - - try: - programmer.connect(self._serial_port) - except: - programmer.close() - Logger.logException("e", "Failed to update firmware") - self.setFirmwareUpdateState(FirmwareUpdateState.communication_error) - return - - # Give programmer some time to connect. Might need more in some cases, but this worked in all tested cases. - sleep(1) - if not programmer.isConnected(): - Logger.log("e", "Unable to connect with serial. Could not update firmware") - self.setFirmwareUpdateState(FirmwareUpdateState.communication_error) - try: - programmer.programChip(hex_file) - except SerialException: - self.setFirmwareUpdateState(FirmwareUpdateState.io_error) - return - except: - self.setFirmwareUpdateState(FirmwareUpdateState.unknown_error) - return - - programmer.close() - - # Clean up for next attempt. - self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) - self._firmware_location = "" - self._onFirmwareProgress(100) - self.setFirmwareUpdateState(FirmwareUpdateState.completed) - - # Try to re-connect with the machine again, which must be done on the Qt thread, so we use call later. - CuraApplication.getInstance().callLater(self.connect) - - @pyqtProperty(float, notify = firmwareProgressChanged) - def firmwareProgress(self): - return self._firmware_progress - - @pyqtProperty(int, notify=firmwareUpdateStateChanged) - def firmwareUpdateState(self): - return self._firmware_update_state - - def setFirmwareUpdateState(self, state): - if self._firmware_update_state != state: - self._firmware_update_state = state - self.firmwareUpdateStateChanged.emit() - - # Callback function for firmware update progress. - def _onFirmwareProgress(self, progress, max_progress = 100): - self._firmware_progress = (progress / max_progress) * 100 # Convert to scale of 0-100 - self.firmwareProgressChanged.emit() - ## Start a print based on a g-code. # \param gcode_list List with gcode (strings). def _printGCode(self, gcode_list: List[str]): @@ -456,13 +364,3 @@ class USBPrinterOutputDevice(PrinterOutputDevice): print_job.updateTimeTotal(estimated_time) self._gcode_position += 1 - - -class FirmwareUpdateState(IntEnum): - idle = 0 - updating = 1 - completed = 2 - unknown_error = 3 - communication_error = 4 - io_error = 5 - firmware_not_found_error = 6 From 339987be9d3a7cf80d7932c49cd418009e9182df Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 2 Aug 2018 11:50:28 +0200 Subject: [PATCH 02/34] Move hardcoded firmware-file table to definitions --- .../USBPrinterOutputDeviceManager.py | 44 ++++--------------- resources/definitions/bq_hephestos.def.json | 3 +- resources/definitions/bq_witbox.def.json | 3 +- resources/definitions/ultimaker2.def.json | 3 +- .../definitions/ultimaker2_extended.def.json | 3 +- .../ultimaker2_extended_plus.def.json | 3 +- resources/definitions/ultimaker2_go.def.json | 3 +- .../definitions/ultimaker2_plus.def.json | 3 +- .../definitions/ultimaker_original.def.json | 4 +- .../ultimaker_original_dual.def.json | 2 + .../ultimaker_original_plus.def.json | 3 +- 11 files changed, 30 insertions(+), 44 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py index 2ee85187ee..f444e72908 100644 --- a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py +++ b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py @@ -93,57 +93,31 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin): global_container_stack = self._application.getGlobalContainerStack() if not global_container_stack: Logger.log("e", "There is no global container stack. Can not update firmware.") - self._firmware_view.close() return "" # The bottom of the containerstack is the machine definition machine_id = global_container_stack.getBottom().id - machine_has_heated_bed = global_container_stack.getProperty("machine_heated_bed", "value") + baudrate = 250000 if platform.system() == "Linux": + # Linux prefers a baudrate of 115200 here because older versions of + # pySerial did not support a baudrate of 250000 baudrate = 115200 - else: - baudrate = 250000 - # NOTE: The keyword used here is the id of the machine. You can find the id of your machine in the *.json file, eg. - # https://github.com/Ultimaker/Cura/blob/master/resources/machines/ultimaker_original.json#L2 - # The *.hex files are stored at a seperate repository: - # https://github.com/Ultimaker/cura-binary-data/tree/master/cura/resources/firmware - machine_without_extras = {"bq_witbox" : "MarlinWitbox.hex", - "bq_hephestos_2" : "MarlinHephestos2.hex", - "ultimaker_original" : "MarlinUltimaker-{baudrate}.hex", - "ultimaker_original_plus" : "MarlinUltimaker-UMOP-{baudrate}.hex", - "ultimaker_original_dual" : "MarlinUltimaker-{baudrate}-dual.hex", - "ultimaker2" : "MarlinUltimaker2.hex", - "ultimaker2_go" : "MarlinUltimaker2go.hex", - "ultimaker2_plus" : "MarlinUltimaker2plus.hex", - "ultimaker2_extended" : "MarlinUltimaker2extended.hex", - "ultimaker2_extended_plus" : "MarlinUltimaker2extended-plus.hex", - } - machine_with_heated_bed = {"ultimaker_original" : "MarlinUltimaker-HBK-{baudrate}.hex", - "ultimaker_original_dual" : "MarlinUltimaker-HBK-{baudrate}-dual.hex", - } - ##TODO: Add check for multiple extruders - hex_file = None - if machine_id in machine_without_extras.keys(): # The machine needs to be defined here! - if machine_id in machine_with_heated_bed.keys() and machine_has_heated_bed: - Logger.log("d", "Choosing firmware with heated bed enabled for machine %s.", machine_id) - hex_file = machine_with_heated_bed[machine_id] # Return firmware with heated bed enabled - else: - Logger.log("d", "Choosing basic firmware for machine %s.", machine_id) - hex_file = machine_without_extras[machine_id] # Return "basic" firmware - else: - Logger.log("w", "There is no firmware for machine %s.", machine_id) + # If a firmware file is available, it should be specified in the definition for the printer + hex_file = global_container_stack.getMetaDataEntry("firmware_file", None) + if machine_has_heated_bed: + hex_file = global_container_stack.getMetaDataEntry("firmware_hbk_file", hex_file) if hex_file: try: return Resources.getPath(CuraApplication.ResourceTypes.Firmware, hex_file.format(baudrate=baudrate)) except FileNotFoundError: - Logger.log("w", "Could not find any firmware for machine %s.", machine_id) + Logger.log("w", "Firmware file %s not found.", hex_file) return "" else: - Logger.log("w", "Could not find any firmware for machine %s.", machine_id) + Logger.log("w", "There is no firmware for machine %s.", machine_id) return "" ## Helper to identify serial ports (and scan for them) diff --git a/resources/definitions/bq_hephestos.def.json b/resources/definitions/bq_hephestos.def.json index 8dc67a8cad..be024cd6fa 100644 --- a/resources/definitions/bq_hephestos.def.json +++ b/resources/definitions/bq_hephestos.def.json @@ -12,7 +12,8 @@ "machine_extruder_trains": { "0": "bq_hephestos_extruder_0" - } + }, + "firmware_file": "MarlinHephestos2.hex" }, "overrides": { diff --git a/resources/definitions/bq_witbox.def.json b/resources/definitions/bq_witbox.def.json index 0ae1c5e339..b96da6179c 100644 --- a/resources/definitions/bq_witbox.def.json +++ b/resources/definitions/bq_witbox.def.json @@ -12,7 +12,8 @@ "machine_extruder_trains": { "0": "bq_witbox_extruder_0" - } + }, + "firmware_file": "MarlinWitbox.hex" }, "overrides": { diff --git a/resources/definitions/ultimaker2.def.json b/resources/definitions/ultimaker2.def.json index aa684946c2..ca7a784bfc 100644 --- a/resources/definitions/ultimaker2.def.json +++ b/resources/definitions/ultimaker2.def.json @@ -20,7 +20,8 @@ "machine_extruder_trains": { "0": "ultimaker2_extruder_0" - } + }, + "firmware_file": "MarlinUltimaker2.hex" }, "overrides": { "machine_name": { "default_value": "Ultimaker 2" }, diff --git a/resources/definitions/ultimaker2_extended.def.json b/resources/definitions/ultimaker2_extended.def.json index af169c94fb..39a1ca37b3 100644 --- a/resources/definitions/ultimaker2_extended.def.json +++ b/resources/definitions/ultimaker2_extended.def.json @@ -14,7 +14,8 @@ "machine_extruder_trains": { "0": "ultimaker2_extended_extruder_0" - } + }, + "firmware_file": "MarlinUltimaker2extended.hex" }, "overrides": { diff --git a/resources/definitions/ultimaker2_extended_plus.def.json b/resources/definitions/ultimaker2_extended_plus.def.json index f3a8bfcf9f..c296ecd43e 100644 --- a/resources/definitions/ultimaker2_extended_plus.def.json +++ b/resources/definitions/ultimaker2_extended_plus.def.json @@ -14,7 +14,8 @@ "machine_extruder_trains": { "0": "ultimaker2_extended_plus_extruder_0" - } + }, + "firmware_file": "MarlinUltimaker2extended-plus.hex" }, "overrides": { diff --git a/resources/definitions/ultimaker2_go.def.json b/resources/definitions/ultimaker2_go.def.json index c66fb38fc0..5301fd7db9 100644 --- a/resources/definitions/ultimaker2_go.def.json +++ b/resources/definitions/ultimaker2_go.def.json @@ -17,7 +17,8 @@ "machine_extruder_trains": { "0": "ultimaker2_go_extruder_0" - } + }, + "firmware_file": "MarlinUltimaker2go.hex" }, "overrides": { diff --git a/resources/definitions/ultimaker2_plus.def.json b/resources/definitions/ultimaker2_plus.def.json index bc4d3a6230..45019789bf 100644 --- a/resources/definitions/ultimaker2_plus.def.json +++ b/resources/definitions/ultimaker2_plus.def.json @@ -19,7 +19,8 @@ "machine_extruder_trains": { "0": "ultimaker2_plus_extruder_0" - } + }, + "firmware_file": "MarlinUltimaker2plus.hex" }, "overrides": { diff --git a/resources/definitions/ultimaker_original.def.json b/resources/definitions/ultimaker_original.def.json index c961423504..bb6a64d8dc 100644 --- a/resources/definitions/ultimaker_original.def.json +++ b/resources/definitions/ultimaker_original.def.json @@ -18,7 +18,9 @@ "machine_extruder_trains": { "0": "ultimaker_original_extruder_0" - } + }, + "firmware_file": "MarlinUltimaker-{baudrate}.hex", + "firmware_hbk_file": "MarlinUltimaker-HKB-{baudrate}.hex" }, "overrides": { diff --git a/resources/definitions/ultimaker_original_dual.def.json b/resources/definitions/ultimaker_original_dual.def.json index 55eddba85f..c6002ef396 100644 --- a/resources/definitions/ultimaker_original_dual.def.json +++ b/resources/definitions/ultimaker_original_dual.def.json @@ -19,6 +19,8 @@ "0": "ultimaker_original_dual_1st", "1": "ultimaker_original_dual_2nd" }, + "firmware_file": "MarlinUltimaker-{baudrate}-dual.hex", + "firmware_hbk_file": "MarlinUltimaker-HKB-{baudrate}-dual.hex", "first_start_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel"], "supported_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel", "UpgradeFirmware"] }, diff --git a/resources/definitions/ultimaker_original_plus.def.json b/resources/definitions/ultimaker_original_plus.def.json index 71aa53b2bf..46d95f8028 100644 --- a/resources/definitions/ultimaker_original_plus.def.json +++ b/resources/definitions/ultimaker_original_plus.def.json @@ -16,7 +16,8 @@ "machine_extruder_trains": { "0": "ultimaker_original_plus_extruder_0" - } + }, + "firmware_file": "MarlinUltimaker-UMOP-{baudrate}.hex" }, "overrides": { From 688a5083d223b84067d9c4b6a7ccc301b6618db1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 8 Aug 2018 15:53:26 +0200 Subject: [PATCH 03/34] Add canUpdateFirmware property to printer output devices --- cura/PrinterOutput/GenericOutputController.py | 2 ++ cura/PrinterOutput/PrinterOutputController.py | 1 + cura/PrinterOutput/PrinterOutputModel.py | 7 +++++++ plugins/USBPrinting/AvrFirmwareUpdater.py | 1 - .../UpgradeFirmwareMachineAction.qml | 1 + 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cura/PrinterOutput/GenericOutputController.py b/cura/PrinterOutput/GenericOutputController.py index e6310e5bff..32ad9d8022 100644 --- a/cura/PrinterOutput/GenericOutputController.py +++ b/cura/PrinterOutput/GenericOutputController.py @@ -29,6 +29,8 @@ class GenericOutputController(PrinterOutputController): self._output_device.printersChanged.connect(self._onPrintersChanged) self._active_printer = None + self.can_update_firmware = True + def _onPrintersChanged(self): if self._active_printer: self._active_printer.stateChanged.disconnect(self._onPrinterStateChanged) diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 58c6ef05a7..4fe5c04a65 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -18,6 +18,7 @@ class PrinterOutputController: self.can_pre_heat_hotends = True self.can_send_raw_gcode = True self.can_control_manually = True + self.can_update_firmware = False self._output_device = output_device def setTargetHotendTemperature(self, printer: "PrinterOutputModel", extruder: "ExtruderOutputModel", temperature: int): diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 6fafa368bb..f43dbf570e 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -277,6 +277,13 @@ class PrinterOutputModel(QObject): return self._controller.can_control_manually return False + # Does the printer support upgrading firmware + @pyqtProperty(bool, notify = canUpdateFirmwareChanged) + def canUpdateFirmware(self): + if self._controller: + return self._controller.can_update_firmware + return False + # Returns the configuration (material, variant and buildplate) of the current printer @pyqtProperty(QObject, notify = configurationChanged) def printerConfiguration(self): diff --git a/plugins/USBPrinting/AvrFirmwareUpdater.py b/plugins/USBPrinting/AvrFirmwareUpdater.py index 5c2b8dc19e..681601e3a5 100644 --- a/plugins/USBPrinting/AvrFirmwareUpdater.py +++ b/plugins/USBPrinting/AvrFirmwareUpdater.py @@ -9,7 +9,6 @@ from .avr_isp import stk500v2, intelHex from enum import IntEnum -@signalemitter class AvrFirmwareUpdater(QObject): firmwareProgressChanged = pyqtSignal() firmwareUpdateStateChanged = pyqtSignal() diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml index ed771d2a04..03c17cd811 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml @@ -16,6 +16,7 @@ Cura.MachineAction anchors.fill: parent; property bool printerConnected: Cura.MachineManager.printerConnected property var activeOutputDevice: printerConnected ? Cura.MachineManager.printerOutputDevices[0] : null + property var canUpdateFirmware: activeOutputDevice ? activeOutputDevice.canUpdateFirmware : False Item { From 4bea1410b8ca194ed64dec4f53864c89b84667e8 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 22 Aug 2018 14:37:48 +0200 Subject: [PATCH 04/34] Allow printer output devices to set their ability to update firmware --- cura/PrinterOutput/GenericOutputController.py | 2 -- cura/PrinterOutput/PrinterOutputController.py | 7 ++++ cura/PrinterOutput/PrinterOutputModel.py | 6 ++++ plugins/USBPrinting/USBPrinterOutputDevice.py | 8 +++-- .../UpgradeFirmwareMachineAction.qml | 34 ++++++++++++------- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/cura/PrinterOutput/GenericOutputController.py b/cura/PrinterOutput/GenericOutputController.py index 32ad9d8022..e6310e5bff 100644 --- a/cura/PrinterOutput/GenericOutputController.py +++ b/cura/PrinterOutput/GenericOutputController.py @@ -29,8 +29,6 @@ class GenericOutputController(PrinterOutputController): self._output_device.printersChanged.connect(self._onPrintersChanged) self._active_printer = None - self.can_update_firmware = True - def _onPrintersChanged(self): if self._active_printer: self._active_printer.stateChanged.disconnect(self._onPrinterStateChanged) diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 4fe5c04a65..eb5f15cceb 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -2,6 +2,7 @@ # Cura is released under the terms of the LGPLv3 or higher. from UM.Logger import Logger +from UM.Signal import Signal MYPY = False if MYPY: @@ -56,3 +57,9 @@ class PrinterOutputController: def sendRawCommand(self, printer: "PrinterOutputModel", command: str): Logger.log("w", "Custom command not implemented in controller") + + canUpdateFirmwareChanged = Signal() + def setCanUpdateFirmware(self, can_update_firmware: bool): + if can_update_firmware != self.can_update_firmware: + self.can_update_firmware = can_update_firmware + self.canUpdateFirmwareChanged.emit() \ No newline at end of file diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 252fc35080..5d63f6f1ce 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -26,6 +26,7 @@ class PrinterOutputModel(QObject): buildplateChanged = pyqtSignal() cameraChanged = pyqtSignal() configurationChanged = pyqtSignal() + canUpdateFirmwareChanged = pyqtSignal() def __init__(self, output_controller: "PrinterOutputController", number_of_extruders: int = 1, parent=None, firmware_version = "") -> None: super().__init__(parent) @@ -34,6 +35,7 @@ class PrinterOutputModel(QObject): self._name = "" self._key = "" # Unique identifier self._controller = output_controller + self._controller.canUpdateFirmwareChanged.connect(self._onControllerCanUpdateFirmwareChanged) self._extruders = [ExtruderOutputModel(printer = self, position = i) for i in range(number_of_extruders)] self._printer_configuration = ConfigurationModel() # Indicates the current configuration setup in this printer self._head_position = Vector(0, 0, 0) @@ -284,6 +286,10 @@ class PrinterOutputModel(QObject): return self._controller.can_update_firmware return False + # Stub to connect UM.Signal to pyqtSignal + def _onControllerCanUpdateFirmwareChanged(self): + self.canUpdateFirmwareChanged.emit() + # Returns the configuration (material, variant and buildplate) of the current printer @pyqtProperty(QObject, notify = configurationChanged) def printerConfiguration(self): diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index bc2350e50f..957269f155 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -183,7 +183,9 @@ class USBPrinterOutputDevice(PrinterOutputDevice): container_stack = CuraApplication.getInstance().getGlobalContainerStack() num_extruders = container_stack.getProperty("machine_extruder_count", "value") # Ensure that a printer is created. - self._printers = [PrinterOutputModel(output_controller=GenericOutputController(self), number_of_extruders=num_extruders)] + controller = GenericOutputController(self) + controller.setCanUpdateFirmware(True) + self._printers = [PrinterOutputModel(output_controller=controller, number_of_extruders=num_extruders)] self._printers[0].updateName(container_stack.getName()) self.setConnectionState(ConnectionState.connected) self._update_thread.start() @@ -353,7 +355,9 @@ class USBPrinterOutputDevice(PrinterOutputDevice): elapsed_time = int(time() - self._print_start_time) print_job = self._printers[0].activePrintJob if print_job is None: - print_job = PrintJobOutputModel(output_controller = GenericOutputController(self), name= CuraApplication.getInstance().getPrintInformation().jobName) + controller = GenericOutputController(self) + controller.setCanUpdateFirmware(True) + print_job = PrintJobOutputModel(output_controller = controller, name= CuraApplication.getInstance().getPrintInformation().jobName) print_job.updateState("printing") self._printers[0].updateActivePrintJob(print_job) diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml index 03c17cd811..7c15c303b5 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml @@ -16,17 +16,17 @@ Cura.MachineAction anchors.fill: parent; property bool printerConnected: Cura.MachineManager.printerConnected property var activeOutputDevice: printerConnected ? Cura.MachineManager.printerOutputDevices[0] : null - property var canUpdateFirmware: activeOutputDevice ? activeOutputDevice.canUpdateFirmware : False + property var canUpdateFirmware: activeOutputDevice ? activeOutputDevice.activePrinter.canUpdateFirmware : False - Item + Column { id: upgradeFirmwareMachineAction anchors.fill: parent; UM.I18nCatalog { id: catalog; name:"cura"} + spacing: UM.Theme.getSize("default_margin").height Label { - id: pageTitle width: parent.width text: catalog.i18nc("@title", "Upgrade Firmware") wrapMode: Text.WordWrap @@ -34,9 +34,6 @@ Cura.MachineAction } Label { - id: pageDescription - anchors.top: pageTitle.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height width: parent.width wrapMode: Text.WordWrap text: catalog.i18nc("@label", "Firmware is the piece of software running directly on your 3D printer. This firmware controls the step motors, regulates the temperature and ultimately makes your printer work.") @@ -44,9 +41,6 @@ Cura.MachineAction Label { - id: upgradeText1 - anchors.top: pageDescription.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height width: parent.width wrapMode: Text.WordWrap text: catalog.i18nc("@label", "The firmware shipping with new printers works, but new versions tend to have more features and improvements."); @@ -54,8 +48,6 @@ Cura.MachineAction Row { - anchors.top: upgradeText1.bottom - anchors.topMargin: UM.Theme.getSize("default_margin").height anchors.horizontalCenter: parent.horizontalCenter width: childrenRect.width spacing: UM.Theme.getSize("default_margin").width @@ -64,7 +56,7 @@ Cura.MachineAction { id: autoUpgradeButton text: catalog.i18nc("@action:button", "Automatically upgrade Firmware"); - enabled: parent.firmwareName != "" && activeOutputDevice + enabled: parent.firmwareName != "" && canUpdateFirmware onClicked: { activeOutputDevice.updateFirmware(parent.firmwareName) @@ -74,7 +66,7 @@ Cura.MachineAction { id: manualUpgradeButton text: catalog.i18nc("@action:button", "Upload custom Firmware"); - enabled: activeOutputDevice != null + enabled: canUpdateFirmware onClicked: { customFirmwareDialog.open() @@ -82,6 +74,22 @@ Cura.MachineAction } } + Label + { + width: parent.width + wrapMode: Text.WordWrap + visible: !printerConnected + text: catalog.i18nc("@label", "Firmware can not be upgraded because there is no connection with the printer."); + } + + Label + { + width: parent.width + wrapMode: Text.WordWrap + visible: printerConnected && !canUpdateFirmware + text: catalog.i18nc("@label", "Firmware can not be upgraded because the connection with the printer does not support upgrading firmware."); + } + FileDialog { id: customFirmwareDialog From 5f81c6d1f4a0c7f52feaa0d860946a90d762ee82 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 22 Aug 2018 15:21:03 +0200 Subject: [PATCH 05/34] Add a FirmwareUpdater class and make AvrFirmwareUpdater a subclass --- cura/FirmwareUpdater.py | 81 +++++++++++++++++++ plugins/USBPrinting/AvrFirmwareUpdater.py | 77 +----------------- .../qml}/FirmwareUpdateWindow.qml | 0 3 files changed, 85 insertions(+), 73 deletions(-) create mode 100644 cura/FirmwareUpdater.py rename {plugins/USBPrinting => resources/qml}/FirmwareUpdateWindow.qml (100%) diff --git a/cura/FirmwareUpdater.py b/cura/FirmwareUpdater.py new file mode 100644 index 0000000000..ca5997bfb1 --- /dev/null +++ b/cura/FirmwareUpdater.py @@ -0,0 +1,81 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from PyQt5.QtCore import QObject, QUrl, pyqtSignal, pyqtProperty + +from UM.Resources import Resources +from cura.PrinterOutputDevice import PrinterOutputDevice + +from enum import IntEnum + +class FirmwareUpdater(QObject): + firmwareProgressChanged = pyqtSignal() + firmwareUpdateStateChanged = pyqtSignal() + + def __init__(self, output_device: PrinterOutputDevice) -> None: + self._output_device = output_device + + self._update_firmware_thread = Thread(target=self._updateFirmware, daemon = True) + + self._firmware_view = None + self._firmware_location = None + self._firmware_progress = 0 + self._firmware_update_state = FirmwareUpdateState.idle + + def updateFirmware(self, file): + # the file path could be url-encoded. + if file.startswith("file://"): + self._firmware_location = QUrl(file).toLocalFile() + else: + self._firmware_location = file + self.showFirmwareInterface() + self.setFirmwareUpdateState(FirmwareUpdateState.updating) + self._update_firmware_thread.start() + + def _updateFirmware(self): + raise NotImplementedError("_updateFirmware needs to be implemented") + + def cleanupAfterUpdate(self): + # Clean up for next attempt. + self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) + self._firmware_location = "" + self._onFirmwareProgress(100) + self.setFirmwareUpdateState(FirmwareUpdateState.completed) + + ## Show firmware interface. + # This will create the view if its not already created. + def showFirmwareInterface(self): + if self._firmware_view is None: + path = Resources.getPath(self.ResourceTypes.QmlFiles, "FirmwareUpdateWindow.qml") + self._firmware_view = CuraApplication.getInstance().createQmlComponent(path, {"manager": self}) + + self._firmware_view.show() + + @pyqtProperty(float, notify = firmwareProgressChanged) + def firmwareProgress(self): + return self._firmware_progress + + @pyqtProperty(int, notify=firmwareUpdateStateChanged) + def firmwareUpdateState(self): + return self._firmware_update_state + + def setFirmwareUpdateState(self, state): + if self._firmware_update_state != state: + self._firmware_update_state = state + self.firmwareUpdateStateChanged.emit() + + # Callback function for firmware update progress. + def _onFirmwareProgress(self, progress, max_progress = 100): + self._firmware_progress = (progress / max_progress) * 100 # Convert to scale of 0-100 + self.firmwareProgressChanged.emit() + + +class FirmwareUpdateState(IntEnum): + idle = 0 + updating = 1 + completed = 2 + unknown_error = 3 + communication_error = 4 + io_error = 5 + firmware_not_found_error = 6 + diff --git a/plugins/USBPrinting/AvrFirmwareUpdater.py b/plugins/USBPrinting/AvrFirmwareUpdater.py index 681601e3a5..d3028be0e4 100644 --- a/plugins/USBPrinting/AvrFirmwareUpdater.py +++ b/plugins/USBPrinting/AvrFirmwareUpdater.py @@ -1,43 +1,16 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from PyQt5.QtCore import QObject, QUrl, pyqtSignal, pyqtProperty - from cura.PrinterOutputDevice import PrinterOutputDevice +from cura.FirmwareUpdater import FirmwareUpdater, FirmwareUpdateState from .avr_isp import stk500v2, intelHex -from enum import IntEnum - -class AvrFirmwareUpdater(QObject): - firmwareProgressChanged = pyqtSignal() - firmwareUpdateStateChanged = pyqtSignal() - +class AvrFirmwareUpdater(FirmwareUpdater): def __init__(self, output_device: PrinterOutputDevice) -> None: - self._output_device = output_device - - self._update_firmware_thread = Thread(target=self._updateFirmware, daemon = True) - - self._firmware_view = None - self._firmware_location = None - self._firmware_progress = 0 - self._firmware_update_state = FirmwareUpdateState.idle - - def updateFirmware(self, file): - # the file path could be url-encoded. - if file.startswith("file://"): - self._firmware_location = QUrl(file).toLocalFile() - else: - self._firmware_location = file - self.showFirmwareInterface() - self.setFirmwareUpdateState(FirmwareUpdateState.updating) - self._update_firmware_thread.start() + super().__init__(output_device) def _updateFirmware(self): - # Ensure that other connections are closed. - if self._connection_state != ConnectionState.closed: - self.close() - try: hex_file = intelHex.readHex(self._firmware_location) assert len(hex_file) > 0 @@ -73,49 +46,7 @@ class AvrFirmwareUpdater(QObject): programmer.close() - # Clean up for next attempt. - self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) - self._firmware_location = "" - self._onFirmwareProgress(100) - self.setFirmwareUpdateState(FirmwareUpdateState.completed) - # Try to re-connect with the machine again, which must be done on the Qt thread, so we use call later. CuraApplication.getInstance().callLater(self.connect) - ## Show firmware interface. - # This will create the view if its not already created. - def showFirmwareInterface(self): - if self._firmware_view is None: - path = os.path.join(PluginRegistry.getInstance().getPluginPath("USBPrinting"), "FirmwareUpdateWindow.qml") - self._firmware_view = CuraApplication.getInstance().createQmlComponent(path, {"manager": self}) - - self._firmware_view.show() - - @pyqtProperty(float, notify = firmwareProgressChanged) - def firmwareProgress(self): - return self._firmware_progress - - @pyqtProperty(int, notify=firmwareUpdateStateChanged) - def firmwareUpdateState(self): - return self._firmware_update_state - - def setFirmwareUpdateState(self, state): - if self._firmware_update_state != state: - self._firmware_update_state = state - self.firmwareUpdateStateChanged.emit() - - # Callback function for firmware update progress. - def _onFirmwareProgress(self, progress, max_progress = 100): - self._firmware_progress = (progress / max_progress) * 100 # Convert to scale of 0-100 - self.firmwareProgressChanged.emit() - - -class FirmwareUpdateState(IntEnum): - idle = 0 - updating = 1 - completed = 2 - unknown_error = 3 - communication_error = 4 - io_error = 5 - firmware_not_found_error = 6 - + self.cleanupAfterUpdate() diff --git a/plugins/USBPrinting/FirmwareUpdateWindow.qml b/resources/qml/FirmwareUpdateWindow.qml similarity index 100% rename from plugins/USBPrinting/FirmwareUpdateWindow.qml rename to resources/qml/FirmwareUpdateWindow.qml From 7b00d6879a5cd197f220e2351686e40d71dcb1d4 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 22 Aug 2018 15:44:11 +0200 Subject: [PATCH 06/34] Factor out USBPrinterManager singleton --- cura/Settings/MachineManager.py | 34 ++++++++++++++++++ .../USBPrinterOutputDeviceManager.py | 35 ------------------- plugins/USBPrinting/__init__.py | 1 - .../UMOCheckupMachineAction.qml | 32 ++++++++--------- .../UpgradeFirmwareMachineAction.qml | 2 +- 5 files changed, 51 insertions(+), 53 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index d65bbfddd9..f330d70225 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -4,6 +4,7 @@ import collections import time from typing import Any, Callable, List, Dict, TYPE_CHECKING, Optional, cast +import platform from UM.ConfigurationErrorMessage import ConfigurationErrorMessage from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator @@ -16,6 +17,7 @@ from UM.FlameProfiler import pyqtSlot from UM import Util from UM.Logger import Logger from UM.Message import Message +from UM.Resources import Resources from UM.Settings.SettingFunction import SettingFunction from UM.Signal import postponeSignals, CompressTechnique @@ -1531,3 +1533,35 @@ class MachineManager(QObject): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self.updateMaterialWithVariant(None) self._updateQualityWithMaterial() + + ## Get default firmware file name if one is specified in the firmware + @pyqtSlot(result = str) + def getDefaultFirmwareName(self): + # Check if there is a valid global container stack + if not self._global_container_stack: + return "" + + # The bottom of the containerstack is the machine definition + machine_id = self._global_container_stack.getBottom().id + machine_has_heated_bed = self._global_container_stack.getProperty("machine_heated_bed", "value") + + baudrate = 250000 + if platform.system() == "Linux": + # Linux prefers a baudrate of 115200 here because older versions of + # pySerial did not support a baudrate of 250000 + baudrate = 115200 + + # If a firmware file is available, it should be specified in the definition for the printer + hex_file = self._global_container_stack.getMetaDataEntry("firmware_file", None) + if machine_has_heated_bed: + hex_file = self._global_container_stack.getMetaDataEntry("firmware_hbk_file", hex_file) + + if hex_file: + try: + return Resources.getPath(cura.CuraApplication.CuraApplication.ResourceTypes.Firmware, hex_file.format(baudrate=baudrate)) + except FileNotFoundError: + Logger.log("w", "Firmware file %s not found.", hex_file) + return "" + else: + Logger.log("w", "There is no firmware for machine %s.", machine_id) + return "" diff --git a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py index f444e72908..bd207d9d96 100644 --- a/plugins/USBPrinting/USBPrinterOutputDeviceManager.py +++ b/plugins/USBPrinting/USBPrinterOutputDeviceManager.py @@ -2,14 +2,12 @@ # Cura is released under the terms of the LGPLv3 or higher. import threading -import platform import time import serial.tools.list_ports from PyQt5.QtCore import QObject, pyqtSlot, pyqtProperty, pyqtSignal from UM.Logger import Logger -from UM.Resources import Resources from UM.Signal import Signal, signalemitter from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin from UM.i18n import i18nCatalog @@ -87,39 +85,6 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin): self._addRemovePorts(port_list) time.sleep(5) - @pyqtSlot(result = str) - def getDefaultFirmwareName(self): - # Check if there is a valid global container stack - global_container_stack = self._application.getGlobalContainerStack() - if not global_container_stack: - Logger.log("e", "There is no global container stack. Can not update firmware.") - return "" - - # The bottom of the containerstack is the machine definition - machine_id = global_container_stack.getBottom().id - machine_has_heated_bed = global_container_stack.getProperty("machine_heated_bed", "value") - - baudrate = 250000 - if platform.system() == "Linux": - # Linux prefers a baudrate of 115200 here because older versions of - # pySerial did not support a baudrate of 250000 - baudrate = 115200 - - # If a firmware file is available, it should be specified in the definition for the printer - hex_file = global_container_stack.getMetaDataEntry("firmware_file", None) - if machine_has_heated_bed: - hex_file = global_container_stack.getMetaDataEntry("firmware_hbk_file", hex_file) - - if hex_file: - try: - return Resources.getPath(CuraApplication.ResourceTypes.Firmware, hex_file.format(baudrate=baudrate)) - except FileNotFoundError: - Logger.log("w", "Firmware file %s not found.", hex_file) - return "" - else: - Logger.log("w", "There is no firmware for machine %s.", machine_id) - return "" - ## Helper to identify serial ports (and scan for them) def _addRemovePorts(self, serial_ports): # First, find and add all new or changed keys diff --git a/plugins/USBPrinting/__init__.py b/plugins/USBPrinting/__init__.py index fd5488eead..0cb68d3865 100644 --- a/plugins/USBPrinting/__init__.py +++ b/plugins/USBPrinting/__init__.py @@ -14,5 +14,4 @@ def getMetaData(): def register(app): # We are violating the QT API here (as we use a factory, which is technically not allowed). # but we don't really have another means for doing this (and it seems to you know -work-) - qmlRegisterSingletonType(USBPrinterOutputDeviceManager.USBPrinterOutputDeviceManager, "Cura", 1, 0, "USBPrinterManager", USBPrinterOutputDeviceManager.USBPrinterOutputDeviceManager.getInstance) return {"output_device": USBPrinterOutputDeviceManager.USBPrinterOutputDeviceManager(app)} diff --git a/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml b/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml index b92638aa12..4a1d42e248 100644 --- a/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml +++ b/plugins/UltimakerMachineActions/UMOCheckupMachineAction.qml @@ -17,7 +17,7 @@ Cura.MachineAction property int rightRow: (checkupMachineAction.width * 0.60) | 0 property bool heatupHotendStarted: false property bool heatupBedStarted: false - property bool usbConnected: Cura.USBPrinterManager.connectedPrinterList.rowCount() > 0 + property bool printerConnected: Cura.MachineManager.printerConnected UM.I18nCatalog { id: catalog; name:"cura"} Label @@ -86,7 +86,7 @@ Cura.MachineAction anchors.left: connectionLabel.right anchors.top: parent.top wrapMode: Text.WordWrap - text: checkupMachineAction.usbConnected ? catalog.i18nc("@info:status","Connected"): catalog.i18nc("@info:status","Not connected") + text: checkupMachineAction.printerConnected ? catalog.i18nc("@info:status","Connected"): catalog.i18nc("@info:status","Not connected") } ////////////////////////////////////////////////////////// Label @@ -97,7 +97,7 @@ Cura.MachineAction anchors.top: connectionLabel.bottom wrapMode: Text.WordWrap text: catalog.i18nc("@label","Min endstop X: ") - visible: checkupMachineAction.usbConnected + visible: checkupMachineAction.printerConnected } Label { @@ -107,7 +107,7 @@ Cura.MachineAction anchors.top: connectionLabel.bottom wrapMode: Text.WordWrap text: manager.xMinEndstopTestCompleted ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked") - visible: checkupMachineAction.usbConnected + visible: checkupMachineAction.printerConnected } ////////////////////////////////////////////////////////////// Label @@ -118,7 +118,7 @@ Cura.MachineAction anchors.top: endstopXLabel.bottom wrapMode: Text.WordWrap text: catalog.i18nc("@label","Min endstop Y: ") - visible: checkupMachineAction.usbConnected + visible: checkupMachineAction.printerConnected } Label { @@ -128,7 +128,7 @@ Cura.MachineAction anchors.top: endstopXLabel.bottom wrapMode: Text.WordWrap text: manager.yMinEndstopTestCompleted ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked") - visible: checkupMachineAction.usbConnected + visible: checkupMachineAction.printerConnected } ///////////////////////////////////////////////////////////////////// Label @@ -139,7 +139,7 @@ Cura.MachineAction anchors.top: endstopYLabel.bottom wrapMode: Text.WordWrap text: catalog.i18nc("@label","Min endstop Z: ") - visible: checkupMachineAction.usbConnected + visible: checkupMachineAction.printerConnected } Label { @@ -149,7 +149,7 @@ Cura.MachineAction anchors.top: endstopYLabel.bottom wrapMode: Text.WordWrap text: manager.zMinEndstopTestCompleted ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked") - visible: checkupMachineAction.usbConnected + visible: checkupMachineAction.printerConnected } //////////////////////////////////////////////////////////// Label @@ -161,7 +161,7 @@ Cura.MachineAction anchors.top: endstopZLabel.bottom wrapMode: Text.WordWrap text: catalog.i18nc("@label","Nozzle temperature check: ") - visible: checkupMachineAction.usbConnected + visible: checkupMachineAction.printerConnected } Label { @@ -171,7 +171,7 @@ Cura.MachineAction anchors.left: nozzleTempLabel.right wrapMode: Text.WordWrap text: catalog.i18nc("@info:status","Not checked") - visible: checkupMachineAction.usbConnected + visible: checkupMachineAction.printerConnected } Item { @@ -181,7 +181,7 @@ Cura.MachineAction anchors.top: nozzleTempLabel.top anchors.left: bedTempStatus.right anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").width/2) - visible: checkupMachineAction.usbConnected + visible: checkupMachineAction.printerConnected Button { text: checkupMachineAction.heatupHotendStarted ? catalog.i18nc("@action:button","Stop Heating") : catalog.i18nc("@action:button","Start Heating") @@ -209,7 +209,7 @@ Cura.MachineAction wrapMode: Text.WordWrap text: manager.hotendTemperature + "°C" font.bold: true - visible: checkupMachineAction.usbConnected + visible: checkupMachineAction.printerConnected } ///////////////////////////////////////////////////////////////////////////// Label @@ -221,7 +221,7 @@ Cura.MachineAction anchors.top: nozzleTempLabel.bottom wrapMode: Text.WordWrap text: catalog.i18nc("@label","Build plate temperature check:") - visible: checkupMachineAction.usbConnected && manager.hasHeatedBed + visible: checkupMachineAction.printerConnected && manager.hasHeatedBed } Label @@ -232,7 +232,7 @@ Cura.MachineAction anchors.left: bedTempLabel.right wrapMode: Text.WordWrap text: manager.bedTestCompleted ? catalog.i18nc("@info:status","Not checked"): catalog.i18nc("@info:status","Checked") - visible: checkupMachineAction.usbConnected && manager.hasHeatedBed + visible: checkupMachineAction.printerConnected && manager.hasHeatedBed } Item { @@ -242,7 +242,7 @@ Cura.MachineAction anchors.top: bedTempLabel.top anchors.left: bedTempStatus.right anchors.leftMargin: Math.round(UM.Theme.getSize("default_margin").width/2) - visible: checkupMachineAction.usbConnected && manager.hasHeatedBed + visible: checkupMachineAction.printerConnected && manager.hasHeatedBed Button { text: checkupMachineAction.heatupBedStarted ?catalog.i18nc("@action:button","Stop Heating") : catalog.i18nc("@action:button","Start Heating") @@ -270,7 +270,7 @@ Cura.MachineAction wrapMode: Text.WordWrap text: manager.bedTemperature + "°C" font.bold: true - visible: checkupMachineAction.usbConnected && manager.hasHeatedBed + visible: checkupMachineAction.printerConnected && manager.hasHeatedBed } Label { diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml index 7c15c303b5..0d12f72a0a 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml @@ -51,7 +51,7 @@ Cura.MachineAction anchors.horizontalCenter: parent.horizontalCenter width: childrenRect.width spacing: UM.Theme.getSize("default_margin").width - property var firmwareName: Cura.USBPrinterManager.getDefaultFirmwareName() + property var firmwareName: Cura.MachineManager.getDefaultFirmwareName() Button { id: autoUpgradeButton From 5d5223920194e20108d7666e7ce6c8350323728e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 24 Aug 2018 09:09:49 +0200 Subject: [PATCH 07/34] Code style --- plugins/USBPrinting/USBPrinterOutputDevice.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 957269f155..18373d34d2 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -205,6 +205,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._command_queue.put(command) else: self._sendCommand(command) + def _sendCommand(self, command: Union[str, bytes]): if self._serial is None or self._connection_state != ConnectionState.connected: return From 77f99ecf20a6f70662ba0304366567d602e411dc Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 24 Aug 2018 15:48:11 +0200 Subject: [PATCH 08/34] Moved FirmwareUpdater to cura.PrinterOutput --- cura/{ => PrinterOutput}/FirmwareUpdater.py | 0 plugins/USBPrinting/AvrFirmwareUpdater.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename cura/{ => PrinterOutput}/FirmwareUpdater.py (100%) diff --git a/cura/FirmwareUpdater.py b/cura/PrinterOutput/FirmwareUpdater.py similarity index 100% rename from cura/FirmwareUpdater.py rename to cura/PrinterOutput/FirmwareUpdater.py diff --git a/plugins/USBPrinting/AvrFirmwareUpdater.py b/plugins/USBPrinting/AvrFirmwareUpdater.py index d3028be0e4..171c81d557 100644 --- a/plugins/USBPrinting/AvrFirmwareUpdater.py +++ b/plugins/USBPrinting/AvrFirmwareUpdater.py @@ -2,7 +2,7 @@ # Cura is released under the terms of the LGPLv3 or higher. from cura.PrinterOutputDevice import PrinterOutputDevice -from cura.FirmwareUpdater import FirmwareUpdater, FirmwareUpdateState +from cura.PrinterOutput.FirmwareUpdater import FirmwareUpdater, FirmwareUpdateState from .avr_isp import stk500v2, intelHex From 9739dbd5f69597b281b61f773d9d6418e0e3eaae Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 2 Sep 2018 17:18:04 +0200 Subject: [PATCH 09/34] Fix missing import --- cura/PrinterOutput/FirmwareUpdater.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cura/PrinterOutput/FirmwareUpdater.py b/cura/PrinterOutput/FirmwareUpdater.py index ca5997bfb1..17089ad17f 100644 --- a/cura/PrinterOutput/FirmwareUpdater.py +++ b/cura/PrinterOutput/FirmwareUpdater.py @@ -7,6 +7,7 @@ from UM.Resources import Resources from cura.PrinterOutputDevice import PrinterOutputDevice from enum import IntEnum +from threading import Thread class FirmwareUpdater(QObject): firmwareProgressChanged = pyqtSignal() From 43b4ca30440a56b843a538ad464e15fccb2fc5f5 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 2 Sep 2018 18:02:33 +0200 Subject: [PATCH 10/34] Fix code-style --- cura/PrinterOutput/FirmwareUpdater.py | 2 +- plugins/USBPrinting/USBPrinterOutputDevice.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cura/PrinterOutput/FirmwareUpdater.py b/cura/PrinterOutput/FirmwareUpdater.py index 17089ad17f..e7ffc2a2b5 100644 --- a/cura/PrinterOutput/FirmwareUpdater.py +++ b/cura/PrinterOutput/FirmwareUpdater.py @@ -16,7 +16,7 @@ class FirmwareUpdater(QObject): def __init__(self, output_device: PrinterOutputDevice) -> None: self._output_device = output_device - self._update_firmware_thread = Thread(target=self._updateFirmware, daemon = True) + self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) self._firmware_view = None self._firmware_location = None diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 18373d34d2..b04b51314c 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -55,7 +55,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._all_baud_rates = [115200, 250000, 230400, 57600, 38400, 19200, 9600] # Instead of using a timer, we really need the update to be as a thread, as reading from serial can block. - self._update_thread = Thread(target=self._update, daemon = True) + self._update_thread = Thread(target=self._update, daemon=True) self._last_temperature_request = None # type: Optional[int] @@ -358,7 +358,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): if print_job is None: controller = GenericOutputController(self) controller.setCanUpdateFirmware(True) - print_job = PrintJobOutputModel(output_controller = controller, name= CuraApplication.getInstance().getPrintInformation().jobName) + print_job = PrintJobOutputModel(output_controller=controller, name=CuraApplication.getInstance().getPrintInformation().jobName) print_job.updateState("printing") self._printers[0].updateActivePrintJob(print_job) From 4a5451576d1894b7eb40bda7f27ac81a20ea6c0f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Sun, 2 Sep 2018 18:07:30 +0200 Subject: [PATCH 11/34] Update copyright --- cura/PrinterOutput/PrinterOutputController.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index eb5f15cceb..dd2276d771 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -1,4 +1,4 @@ -# Copyright (c) 2017 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from UM.Logger import Logger From 9a98341bda96681388aefe2d2728fd7f1328c4e5 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 28 Sep 2018 11:38:42 +0200 Subject: [PATCH 12/34] Fix code-style and typing --- cura/Settings/MachineManager.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 6fd945fc31..911022b6ac 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -4,13 +4,13 @@ import collections import time from typing import Any, Callable, List, Dict, TYPE_CHECKING, Optional, cast -import platform from UM.ConfigurationErrorMessage import ConfigurationErrorMessage from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.Interfaces import ContainerInterface from UM.Signal import Signal +from UM.Platform import Platform from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QTimer from UM.FlameProfiler import pyqtSlot @@ -1543,17 +1543,16 @@ class MachineManager(QObject): ## Get default firmware file name if one is specified in the firmware @pyqtSlot(result = str) - def getDefaultFirmwareName(self): + def getDefaultFirmwareName(self) -> str: # Check if there is a valid global container stack if not self._global_container_stack: return "" # The bottom of the containerstack is the machine definition - machine_id = self._global_container_stack.getBottom().id machine_has_heated_bed = self._global_container_stack.getProperty("machine_heated_bed", "value") baudrate = 250000 - if platform.system() == "Linux": + if Platform.isLinux(): # Linux prefers a baudrate of 115200 here because older versions of # pySerial did not support a baudrate of 250000 baudrate = 115200 @@ -1570,5 +1569,5 @@ class MachineManager(QObject): Logger.log("w", "Firmware file %s not found.", hex_file) return "" else: - Logger.log("w", "There is no firmware for machine %s.", machine_id) + Logger.log("w", "There is no firmware for machine %s.", self._global_container_stack.getBottom().id) return "" From bc52830c8902f14a53bd40fa009856e545876436 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 28 Sep 2018 11:49:00 +0200 Subject: [PATCH 13/34] Move getDefaultFirmwareName() into GlobalStack --- cura/Settings/GlobalStack.py | 29 ++++++++++++++++- cura/Settings/MachineManager.py | 32 ------------------- .../UpgradeFirmwareMachineAction.qml | 2 +- 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index 517b45eb98..e3ae8c2deb 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -4,7 +4,7 @@ from collections import defaultdict import threading from typing import Any, Dict, Optional, Set, TYPE_CHECKING -from PyQt5.QtCore import pyqtProperty +from PyQt5.QtCore import pyqtProperty, pyqtSlot from UM.Decorators import override from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase @@ -13,6 +13,8 @@ from UM.Settings.SettingInstance import InstanceState from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.Interfaces import PropertyEvaluationContext from UM.Logger import Logger +from UM.Resources import Resources +from UM.Platform import Platform from UM.Util import parseBool import cura.CuraApplication @@ -200,6 +202,31 @@ class GlobalStack(CuraContainerStack): def getHasMachineQuality(self) -> bool: return parseBool(self.getMetaDataEntry("has_machine_quality", False)) + ## Get default firmware file name if one is specified in the firmware + @pyqtSlot(result = str) + def getDefaultFirmwareName(self) -> str: + machine_has_heated_bed = self.getProperty("machine_heated_bed", "value") + + baudrate = 250000 + if Platform.isLinux(): + # Linux prefers a baudrate of 115200 here because older versions of + # pySerial did not support a baudrate of 250000 + baudrate = 115200 + + # If a firmware file is available, it should be specified in the definition for the printer + hex_file = self.getMetaDataEntry("firmware_file", None) + if machine_has_heated_bed: + hex_file = self.getMetaDataEntry("firmware_hbk_file", hex_file) + + if hex_file: + try: + return Resources.getPath(cura.CuraApplication.CuraApplication.ResourceTypes.Firmware, hex_file.format(baudrate=baudrate)) + except FileNotFoundError: + Logger.log("w", "Firmware file %s not found.", hex_file) + return "" + else: + Logger.log("w", "There is no firmware for machine %s.", self.getBottom().id) + return "" ## private: global_stack_mime = MimeType( diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 911022b6ac..0abb1a5dc2 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -10,7 +10,6 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.Interfaces import ContainerInterface from UM.Signal import Signal -from UM.Platform import Platform from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QTimer from UM.FlameProfiler import pyqtSlot @@ -1540,34 +1539,3 @@ class MachineManager(QObject): with postponeSignals(*self._getContainerChangedSignals(), compress = CompressTechnique.CompressPerParameterValue): self.updateMaterialWithVariant(None) self._updateQualityWithMaterial() - - ## Get default firmware file name if one is specified in the firmware - @pyqtSlot(result = str) - def getDefaultFirmwareName(self) -> str: - # Check if there is a valid global container stack - if not self._global_container_stack: - return "" - - # The bottom of the containerstack is the machine definition - machine_has_heated_bed = self._global_container_stack.getProperty("machine_heated_bed", "value") - - baudrate = 250000 - if Platform.isLinux(): - # Linux prefers a baudrate of 115200 here because older versions of - # pySerial did not support a baudrate of 250000 - baudrate = 115200 - - # If a firmware file is available, it should be specified in the definition for the printer - hex_file = self._global_container_stack.getMetaDataEntry("firmware_file", None) - if machine_has_heated_bed: - hex_file = self._global_container_stack.getMetaDataEntry("firmware_hbk_file", hex_file) - - if hex_file: - try: - return Resources.getPath(cura.CuraApplication.CuraApplication.ResourceTypes.Firmware, hex_file.format(baudrate=baudrate)) - except FileNotFoundError: - Logger.log("w", "Firmware file %s not found.", hex_file) - return "" - else: - Logger.log("w", "There is no firmware for machine %s.", self._global_container_stack.getBottom().id) - return "" diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml index 0d12f72a0a..469ada7afb 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml @@ -51,7 +51,7 @@ Cura.MachineAction anchors.horizontalCenter: parent.horizontalCenter width: childrenRect.width spacing: UM.Theme.getSize("default_margin").width - property var firmwareName: Cura.MachineManager.getDefaultFirmwareName() + property var firmwareName: Cura.MachineManager.activeMachine.getDefaultFirmwareName() Button { id: autoUpgradeButton From a12c0e8d9eadb1bdf0d8609f1b1ffcfb09e706cc Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 28 Sep 2018 11:51:33 +0200 Subject: [PATCH 14/34] Remove superfluous import --- cura/Settings/MachineManager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cura/Settings/MachineManager.py b/cura/Settings/MachineManager.py index 0abb1a5dc2..0059b7aad2 100755 --- a/cura/Settings/MachineManager.py +++ b/cura/Settings/MachineManager.py @@ -16,7 +16,6 @@ from UM.FlameProfiler import pyqtSlot from UM import Util from UM.Logger import Logger from UM.Message import Message -from UM.Resources import Resources from UM.Settings.SettingFunction import SettingFunction from UM.Signal import postponeSignals, CompressTechnique From a573a598b01445d0f785e4b9256d6c66e96012ab Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 28 Sep 2018 12:40:44 +0200 Subject: [PATCH 15/34] Add typing and appease MYPY --- cura/PrinterOutput/FirmwareUpdater.py | 23 +++-- cura/PrinterOutput/PrintJobOutputModel.py | 2 +- cura/PrinterOutput/PrinterOutputController.py | 31 +++--- cura/PrinterOutput/PrinterOutputModel.py | 97 ++++++++++--------- plugins/USBPrinting/AvrFirmwareUpdater.py | 2 +- plugins/USBPrinting/USBPrinterOutputDevice.py | 4 +- 6 files changed, 83 insertions(+), 76 deletions(-) diff --git a/cura/PrinterOutput/FirmwareUpdater.py b/cura/PrinterOutput/FirmwareUpdater.py index e7ffc2a2b5..06e019c593 100644 --- a/cura/PrinterOutput/FirmwareUpdater.py +++ b/cura/PrinterOutput/FirmwareUpdater.py @@ -5,9 +5,11 @@ from PyQt5.QtCore import QObject, QUrl, pyqtSignal, pyqtProperty from UM.Resources import Resources from cura.PrinterOutputDevice import PrinterOutputDevice +from cura.CuraApplication import CuraApplication from enum import IntEnum from threading import Thread +from typing import Any class FirmwareUpdater(QObject): firmwareProgressChanged = pyqtSignal() @@ -19,11 +21,11 @@ class FirmwareUpdater(QObject): self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) self._firmware_view = None - self._firmware_location = None + self._firmware_location = "" self._firmware_progress = 0 self._firmware_update_state = FirmwareUpdateState.idle - def updateFirmware(self, file): + def updateFirmware(self, file: Any[str, QUrl]) -> None: # the file path could be url-encoded. if file.startswith("file://"): self._firmware_location = QUrl(file).toLocalFile() @@ -33,10 +35,10 @@ class FirmwareUpdater(QObject): self.setFirmwareUpdateState(FirmwareUpdateState.updating) self._update_firmware_thread.start() - def _updateFirmware(self): + def _updateFirmware(self) -> None: raise NotImplementedError("_updateFirmware needs to be implemented") - def cleanupAfterUpdate(self): + def cleanupAfterUpdate(self) -> None: # Clean up for next attempt. self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) self._firmware_location = "" @@ -45,28 +47,29 @@ class FirmwareUpdater(QObject): ## Show firmware interface. # This will create the view if its not already created. - def showFirmwareInterface(self): + def showFirmwareInterface(self) -> None: if self._firmware_view is None: path = Resources.getPath(self.ResourceTypes.QmlFiles, "FirmwareUpdateWindow.qml") self._firmware_view = CuraApplication.getInstance().createQmlComponent(path, {"manager": self}) - self._firmware_view.show() + if self._firmware_view: + self._firmware_view.show() @pyqtProperty(float, notify = firmwareProgressChanged) - def firmwareProgress(self): + def firmwareProgress(self) -> float: return self._firmware_progress @pyqtProperty(int, notify=firmwareUpdateStateChanged) - def firmwareUpdateState(self): + def firmwareUpdateState(self) -> FirmwareUpdateState: return self._firmware_update_state - def setFirmwareUpdateState(self, state): + def setFirmwareUpdateState(self, state) -> None: if self._firmware_update_state != state: self._firmware_update_state = state self.firmwareUpdateStateChanged.emit() # Callback function for firmware update progress. - def _onFirmwareProgress(self, progress, max_progress = 100): + def _onFirmwareProgress(self, progress, max_progress = 100) -> None: self._firmware_progress = (progress / max_progress) * 100 # Convert to scale of 0-100 self.firmwareProgressChanged.emit() diff --git a/cura/PrinterOutput/PrintJobOutputModel.py b/cura/PrinterOutput/PrintJobOutputModel.py index 7366b95f86..5b8cc39ad8 100644 --- a/cura/PrinterOutput/PrintJobOutputModel.py +++ b/cura/PrinterOutput/PrintJobOutputModel.py @@ -91,7 +91,7 @@ class PrintJobOutputModel(QObject): def assignedPrinter(self): return self._assigned_printer - def updateAssignedPrinter(self, assigned_printer: "PrinterOutputModel"): + def updateAssignedPrinter(self, assigned_printer: Optional[PrinterOutputModel]): if self._assigned_printer != assigned_printer: old_printer = self._assigned_printer self._assigned_printer = assigned_printer diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index dd2276d771..9a29233f95 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -4,15 +4,18 @@ from UM.Logger import Logger from UM.Signal import Signal +from typing import Any + MYPY = False if MYPY: from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel + from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice class PrinterOutputController: - def __init__(self, output_device): + def __init__(self, output_device: PrinterOutputDevice) -> None: self.can_pause = True self.can_abort = True self.can_pre_heat_bed = True @@ -22,44 +25,44 @@ class PrinterOutputController: self.can_update_firmware = False self._output_device = output_device - def setTargetHotendTemperature(self, printer: "PrinterOutputModel", extruder: "ExtruderOutputModel", temperature: int): + def setTargetHotendTemperature(self, printer: "PrinterOutputModel", extruder: "ExtruderOutputModel", temperature: Any[int, float]) -> None: Logger.log("w", "Set target hotend temperature not implemented in controller") - def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): + def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int) -> None: Logger.log("w", "Set target bed temperature not implemented in controller") - def setJobState(self, job: "PrintJobOutputModel", state: str): + def setJobState(self, job: "PrintJobOutputModel", state: str) -> None: Logger.log("w", "Set job state not implemented in controller") - def cancelPreheatBed(self, printer: "PrinterOutputModel"): + def cancelPreheatBed(self, printer: "PrinterOutputModel") -> None: Logger.log("w", "Cancel preheat bed not implemented in controller") - def preheatBed(self, printer: "PrinterOutputModel", temperature, duration): + def preheatBed(self, printer: "PrinterOutputModel", temperature, duration) -> None: Logger.log("w", "Preheat bed not implemented in controller") - def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): + def cancelPreheatHotend(self, extruder: "ExtruderOutputModel") -> None: Logger.log("w", "Cancel preheat hotend not implemented in controller") - def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration): + def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration) -> None: Logger.log("w", "Preheat hotend not implemented in controller") - def setHeadPosition(self, printer: "PrinterOutputModel", x, y, z, speed): + def setHeadPosition(self, printer: "PrinterOutputModel", x, y, z, speed) -> None: Logger.log("w", "Set head position not implemented in controller") - def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed): + def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed) -> None: Logger.log("w", "Move head not implemented in controller") - def homeBed(self, printer: "PrinterOutputModel"): + def homeBed(self, printer: "PrinterOutputModel") -> None: Logger.log("w", "Home bed not implemented in controller") - def homeHead(self, printer: "PrinterOutputModel"): + def homeHead(self, printer: "PrinterOutputModel") -> None: Logger.log("w", "Home head not implemented in controller") - def sendRawCommand(self, printer: "PrinterOutputModel", command: str): + def sendRawCommand(self, printer: "PrinterOutputModel", command: str) -> None: Logger.log("w", "Custom command not implemented in controller") canUpdateFirmwareChanged = Signal() - def setCanUpdateFirmware(self, can_update_firmware: bool): + def setCanUpdateFirmware(self, can_update_firmware: bool) -> None: if can_update_firmware != self.can_update_firmware: self.can_update_firmware = can_update_firmware self.canUpdateFirmwareChanged.emit() \ No newline at end of file diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 859165aef3..96feef1b55 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -2,7 +2,7 @@ # Cura is released under the terms of the LGPLv3 or higher. from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant, pyqtSlot -from typing import Optional +from typing import List, Dict, Optional from UM.Math.Vector import Vector from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel @@ -11,6 +11,7 @@ MYPY = False if MYPY: from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from cura.PrinterOutput.PrinterOutputController import PrinterOutputController + from cura.PrinterOutput.NetworkCamera import NetworkCamera class PrinterOutputModel(QObject): @@ -44,7 +45,7 @@ class PrinterOutputModel(QObject): self._printer_state = "unknown" self._is_preheating = False self._printer_type = "" - self._buildplate_name = None + self._buildplate_name = "" self._printer_configuration.extruderConfigurations = [extruder.extruderConfiguration for extruder in self._extruders] @@ -52,32 +53,32 @@ class PrinterOutputModel(QObject): self._camera = None @pyqtProperty(str, constant = True) - def firmwareVersion(self): + def firmwareVersion(self) -> str: return self._firmware_version - def setCamera(self, camera): + def setCamera(self, camera: Optional["NetworkCamera"]) -> None: if self._camera is not camera: self._camera = camera self.cameraChanged.emit() - def updateIsPreheating(self, pre_heating): + def updateIsPreheating(self, pre_heating: bool) -> None: if self._is_preheating != pre_heating: self._is_preheating = pre_heating self.isPreheatingChanged.emit() @pyqtProperty(bool, notify=isPreheatingChanged) - def isPreheating(self): + def isPreheating(self) -> bool: return self._is_preheating @pyqtProperty(QObject, notify=cameraChanged) - def camera(self): + def camera(self) -> Optional["NetworkCamera"]: return self._camera @pyqtProperty(str, notify = printerTypeChanged) - def type(self): + def type(self) -> str: return self._printer_type - def updateType(self, printer_type): + def updateType(self, printer_type: str) -> None: if self._printer_type != printer_type: self._printer_type = printer_type self._printer_configuration.printerType = self._printer_type @@ -85,10 +86,10 @@ class PrinterOutputModel(QObject): self.configurationChanged.emit() @pyqtProperty(str, notify = buildplateChanged) - def buildplate(self): + def buildplate(self) -> str: return self._buildplate_name - def updateBuildplateName(self, buildplate_name): + def updateBuildplateName(self, buildplate_name: str) -> None: if self._buildplate_name != buildplate_name: self._buildplate_name = buildplate_name self._printer_configuration.buildplateConfiguration = self._buildplate_name @@ -96,66 +97,66 @@ class PrinterOutputModel(QObject): self.configurationChanged.emit() @pyqtProperty(str, notify=keyChanged) - def key(self): + def key(self) -> str: return self._key - def updateKey(self, key: str): + def updateKey(self, key: str) -> None: if self._key != key: self._key = key self.keyChanged.emit() @pyqtSlot() - def homeHead(self): + def homeHead(self) -> None: self._controller.homeHead(self) @pyqtSlot() - def homeBed(self): + def homeBed(self) -> None: self._controller.homeBed(self) @pyqtSlot(str) - def sendRawCommand(self, command: str): + def sendRawCommand(self, command: str) -> None: self._controller.sendRawCommand(self, command) @pyqtProperty("QVariantList", constant = True) - def extruders(self): + def extruders(self) -> List["ExtruderOutputModel"]: return self._extruders @pyqtProperty(QVariant, notify = headPositionChanged) - def headPosition(self): + def headPosition(self) -> Dict[str, float]: return {"x": self._head_position.x, "y": self._head_position.y, "z": self.head_position.z} - def updateHeadPosition(self, x, y, z): + def updateHeadPosition(self, x: float, y: float, z: float) -> None: if self._head_position.x != x or self._head_position.y != y or self._head_position.z != z: self._head_position = Vector(x, y, z) self.headPositionChanged.emit() @pyqtProperty(float, float, float) @pyqtProperty(float, float, float, float) - def setHeadPosition(self, x, y, z, speed = 3000): + def setHeadPosition(self, x: float, y: float, z: float, speed: float = 3000) -> None: self.updateHeadPosition(x, y, z) self._controller.setHeadPosition(self, x, y, z, speed) @pyqtProperty(float) @pyqtProperty(float, float) - def setHeadX(self, x, speed = 3000): + def setHeadX(self, x: float, speed: float = 3000) -> None: self.updateHeadPosition(x, self._head_position.y, self._head_position.z) self._controller.setHeadPosition(self, x, self._head_position.y, self._head_position.z, speed) @pyqtProperty(float) @pyqtProperty(float, float) - def setHeadY(self, y, speed = 3000): + def setHeadY(self, y: float, speed: float = 3000) -> None: self.updateHeadPosition(self._head_position.x, y, self._head_position.z) self._controller.setHeadPosition(self, self._head_position.x, y, self._head_position.z, speed) @pyqtProperty(float) @pyqtProperty(float, float) - def setHeadZ(self, z, speed = 3000): + def setHeadZ(self, z: float, speed:float = 3000) -> None: self.updateHeadPosition(self._head_position.x, self._head_position.y, z) self._controller.setHeadPosition(self, self._head_position.x, self._head_position.y, z, speed) @pyqtSlot(float, float, float) @pyqtSlot(float, float, float, float) - def moveHead(self, x = 0, y = 0, z = 0, speed = 3000): + def moveHead(self, x: float = 0, y: float = 0, z: float = 0, speed: float = 3000) -> None: self._controller.moveHead(self, x, y, z, speed) ## Pre-heats the heated bed of the printer. @@ -164,47 +165,47 @@ class PrinterOutputModel(QObject): # Celsius. # \param duration How long the bed should stay warm, in seconds. @pyqtSlot(float, float) - def preheatBed(self, temperature, duration): + def preheatBed(self, temperature: float, duration: float) -> None: self._controller.preheatBed(self, temperature, duration) @pyqtSlot() - def cancelPreheatBed(self): + def cancelPreheatBed(self) -> None: self._controller.cancelPreheatBed(self) - def getController(self): + def getController(self) -> PrinterOutputController: return self._controller @pyqtProperty(str, notify=nameChanged) - def name(self): + def name(self) -> str: return self._name - def setName(self, name): + def setName(self, name: str) -> None: self._setName(name) self.updateName(name) - def updateName(self, name): + def updateName(self, name: str) -> None: if self._name != name: self._name = name self.nameChanged.emit() ## Update the bed temperature. This only changes it locally. - def updateBedTemperature(self, temperature): + def updateBedTemperature(self, temperature: int) -> None: if self._bed_temperature != temperature: self._bed_temperature = temperature self.bedTemperatureChanged.emit() - def updateTargetBedTemperature(self, temperature): + def updateTargetBedTemperature(self, temperature: int) -> None: if self._target_bed_temperature != temperature: self._target_bed_temperature = temperature self.targetBedTemperatureChanged.emit() ## Set the target bed temperature. This ensures that it's actually sent to the remote. @pyqtSlot(int) - def setTargetBedTemperature(self, temperature): + def setTargetBedTemperature(self, temperature: int) -> None: self._controller.setTargetBedTemperature(self, temperature) self.updateTargetBedTemperature(temperature) - def updateActivePrintJob(self, print_job): + def updateActivePrintJob(self, print_job: Optional[PrintJobOutputModel]) -> None: if self._active_print_job != print_job: old_print_job = self._active_print_job @@ -216,83 +217,83 @@ class PrinterOutputModel(QObject): old_print_job.updateAssignedPrinter(None) self.activePrintJobChanged.emit() - def updateState(self, printer_state): + def updateState(self, printer_state: str) -> None: if self._printer_state != printer_state: self._printer_state = printer_state self.stateChanged.emit() @pyqtProperty(QObject, notify = activePrintJobChanged) - def activePrintJob(self): + def activePrintJob(self) -> Optional[PrintJobOutputModel]: return self._active_print_job @pyqtProperty(str, notify=stateChanged) - def state(self): + def state(self) -> str: return self._printer_state @pyqtProperty(int, notify = bedTemperatureChanged) - def bedTemperature(self): + def bedTemperature(self) -> int: return self._bed_temperature @pyqtProperty(int, notify=targetBedTemperatureChanged) - def targetBedTemperature(self): + def targetBedTemperature(self) -> int: return self._target_bed_temperature # Does the printer support pre-heating the bed at all @pyqtProperty(bool, constant=True) - def canPreHeatBed(self): + def canPreHeatBed(self) -> bool: if self._controller: return self._controller.can_pre_heat_bed return False # Does the printer support pre-heating the bed at all @pyqtProperty(bool, constant=True) - def canPreHeatHotends(self): + def canPreHeatHotends(self) -> bool: if self._controller: return self._controller.can_pre_heat_hotends return False # Does the printer support sending raw G-code at all @pyqtProperty(bool, constant=True) - def canSendRawGcode(self): + def canSendRawGcode(self) -> bool: if self._controller: return self._controller.can_send_raw_gcode return False # Does the printer support pause at all @pyqtProperty(bool, constant=True) - def canPause(self): + def canPause(self) -> bool: if self._controller: return self._controller.can_pause return False # Does the printer support abort at all @pyqtProperty(bool, constant=True) - def canAbort(self): + def canAbort(self) -> bool: if self._controller: return self._controller.can_abort return False # Does the printer support manual control at all @pyqtProperty(bool, constant=True) - def canControlManually(self): + def canControlManually(self) -> bool: if self._controller: return self._controller.can_control_manually return False # Does the printer support upgrading firmware @pyqtProperty(bool, notify = canUpdateFirmwareChanged) - def canUpdateFirmware(self): + def canUpdateFirmware(self) -> bool: if self._controller: return self._controller.can_update_firmware return False # Stub to connect UM.Signal to pyqtSignal - def _onControllerCanUpdateFirmwareChanged(self): + def _onControllerCanUpdateFirmwareChanged(self) -> None: self.canUpdateFirmwareChanged.emit() # Returns the configuration (material, variant and buildplate) of the current printer @pyqtProperty(QObject, notify = configurationChanged) - def printerConfiguration(self): + def printerConfiguration(self) -> Optional[ConfigurationModel]: if self._printer_configuration.isValid(): return self._printer_configuration return None \ No newline at end of file diff --git a/plugins/USBPrinting/AvrFirmwareUpdater.py b/plugins/USBPrinting/AvrFirmwareUpdater.py index 171c81d557..c3852c46f6 100644 --- a/plugins/USBPrinting/AvrFirmwareUpdater.py +++ b/plugins/USBPrinting/AvrFirmwareUpdater.py @@ -10,7 +10,7 @@ class AvrFirmwareUpdater(FirmwareUpdater): def __init__(self, output_device: PrinterOutputDevice) -> None: super().__init__(output_device) - def _updateFirmware(self): + def _updateFirmware(self) -> None: try: hex_file = intelHex.readHex(self._firmware_location) assert len(hex_file) > 0 diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 4813696ffe..5e18e216bc 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -99,12 +99,12 @@ class USBPrinterOutputDevice(PrinterOutputDevice): application.triggerNextExitCheck() @pyqtSlot(str) - def updateFirmware(self, file): + def updateFirmware(self, file: Any[str, QUrl]) -> None: self._firmware_updater.updateFirmware(file) ## Reset USB device settings # - def resetDeviceSettings(self): + def resetDeviceSettings(self) -> None: self._firmware_name = None ## Request the current scene to be sent to a USB-connected printer. From 6be6d6cfc322630c20db6fbfa5271967324b60d4 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 28 Sep 2018 12:49:53 +0200 Subject: [PATCH 16/34] Fixed missing typing import --- plugins/USBPrinting/USBPrinterOutputDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 5e18e216bc..c9fcdbe625 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -21,7 +21,7 @@ from serial import Serial, SerialException, SerialTimeoutException from threading import Thread, Event from time import time, sleep from queue import Queue -from typing import Union, Optional, List, cast +from typing import Union, Optional, List, cast, Any import re import functools # Used for reduce From 6ecc9366cb6ee80ad11bab33371dec7799a899ae Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 28 Sep 2018 13:06:09 +0200 Subject: [PATCH 17/34] Fix filename typos --- resources/definitions/ultimaker_original.def.json | 2 +- resources/definitions/ultimaker_original_dual.def.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/definitions/ultimaker_original.def.json b/resources/definitions/ultimaker_original.def.json index bb6a64d8dc..bb21e4b82e 100644 --- a/resources/definitions/ultimaker_original.def.json +++ b/resources/definitions/ultimaker_original.def.json @@ -20,7 +20,7 @@ "0": "ultimaker_original_extruder_0" }, "firmware_file": "MarlinUltimaker-{baudrate}.hex", - "firmware_hbk_file": "MarlinUltimaker-HKB-{baudrate}.hex" + "firmware_hbk_file": "MarlinUltimaker-HBK-{baudrate}.hex" }, "overrides": { diff --git a/resources/definitions/ultimaker_original_dual.def.json b/resources/definitions/ultimaker_original_dual.def.json index c6002ef396..1ffb6e840b 100644 --- a/resources/definitions/ultimaker_original_dual.def.json +++ b/resources/definitions/ultimaker_original_dual.def.json @@ -20,7 +20,7 @@ "1": "ultimaker_original_dual_2nd" }, "firmware_file": "MarlinUltimaker-{baudrate}-dual.hex", - "firmware_hbk_file": "MarlinUltimaker-HKB-{baudrate}-dual.hex", + "firmware_hbk_file": "MarlinUltimaker-HBK-{baudrate}-dual.hex", "first_start_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel"], "supported_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel", "UpgradeFirmware"] }, From b73a71746eb4ac44c6387388c1fac68ddcc618b7 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 28 Sep 2018 13:06:36 +0200 Subject: [PATCH 18/34] Fix missing imports --- plugins/USBPrinting/AvrFirmwareUpdater.py | 12 ++++++++++-- plugins/USBPrinting/USBPrinterOutputDevice.py | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/plugins/USBPrinting/AvrFirmwareUpdater.py b/plugins/USBPrinting/AvrFirmwareUpdater.py index c3852c46f6..ab71f70e30 100644 --- a/plugins/USBPrinting/AvrFirmwareUpdater.py +++ b/plugins/USBPrinting/AvrFirmwareUpdater.py @@ -1,10 +1,16 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. +from UM.Logger import Logger + +from cura.CuraApplication import CuraApplication from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.FirmwareUpdater import FirmwareUpdater, FirmwareUpdateState from .avr_isp import stk500v2, intelHex +from serial import SerialException + +from time import sleep class AvrFirmwareUpdater(FirmwareUpdater): def __init__(self, output_device: PrinterOutputDevice) -> None: @@ -37,10 +43,12 @@ class AvrFirmwareUpdater(FirmwareUpdater): self.setFirmwareUpdateState(FirmwareUpdateState.communication_error) try: programmer.programChip(hex_file) - except SerialException: + except SerialException as e: + Logger.log("e", "A serial port exception occured during firmware update: %s" % e) self.setFirmwareUpdateState(FirmwareUpdateState.io_error) return - except: + except Exception as e: + Logger.log("e", "An unknown exception occured during firmware update: %s" % e) self.setFirmwareUpdateState(FirmwareUpdateState.unknown_error) return diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index c9fcdbe625..9ab2a06d50 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -15,7 +15,7 @@ from cura.PrinterOutput.GenericOutputController import GenericOutputController from .AutoDetectBaudJob import AutoDetectBaudJob from .AvrFirmwareUpdater import AvrFirmwareUpdater -from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty +from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty, QUrl from serial import Serial, SerialException, SerialTimeoutException from threading import Thread, Event From 09742f0cf51769b46ac8be2402d1db9df10a5061 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 28 Sep 2018 13:09:59 +0200 Subject: [PATCH 19/34] Simplify code --- cura/Settings/GlobalStack.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cura/Settings/GlobalStack.py b/cura/Settings/GlobalStack.py index e3ae8c2deb..da1ec61254 100755 --- a/cura/Settings/GlobalStack.py +++ b/cura/Settings/GlobalStack.py @@ -218,16 +218,16 @@ class GlobalStack(CuraContainerStack): if machine_has_heated_bed: hex_file = self.getMetaDataEntry("firmware_hbk_file", hex_file) - if hex_file: - try: - return Resources.getPath(cura.CuraApplication.CuraApplication.ResourceTypes.Firmware, hex_file.format(baudrate=baudrate)) - except FileNotFoundError: - Logger.log("w", "Firmware file %s not found.", hex_file) - return "" - else: + if not hex_file: Logger.log("w", "There is no firmware for machine %s.", self.getBottom().id) return "" + try: + return Resources.getPath(cura.CuraApplication.CuraApplication.ResourceTypes.Firmware, hex_file.format(baudrate=baudrate)) + except FileNotFoundError: + Logger.log("w", "Firmware file %s not found.", hex_file) + return "" + ## private: global_stack_mime = MimeType( name = "application/x-cura-globalstack", From 9af71f2888c1de1616af67f3241c08544f0958df Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 28 Sep 2018 13:40:39 +0200 Subject: [PATCH 20/34] Fix incorrect typing and issues caused by typing --- cura/PrinterOutput/FirmwareUpdater.py | 6 +++--- cura/PrinterOutput/GenericOutputController.py | 4 ++-- cura/PrinterOutput/PrintJobOutputModel.py | 2 +- cura/PrinterOutput/PrinterOutputController.py | 6 +++--- cura/PrinterOutput/PrinterOutputModel.py | 8 ++++---- plugins/USBPrinting/USBPrinterOutputDevice.py | 4 ++-- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cura/PrinterOutput/FirmwareUpdater.py b/cura/PrinterOutput/FirmwareUpdater.py index 06e019c593..2f200118a9 100644 --- a/cura/PrinterOutput/FirmwareUpdater.py +++ b/cura/PrinterOutput/FirmwareUpdater.py @@ -9,7 +9,7 @@ from cura.CuraApplication import CuraApplication from enum import IntEnum from threading import Thread -from typing import Any +from typing import Union class FirmwareUpdater(QObject): firmwareProgressChanged = pyqtSignal() @@ -25,7 +25,7 @@ class FirmwareUpdater(QObject): self._firmware_progress = 0 self._firmware_update_state = FirmwareUpdateState.idle - def updateFirmware(self, file: Any[str, QUrl]) -> None: + def updateFirmware(self, file: Union[str, QUrl]) -> None: # the file path could be url-encoded. if file.startswith("file://"): self._firmware_location = QUrl(file).toLocalFile() @@ -60,7 +60,7 @@ class FirmwareUpdater(QObject): return self._firmware_progress @pyqtProperty(int, notify=firmwareUpdateStateChanged) - def firmwareUpdateState(self) -> FirmwareUpdateState: + def firmwareUpdateState(self) -> "FirmwareUpdateState": return self._firmware_update_state def setFirmwareUpdateState(self, state) -> None: diff --git a/cura/PrinterOutput/GenericOutputController.py b/cura/PrinterOutput/GenericOutputController.py index e6310e5bff..e26fefb520 100644 --- a/cura/PrinterOutput/GenericOutputController.py +++ b/cura/PrinterOutput/GenericOutputController.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Union from cura.PrinterOutput.PrinterOutputController import PrinterOutputController from PyQt5.QtCore import QTimer @@ -109,7 +109,7 @@ class GenericOutputController(PrinterOutputController): self.setTargetBedTemperature(self._preheat_printer, 0) self._preheat_printer.updateIsPreheating(False) - def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: int): + def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: Union[int, float]) -> None: self._output_device.sendCommand("M104 S%s T%s" % (temperature, position)) def _onTargetHotendTemperatureChanged(self): diff --git a/cura/PrinterOutput/PrintJobOutputModel.py b/cura/PrinterOutput/PrintJobOutputModel.py index 5b8cc39ad8..70878a7573 100644 --- a/cura/PrinterOutput/PrintJobOutputModel.py +++ b/cura/PrinterOutput/PrintJobOutputModel.py @@ -91,7 +91,7 @@ class PrintJobOutputModel(QObject): def assignedPrinter(self): return self._assigned_printer - def updateAssignedPrinter(self, assigned_printer: Optional[PrinterOutputModel]): + def updateAssignedPrinter(self, assigned_printer: Optional["PrinterOutputModel"]): if self._assigned_printer != assigned_printer: old_printer = self._assigned_printer self._assigned_printer = assigned_printer diff --git a/cura/PrinterOutput/PrinterOutputController.py b/cura/PrinterOutput/PrinterOutputController.py index 9a29233f95..cc7b78ac11 100644 --- a/cura/PrinterOutput/PrinterOutputController.py +++ b/cura/PrinterOutput/PrinterOutputController.py @@ -4,7 +4,7 @@ from UM.Logger import Logger from UM.Signal import Signal -from typing import Any +from typing import Union MYPY = False if MYPY: @@ -15,7 +15,7 @@ if MYPY: class PrinterOutputController: - def __init__(self, output_device: PrinterOutputDevice) -> None: + def __init__(self, output_device: "PrinterOutputDevice") -> None: self.can_pause = True self.can_abort = True self.can_pre_heat_bed = True @@ -25,7 +25,7 @@ class PrinterOutputController: self.can_update_firmware = False self._output_device = output_device - def setTargetHotendTemperature(self, printer: "PrinterOutputModel", extruder: "ExtruderOutputModel", temperature: Any[int, float]) -> None: + def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: Union[int, float]) -> None: Logger.log("w", "Set target hotend temperature not implemented in controller") def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int) -> None: diff --git a/cura/PrinterOutput/PrinterOutputModel.py b/cura/PrinterOutput/PrinterOutputModel.py index 96feef1b55..abfee41e80 100644 --- a/cura/PrinterOutput/PrinterOutputModel.py +++ b/cura/PrinterOutput/PrinterOutputModel.py @@ -172,7 +172,7 @@ class PrinterOutputModel(QObject): def cancelPreheatBed(self) -> None: self._controller.cancelPreheatBed(self) - def getController(self) -> PrinterOutputController: + def getController(self) -> "PrinterOutputController": return self._controller @pyqtProperty(str, notify=nameChanged) @@ -205,7 +205,7 @@ class PrinterOutputModel(QObject): self._controller.setTargetBedTemperature(self, temperature) self.updateTargetBedTemperature(temperature) - def updateActivePrintJob(self, print_job: Optional[PrintJobOutputModel]) -> None: + def updateActivePrintJob(self, print_job: Optional["PrintJobOutputModel"]) -> None: if self._active_print_job != print_job: old_print_job = self._active_print_job @@ -223,14 +223,14 @@ class PrinterOutputModel(QObject): self.stateChanged.emit() @pyqtProperty(QObject, notify = activePrintJobChanged) - def activePrintJob(self) -> Optional[PrintJobOutputModel]: + def activePrintJob(self) -> Optional["PrintJobOutputModel"]: return self._active_print_job @pyqtProperty(str, notify=stateChanged) def state(self) -> str: return self._printer_state - @pyqtProperty(int, notify = bedTemperatureChanged) + @pyqtProperty(int, notify=bedTemperatureChanged) def bedTemperature(self) -> int: return self._bed_temperature diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 9ab2a06d50..ebfdca2dab 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -21,7 +21,7 @@ from serial import Serial, SerialException, SerialTimeoutException from threading import Thread, Event from time import time, sleep from queue import Queue -from typing import Union, Optional, List, cast, Any +from typing import Union, Optional, List, cast import re import functools # Used for reduce @@ -99,7 +99,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): application.triggerNextExitCheck() @pyqtSlot(str) - def updateFirmware(self, file: Any[str, QUrl]) -> None: + def updateFirmware(self, file: Union[str, QUrl]) -> None: self._firmware_updater.updateFirmware(file) ## Reset USB device settings From fa5ee4c5a270111dad13803d4149ec06f49f8e20 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Fri, 28 Sep 2018 13:44:18 +0200 Subject: [PATCH 21/34] Fix typo --- .../UltimakerMachineActions/UpgradeFirmwareMachineAction.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml index 469ada7afb..1d0aabcae3 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml @@ -16,7 +16,7 @@ Cura.MachineAction anchors.fill: parent; property bool printerConnected: Cura.MachineManager.printerConnected property var activeOutputDevice: printerConnected ? Cura.MachineManager.printerOutputDevices[0] : null - property var canUpdateFirmware: activeOutputDevice ? activeOutputDevice.activePrinter.canUpdateFirmware : False + property var canUpdateFirmware: activeOutputDevice ? activeOutputDevice.activePrinter.canUpdateFirmware : false Column { From 3908781f6f7d7072f71ae7011731c62d6c6583bc Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 2 Oct 2018 17:08:39 +0200 Subject: [PATCH 22/34] Fix this sh*t Sorry, I kind of dropped the ball before. --- cura/PrinterOutput/FirmwareUpdater.py | 38 ++++++++++++++--------- plugins/USBPrinting/AvrFirmwareUpdater.py | 20 +++++++----- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/cura/PrinterOutput/FirmwareUpdater.py b/cura/PrinterOutput/FirmwareUpdater.py index 2f200118a9..88169b1d75 100644 --- a/cura/PrinterOutput/FirmwareUpdater.py +++ b/cura/PrinterOutput/FirmwareUpdater.py @@ -16,6 +16,8 @@ class FirmwareUpdater(QObject): firmwareUpdateStateChanged = pyqtSignal() def __init__(self, output_device: PrinterOutputDevice) -> None: + super().__init__() + self._output_device = output_device self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) @@ -31,29 +33,35 @@ class FirmwareUpdater(QObject): self._firmware_location = QUrl(file).toLocalFile() else: self._firmware_location = file - self.showFirmwareInterface() - self.setFirmwareUpdateState(FirmwareUpdateState.updating) + self._showFirmwareInterface() + self._setFirmwareUpdateState(FirmwareUpdateState.updating) + self._update_firmware_thread.start() def _updateFirmware(self) -> None: raise NotImplementedError("_updateFirmware needs to be implemented") - def cleanupAfterUpdate(self) -> None: + ## Show firmware interface. + # This will create the view if its not already created. + def _showFirmwareInterface(self) -> None: + if self._firmware_view is None: + path = Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "FirmwareUpdateWindow.qml") + self._firmware_view = CuraApplication.getInstance().createQmlComponent(path, {"manager": self}) + + if not self._firmware_view: + return + + self._onFirmwareProgress(0) + self._setFirmwareUpdateState(FirmwareUpdateState.idle) + self._firmware_view.show() + + ## Cleanup after a succesful update + def _cleanupAfterUpdate(self) -> None: # Clean up for next attempt. self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) self._firmware_location = "" self._onFirmwareProgress(100) - self.setFirmwareUpdateState(FirmwareUpdateState.completed) - - ## Show firmware interface. - # This will create the view if its not already created. - def showFirmwareInterface(self) -> None: - if self._firmware_view is None: - path = Resources.getPath(self.ResourceTypes.QmlFiles, "FirmwareUpdateWindow.qml") - self._firmware_view = CuraApplication.getInstance().createQmlComponent(path, {"manager": self}) - - if self._firmware_view: - self._firmware_view.show() + self._setFirmwareUpdateState(FirmwareUpdateState.completed) @pyqtProperty(float, notify = firmwareProgressChanged) def firmwareProgress(self) -> float: @@ -63,7 +71,7 @@ class FirmwareUpdater(QObject): def firmwareUpdateState(self) -> "FirmwareUpdateState": return self._firmware_update_state - def setFirmwareUpdateState(self, state) -> None: + def _setFirmwareUpdateState(self, state) -> None: if self._firmware_update_state != state: self._firmware_update_state = state self.firmwareUpdateStateChanged.emit() diff --git a/plugins/USBPrinting/AvrFirmwareUpdater.py b/plugins/USBPrinting/AvrFirmwareUpdater.py index ab71f70e30..505e1ddb7e 100644 --- a/plugins/USBPrinting/AvrFirmwareUpdater.py +++ b/plugins/USBPrinting/AvrFirmwareUpdater.py @@ -22,39 +22,43 @@ class AvrFirmwareUpdater(FirmwareUpdater): assert len(hex_file) > 0 except (FileNotFoundError, AssertionError): Logger.log("e", "Unable to read provided hex file. Could not update firmware.") - self.setFirmwareUpdateState(FirmwareUpdateState.firmware_not_found_error) + self._setFirmwareUpdateState(FirmwareUpdateState.firmware_not_found_error) return programmer = stk500v2.Stk500v2() programmer.progress_callback = self._onFirmwareProgress + # Ensure that other connections are closed. + if self._output_device.isConnected(): + self._output_device.close() + try: - programmer.connect(self._serial_port) + programmer.connect(self._output_device._serial_port) except: programmer.close() Logger.logException("e", "Failed to update firmware") - self.setFirmwareUpdateState(FirmwareUpdateState.communication_error) + self._setFirmwareUpdateState(FirmwareUpdateState.communication_error) return # Give programmer some time to connect. Might need more in some cases, but this worked in all tested cases. sleep(1) if not programmer.isConnected(): Logger.log("e", "Unable to connect with serial. Could not update firmware") - self.setFirmwareUpdateState(FirmwareUpdateState.communication_error) + self._setFirmwareUpdateState(FirmwareUpdateState.communication_error) try: programmer.programChip(hex_file) except SerialException as e: Logger.log("e", "A serial port exception occured during firmware update: %s" % e) - self.setFirmwareUpdateState(FirmwareUpdateState.io_error) + self._setFirmwareUpdateState(FirmwareUpdateState.io_error) return except Exception as e: Logger.log("e", "An unknown exception occured during firmware update: %s" % e) - self.setFirmwareUpdateState(FirmwareUpdateState.unknown_error) + self._setFirmwareUpdateState(FirmwareUpdateState.unknown_error) return programmer.close() # Try to re-connect with the machine again, which must be done on the Qt thread, so we use call later. - CuraApplication.getInstance().callLater(self.connect) + CuraApplication.getInstance().callLater(self._output_device.connect) - self.cleanupAfterUpdate() + self._cleanupAfterUpdate() From b4e186ce789c920ab4a1387910ea4a89ad3ce843 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 2 Oct 2018 17:14:22 +0200 Subject: [PATCH 23/34] Disable close button while updating firmware --- resources/qml/FirmwareUpdateWindow.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/qml/FirmwareUpdateWindow.qml b/resources/qml/FirmwareUpdateWindow.qml index e0f9de314e..c71d70fc97 100644 --- a/resources/qml/FirmwareUpdateWindow.qml +++ b/resources/qml/FirmwareUpdateWindow.qml @@ -82,7 +82,7 @@ UM.Dialog Button { text: catalog.i18nc("@action:button","Close"); - enabled: manager.firmwareUpdateCompleteStatus; + enabled: manager.firmwareUpdateState != 1; onClicked: base.visible = false; } ] From 718ac0a30731dec368422b5d230945ee09f5595e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 3 Oct 2018 09:17:51 +0200 Subject: [PATCH 24/34] Create firmware update progress window from QML --- cura/PrinterOutput/FirmwareUpdater.py | 27 +---- cura/PrinterOutputDevice.py | 7 +- .../UpgradeFirmwareMachineAction.py | 43 ++++++- .../UpgradeFirmwareMachineAction.qml | 107 ++++++++++++++++-- resources/qml/FirmwareUpdateWindow.qml | 89 --------------- 5 files changed, 151 insertions(+), 122 deletions(-) delete mode 100644 resources/qml/FirmwareUpdateWindow.qml diff --git a/cura/PrinterOutput/FirmwareUpdater.py b/cura/PrinterOutput/FirmwareUpdater.py index 88169b1d75..92e92437ad 100644 --- a/cura/PrinterOutput/FirmwareUpdater.py +++ b/cura/PrinterOutput/FirmwareUpdater.py @@ -3,26 +3,25 @@ from PyQt5.QtCore import QObject, QUrl, pyqtSignal, pyqtProperty -from UM.Resources import Resources -from cura.PrinterOutputDevice import PrinterOutputDevice -from cura.CuraApplication import CuraApplication - from enum import IntEnum from threading import Thread from typing import Union +MYPY = False +if MYPY: + from cura.PrinterOutputDevice import PrinterOutputDevice + class FirmwareUpdater(QObject): firmwareProgressChanged = pyqtSignal() firmwareUpdateStateChanged = pyqtSignal() - def __init__(self, output_device: PrinterOutputDevice) -> None: + def __init__(self, output_device: "PrinterOutputDevice") -> None: super().__init__() self._output_device = output_device self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) - self._firmware_view = None self._firmware_location = "" self._firmware_progress = 0 self._firmware_update_state = FirmwareUpdateState.idle @@ -33,7 +32,7 @@ class FirmwareUpdater(QObject): self._firmware_location = QUrl(file).toLocalFile() else: self._firmware_location = file - self._showFirmwareInterface() + self._setFirmwareUpdateState(FirmwareUpdateState.updating) self._update_firmware_thread.start() @@ -41,20 +40,6 @@ class FirmwareUpdater(QObject): def _updateFirmware(self) -> None: raise NotImplementedError("_updateFirmware needs to be implemented") - ## Show firmware interface. - # This will create the view if its not already created. - def _showFirmwareInterface(self) -> None: - if self._firmware_view is None: - path = Resources.getPath(CuraApplication.ResourceTypes.QmlFiles, "FirmwareUpdateWindow.qml") - self._firmware_view = CuraApplication.getInstance().createQmlComponent(path, {"manager": self}) - - if not self._firmware_view: - return - - self._onFirmwareProgress(0) - self._setFirmwareUpdateState(FirmwareUpdateState.idle) - self._firmware_view.show() - ## Cleanup after a succesful update def _cleanupAfterUpdate(self) -> None: # Clean up for next attempt. diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index 5ea65adb8e..c63f9c35b5 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -20,6 +20,7 @@ MYPY = False if MYPY: from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.ConfigurationModel import ConfigurationModel + from cura.PrinterOutput.FirmwareUpdater import FirmwareUpdater i18n_catalog = i18nCatalog("cura") @@ -83,6 +84,7 @@ class PrinterOutputDevice(QObject, OutputDevice): self._connection_state = ConnectionState.closed #type: ConnectionState + self._firmware_updater = None #type: Optional[FirmwareUpdater] self._firmware_name = None #type: Optional[str] self._address = "" #type: str self._connection_text = "" #type: str @@ -225,4 +227,7 @@ class PrinterOutputDevice(QObject, OutputDevice): # # This name can be used to define device type def getFirmwareName(self) -> Optional[str]: - return self._firmware_name \ No newline at end of file + return self._firmware_name + + def getFirmwareUpdater(self) -> Optional["FirmwareUpdater"]: + return self._firmware_updater \ No newline at end of file diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py index 1f0e640f04..671ed22d5a 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py @@ -1,19 +1,58 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + from UM.Application import Application from UM.Settings.DefinitionContainer import DefinitionContainer from cura.MachineAction import MachineAction from UM.i18n import i18nCatalog from UM.Settings.ContainerRegistry import ContainerRegistry +from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject +from typing import Optional + +MYPY = False +if MYPY: + from cura.PrinterOutput.FirmwareUpdater import FirmwareUpdater + catalog = i18nCatalog("cura") ## Upgrade the firmware of a machine by USB with this action. class UpgradeFirmwareMachineAction(MachineAction): - def __init__(self): + def __init__(self) -> None: super().__init__("UpgradeFirmware", catalog.i18nc("@action", "Upgrade Firmware")) self._qml_url = "UpgradeFirmwareMachineAction.qml" ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded) - def _onContainerAdded(self, container): + self._active_output_device = None + + Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated) + + def _onEngineCreated(self) -> None: + Application.getInstance().getMachineManager().outputDevicesChanged.connect(self._onOutputDevicesChanged) + + def _onContainerAdded(self, container) -> None: # Add this action as a supported action to all machine definitions if they support USB connection if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine" and container.getMetaDataEntry("supports_usb_connection"): Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey()) + + def _onOutputDevicesChanged(self) -> None: + if self._active_output_device: + self._active_output_device.activePrinter.getController().canUpdateFirmwareChanged.disconnect(self._onControllerCanUpdateFirmwareChanged) + output_devices = Application.getInstance().getMachineManager().printerOutputDevices + print(output_devices) + self._active_output_device = output_devices[0] if output_devices else None + if self._active_output_device: + self._active_output_device.activePrinter.getController().canUpdateFirmwareChanged.connect(self._onControllerCanUpdateFirmwareChanged) + + self.outputDeviceCanUpdateFirmwareChanged.emit() + + def _onControllerCanUpdateFirmwareChanged(self) -> None: + self.outputDeviceCanUpdateFirmwareChanged.emit() + + outputDeviceCanUpdateFirmwareChanged = pyqtSignal() + @pyqtProperty(QObject, notify = outputDeviceCanUpdateFirmwareChanged) + def firmwareUpdater(self) -> Optional["firmwareUpdater"]: + if self._active_output_device and self._active_output_device.activePrinter.getController().can_update_firmware: + return self._active_output_device.getFirmwareUpdater() + + return None \ No newline at end of file diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml index 1d0aabcae3..1c1f39edd0 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Ultimaker B.V. +// Copyright (c) 2018 Ultimaker B.V. // Cura is released under the terms of the LGPLv3 or higher. import QtQuick 2.2 @@ -59,7 +59,8 @@ Cura.MachineAction enabled: parent.firmwareName != "" && canUpdateFirmware onClicked: { - activeOutputDevice.updateFirmware(parent.firmwareName) + firmwareUpdateWindow.visible = true; + activeOutputDevice.updateFirmware(parent.firmwareName); } } Button @@ -78,7 +79,7 @@ Cura.MachineAction { width: parent.width wrapMode: Text.WordWrap - visible: !printerConnected + visible: !printerConnected && !firmwareUpdateWindow.visible text: catalog.i18nc("@label", "Firmware can not be upgraded because there is no connection with the printer."); } @@ -89,14 +90,102 @@ Cura.MachineAction visible: printerConnected && !canUpdateFirmware text: catalog.i18nc("@label", "Firmware can not be upgraded because the connection with the printer does not support upgrading firmware."); } + } - FileDialog + FileDialog + { + id: customFirmwareDialog + title: catalog.i18nc("@title:window", "Select custom firmware") + nameFilters: "Firmware image files (*.hex)" + selectExisting: true + onAccepted: { - id: customFirmwareDialog - title: catalog.i18nc("@title:window", "Select custom firmware") - nameFilters: "Firmware image files (*.hex)" - selectExisting: true - onAccepted: activeOutputDevice.updateFirmware(fileUrl) + firmwareUpdateWindow.visible = true; + activeOutputDevice.updateFirmware(fileUrl); } } + + UM.Dialog + { + id: firmwareUpdateWindow + + width: minimumWidth + minimumWidth: 500 * screenScaleFactor + height: minimumHeight + minimumHeight: 100 * screenScaleFactor + + modality: Qt.ApplicationModal + + title: catalog.i18nc("@title:window","Firmware Update") + + Column + { + anchors.fill: parent + + Label + { + anchors + { + left: parent.left + right: parent.right + } + + text: { + if(manager.firmwareUpdater == null) + { + return ""; + } + switch (manager.firmwareUpdater.firmwareUpdateState) + { + case 0: + return ""; //Not doing anything (eg; idling) + case 1: + return catalog.i18nc("@label","Updating firmware."); + case 2: + return catalog.i18nc("@label","Firmware update completed."); + case 3: + return catalog.i18nc("@label","Firmware update failed due to an unknown error."); + case 4: + return catalog.i18nc("@label","Firmware update failed due to an communication error."); + case 5: + return catalog.i18nc("@label","Firmware update failed due to an input/output error."); + case 6: + return catalog.i18nc("@label","Firmware update failed due to missing firmware."); + } + } + + wrapMode: Text.Wrap + } + + ProgressBar + { + id: prog + value: (manager.firmwareUpdater != null) ? manager.firmwareUpdater.firmwareProgress : 0 + minimumValue: 0 + maximumValue: 100 + indeterminate: + { + if(manager.firmwareUpdater == null) + { + return false; + } + return manager.firmwareUpdater.firmwareProgress < 1 && manager.firmwareUpdater.firmwareProgress > 0; + } + anchors + { + left: parent.left; + right: parent.right; + } + } + } + + rightButtons: [ + Button + { + text: catalog.i18nc("@action:button","Close"); + enabled: (manager.firmwareUpdater != null) ? manager.firmwareUpdater.firmwareUpdateState != 1 : true; + onClicked: firmwareUpdateWindow.visible = false; + } + ] + } } \ No newline at end of file diff --git a/resources/qml/FirmwareUpdateWindow.qml b/resources/qml/FirmwareUpdateWindow.qml deleted file mode 100644 index c71d70fc97..0000000000 --- a/resources/qml/FirmwareUpdateWindow.qml +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 2017 Ultimaker B.V. -// Cura is released under the terms of the LGPLv3 or higher. - -import QtQuick 2.2 -import QtQuick.Window 2.2 -import QtQuick.Controls 1.2 - -import UM 1.1 as UM - -UM.Dialog -{ - id: base; - - width: minimumWidth; - minimumWidth: 500 * screenScaleFactor; - height: minimumHeight; - minimumHeight: 100 * screenScaleFactor; - - visible: true; - modality: Qt.ApplicationModal; - - title: catalog.i18nc("@title:window","Firmware Update"); - - Column - { - anchors.fill: parent; - - Label - { - anchors - { - left: parent.left; - right: parent.right; - } - - text: { - switch (manager.firmwareUpdateState) - { - case 0: - return "" //Not doing anything (eg; idling) - case 1: - return catalog.i18nc("@label","Updating firmware.") - case 2: - return catalog.i18nc("@label","Firmware update completed.") - case 3: - return catalog.i18nc("@label","Firmware update failed due to an unknown error.") - case 4: - return catalog.i18nc("@label","Firmware update failed due to an communication error.") - case 5: - return catalog.i18nc("@label","Firmware update failed due to an input/output error.") - case 6: - return catalog.i18nc("@label","Firmware update failed due to missing firmware.") - } - } - - wrapMode: Text.Wrap; - } - - ProgressBar - { - id: prog - value: manager.firmwareProgress - minimumValue: 0 - maximumValue: 100 - indeterminate: manager.firmwareProgress < 1 && manager.firmwareProgress > 0 - anchors - { - left: parent.left; - right: parent.right; - } - } - - SystemPalette - { - id: palette; - } - - UM.I18nCatalog { id: catalog; name: "cura"; } - } - - rightButtons: [ - Button - { - text: catalog.i18nc("@action:button","Close"); - enabled: manager.firmwareUpdateState != 1; - onClicked: base.visible = false; - } - ] -} From cf3d7df8a6998c9982b1a2a1e5136898c96e0b2e Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 3 Oct 2018 13:59:46 +0200 Subject: [PATCH 25/34] Fix showing progress --- .../UpgradeFirmwareMachineAction.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py index 671ed22d5a..478ea9b6bb 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py @@ -6,6 +6,7 @@ from UM.Settings.DefinitionContainer import DefinitionContainer from cura.MachineAction import MachineAction from UM.i18n import i18nCatalog from UM.Settings.ContainerRegistry import ContainerRegistry +from cura.PrinterOutput.FirmwareUpdater import FirmwareUpdateState from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject from typing import Optional @@ -13,6 +14,7 @@ from typing import Optional MYPY = False if MYPY: from cura.PrinterOutput.FirmwareUpdater import FirmwareUpdater + from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice catalog = i18nCatalog("cura") @@ -23,7 +25,8 @@ class UpgradeFirmwareMachineAction(MachineAction): self._qml_url = "UpgradeFirmwareMachineAction.qml" ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded) - self._active_output_device = None + self._active_output_device = None #type: Optional[PrinterOutputDevice] + self._active_firmware_updater = None #type: Optional[FirmwareUpdater] Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated) @@ -38,9 +41,10 @@ class UpgradeFirmwareMachineAction(MachineAction): def _onOutputDevicesChanged(self) -> None: if self._active_output_device: self._active_output_device.activePrinter.getController().canUpdateFirmwareChanged.disconnect(self._onControllerCanUpdateFirmwareChanged) + output_devices = Application.getInstance().getMachineManager().printerOutputDevices - print(output_devices) self._active_output_device = output_devices[0] if output_devices else None + if self._active_output_device: self._active_output_device.activePrinter.getController().canUpdateFirmwareChanged.connect(self._onControllerCanUpdateFirmwareChanged) @@ -53,6 +57,12 @@ class UpgradeFirmwareMachineAction(MachineAction): @pyqtProperty(QObject, notify = outputDeviceCanUpdateFirmwareChanged) def firmwareUpdater(self) -> Optional["firmwareUpdater"]: if self._active_output_device and self._active_output_device.activePrinter.getController().can_update_firmware: - return self._active_output_device.getFirmwareUpdater() + self._active_firmware_updater = self._active_output_device.getFirmwareUpdater() + return self._active_firmware_updater - return None \ No newline at end of file + elif self._active_firmware_updater and self._active_firmware_updater.firmwareUpdateState not in [FirmwareUpdateState.idle, FirmwareUpdateState.completed]: + # During a firmware update, the PrinterOutputDevice is disconnected but the FirmwareUpdater is still there + return self._active_firmware_updater + + self._active_firmware_updater = None + return None From 61ffdf23d70d79857156020dcd1508496d036511 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 3 Oct 2018 14:10:02 +0200 Subject: [PATCH 26/34] Fix MYPY/typing errors --- plugins/USBPrinting/USBPrinterOutputDevice.py | 3 +++ .../UpgradeFirmwareMachineAction.py | 12 ++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 15136491f8..1fd2fdeb5c 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -100,6 +100,9 @@ class USBPrinterOutputDevice(PrinterOutputDevice): @pyqtSlot(str) def updateFirmware(self, file: Union[str, QUrl]) -> None: + if not self._firmware_updater: + return + self._firmware_updater.updateFirmware(file) ## Reset USB device settings diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py index 478ea9b6bb..8d03a15b38 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py +++ b/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from UM.Application import Application +from cura.CuraApplication import CuraApplication from UM.Settings.DefinitionContainer import DefinitionContainer from cura.MachineAction import MachineAction from UM.i18n import i18nCatalog @@ -28,21 +28,21 @@ class UpgradeFirmwareMachineAction(MachineAction): self._active_output_device = None #type: Optional[PrinterOutputDevice] self._active_firmware_updater = None #type: Optional[FirmwareUpdater] - Application.getInstance().engineCreatedSignal.connect(self._onEngineCreated) + CuraApplication.getInstance().engineCreatedSignal.connect(self._onEngineCreated) def _onEngineCreated(self) -> None: - Application.getInstance().getMachineManager().outputDevicesChanged.connect(self._onOutputDevicesChanged) + CuraApplication.getInstance().getMachineManager().outputDevicesChanged.connect(self._onOutputDevicesChanged) def _onContainerAdded(self, container) -> None: # Add this action as a supported action to all machine definitions if they support USB connection if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine" and container.getMetaDataEntry("supports_usb_connection"): - Application.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey()) + CuraApplication.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey()) def _onOutputDevicesChanged(self) -> None: if self._active_output_device: self._active_output_device.activePrinter.getController().canUpdateFirmwareChanged.disconnect(self._onControllerCanUpdateFirmwareChanged) - output_devices = Application.getInstance().getMachineManager().printerOutputDevices + output_devices = CuraApplication.getInstance().getMachineManager().printerOutputDevices self._active_output_device = output_devices[0] if output_devices else None if self._active_output_device: @@ -55,7 +55,7 @@ class UpgradeFirmwareMachineAction(MachineAction): outputDeviceCanUpdateFirmwareChanged = pyqtSignal() @pyqtProperty(QObject, notify = outputDeviceCanUpdateFirmwareChanged) - def firmwareUpdater(self) -> Optional["firmwareUpdater"]: + def firmwareUpdater(self) -> Optional["FirmwareUpdater"]: if self._active_output_device and self._active_output_device.activePrinter.getController().can_update_firmware: self._active_firmware_updater = self._active_output_device.getFirmwareUpdater() return self._active_firmware_updater From b7542a8ef8ff17491c1366e7ca5532ebc9e0c526 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 3 Oct 2018 20:55:51 +0200 Subject: [PATCH 27/34] Move Firmware Updater into a plugin of its own --- .../FirmwareUpdaterMachineAction.py} | 4 ++-- .../FirmwareUpdaterMachineAction.qml} | 18 +++++++++--------- plugins/FirmwareUpdater/__init__.py | 13 +++++++++++++ plugins/FirmwareUpdater/plugin.json | 8 ++++++++ plugins/UltimakerMachineActions/__init__.py | 5 ----- resources/bundled_packages/cura.json | 17 +++++++++++++++++ 6 files changed, 49 insertions(+), 16 deletions(-) rename plugins/{UltimakerMachineActions/UpgradeFirmwareMachineAction.py => FirmwareUpdater/FirmwareUpdaterMachineAction.py} (96%) rename plugins/{UltimakerMachineActions/UpgradeFirmwareMachineAction.qml => FirmwareUpdater/FirmwareUpdaterMachineAction.qml} (92%) create mode 100644 plugins/FirmwareUpdater/__init__.py create mode 100644 plugins/FirmwareUpdater/plugin.json diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py similarity index 96% rename from plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py rename to plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py index 8d03a15b38..4faa3abc64 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.py +++ b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py @@ -19,10 +19,10 @@ if MYPY: catalog = i18nCatalog("cura") ## Upgrade the firmware of a machine by USB with this action. -class UpgradeFirmwareMachineAction(MachineAction): +class FirmwareUpdaterMachineAction(MachineAction): def __init__(self) -> None: super().__init__("UpgradeFirmware", catalog.i18nc("@action", "Upgrade Firmware")) - self._qml_url = "UpgradeFirmwareMachineAction.qml" + self._qml_url = "FirmwareUpdaterMachineAction.qml" ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded) self._active_output_device = None #type: Optional[PrinterOutputDevice] diff --git a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml similarity index 92% rename from plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml rename to plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml index 1c1f39edd0..ab5bb89347 100644 --- a/plugins/UltimakerMachineActions/UpgradeFirmwareMachineAction.qml +++ b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml @@ -20,7 +20,7 @@ Cura.MachineAction Column { - id: upgradeFirmwareMachineAction + id: firmwareUpdaterMachineAction anchors.fill: parent; UM.I18nCatalog { id: catalog; name:"cura"} spacing: UM.Theme.getSize("default_margin").height @@ -28,7 +28,7 @@ Cura.MachineAction Label { width: parent.width - text: catalog.i18nc("@title", "Upgrade Firmware") + text: catalog.i18nc("@title", "Update Firmware") wrapMode: Text.WordWrap font.pointSize: 18 } @@ -59,7 +59,7 @@ Cura.MachineAction enabled: parent.firmwareName != "" && canUpdateFirmware onClicked: { - firmwareUpdateWindow.visible = true; + updateProgressDialog.visible = true; activeOutputDevice.updateFirmware(parent.firmwareName); } } @@ -79,8 +79,8 @@ Cura.MachineAction { width: parent.width wrapMode: Text.WordWrap - visible: !printerConnected && !firmwareUpdateWindow.visible - text: catalog.i18nc("@label", "Firmware can not be upgraded because there is no connection with the printer."); + visible: !printerConnected && !updateProgressDialog.visible + text: catalog.i18nc("@label", "Firmware can not be updated because there is no connection with the printer."); } Label @@ -88,7 +88,7 @@ Cura.MachineAction width: parent.width wrapMode: Text.WordWrap visible: printerConnected && !canUpdateFirmware - text: catalog.i18nc("@label", "Firmware can not be upgraded because the connection with the printer does not support upgrading firmware."); + text: catalog.i18nc("@label", "Firmware can not be updated because the connection with the printer does not support upgrading firmware."); } } @@ -100,14 +100,14 @@ Cura.MachineAction selectExisting: true onAccepted: { - firmwareUpdateWindow.visible = true; + updateProgressDialog.visible = true; activeOutputDevice.updateFirmware(fileUrl); } } UM.Dialog { - id: firmwareUpdateWindow + id: updateProgressDialog width: minimumWidth minimumWidth: 500 * screenScaleFactor @@ -184,7 +184,7 @@ Cura.MachineAction { text: catalog.i18nc("@action:button","Close"); enabled: (manager.firmwareUpdater != null) ? manager.firmwareUpdater.firmwareUpdateState != 1 : true; - onClicked: firmwareUpdateWindow.visible = false; + onClicked: updateProgressDialog.visible = false; } ] } diff --git a/plugins/FirmwareUpdater/__init__.py b/plugins/FirmwareUpdater/__init__.py new file mode 100644 index 0000000000..58c351a4ea --- /dev/null +++ b/plugins/FirmwareUpdater/__init__.py @@ -0,0 +1,13 @@ +# Copyright (c) 2018 Ultimaker B.V. +# Cura is released under the terms of the LGPLv3 or higher. + +from . import FirmwareUpdaterMachineAction + +def getMetaData(): + return { + } + +def register(app): + return { "machine_action": [ + FirmwareUpdaterMachineAction.FirmwareUpdaterMachineAction(), + ]} diff --git a/plugins/FirmwareUpdater/plugin.json b/plugins/FirmwareUpdater/plugin.json new file mode 100644 index 0000000000..3e09eab2b5 --- /dev/null +++ b/plugins/FirmwareUpdater/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "Firmware Updater", + "author": "Ultimaker B.V.", + "version": "1.0.0", + "description": "Provides a machine actions for updating firmware.", + "api": 5, + "i18n-catalog": "cura" +} diff --git a/plugins/UltimakerMachineActions/__init__.py b/plugins/UltimakerMachineActions/__init__.py index 495f212736..30493536ce 100644 --- a/plugins/UltimakerMachineActions/__init__.py +++ b/plugins/UltimakerMachineActions/__init__.py @@ -2,13 +2,9 @@ # Cura is released under the terms of the LGPLv3 or higher. from . import BedLevelMachineAction -from . import UpgradeFirmwareMachineAction from . import UMOUpgradeSelection from . import UM2UpgradeSelection -from UM.i18n import i18nCatalog -catalog = i18nCatalog("cura") - def getMetaData(): return { } @@ -16,7 +12,6 @@ def getMetaData(): def register(app): return { "machine_action": [ BedLevelMachineAction.BedLevelMachineAction(), - UpgradeFirmwareMachineAction.UpgradeFirmwareMachineAction(), UMOUpgradeSelection.UMOUpgradeSelection(), UM2UpgradeSelection.UM2UpgradeSelection() ]} diff --git a/resources/bundled_packages/cura.json b/resources/bundled_packages/cura.json index 7107bbe4f0..ad97f3595b 100644 --- a/resources/bundled_packages/cura.json +++ b/resources/bundled_packages/cura.json @@ -118,6 +118,23 @@ } } }, + "FirmwareUpdater": { + "package_info": { + "package_id": "FirmwareUpdater", + "package_type": "plugin", + "display_name": "Firmware Updater", + "description": "Provides a machine actions for updating firmware.", + "package_version": "1.0.0", + "sdk_version": 5, + "website": "https://ultimaker.com", + "author": { + "author_id": "Ultimaker", + "display_name": "Ultimaker B.V.", + "email": "plugins@ultimaker.com", + "website": "https://ultimaker.com" + } + } + }, "GCodeGzReader": { "package_info": { "package_id": "GCodeGzReader", From c2558f91dd26095ddb5d019f1fa07e1e5b67c1e1 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 3 Oct 2018 21:00:23 +0200 Subject: [PATCH 28/34] Remove UpgradeFirmware as supported machine action... because the plugin adds itself as a supported action --- resources/definitions/makeit_pro_l.def.json | 1 - resources/definitions/makeit_pro_m.def.json | 1 - resources/definitions/tam.def.json | 1 - resources/definitions/ultimaker2.def.json | 2 +- resources/definitions/ultimaker2_extended_plus.def.json | 1 - resources/definitions/ultimaker2_go.def.json | 1 - resources/definitions/ultimaker2_plus.def.json | 1 - resources/definitions/ultimaker_original.def.json | 2 +- resources/definitions/ultimaker_original_dual.def.json | 2 +- resources/definitions/ultimaker_original_plus.def.json | 2 +- resources/definitions/wanhao_d6.def.json | 3 --- 11 files changed, 4 insertions(+), 13 deletions(-) diff --git a/resources/definitions/makeit_pro_l.def.json b/resources/definitions/makeit_pro_l.def.json index 2f9173c90e..d40d63f97b 100644 --- a/resources/definitions/makeit_pro_l.def.json +++ b/resources/definitions/makeit_pro_l.def.json @@ -8,7 +8,6 @@ "manufacturer": "NA", "file_formats": "text/x-gcode", "has_materials": false, - "supported_actions": [ "MachineSettingsAction", "UpgradeFirmware" ], "machine_extruder_trains": { "0": "makeit_l_dual_1st", diff --git a/resources/definitions/makeit_pro_m.def.json b/resources/definitions/makeit_pro_m.def.json index 0cd7b42df3..1f0381df86 100644 --- a/resources/definitions/makeit_pro_m.def.json +++ b/resources/definitions/makeit_pro_m.def.json @@ -8,7 +8,6 @@ "manufacturer": "NA", "file_formats": "text/x-gcode", "has_materials": false, - "supported_actions": [ "MachineSettingsAction", "UpgradeFirmware" ], "machine_extruder_trains": { "0": "makeit_dual_1st", diff --git a/resources/definitions/tam.def.json b/resources/definitions/tam.def.json index 9865abedda..0ed8d657a2 100644 --- a/resources/definitions/tam.def.json +++ b/resources/definitions/tam.def.json @@ -10,7 +10,6 @@ "platform": "tam_series1.stl", "platform_offset": [-580.0, -6.23, 253.5], "has_materials": false, - "supported_actions": ["UpgradeFirmware"], "machine_extruder_trains": { "0": "tam_extruder_0" diff --git a/resources/definitions/ultimaker2.def.json b/resources/definitions/ultimaker2.def.json index f367558df0..bbe61d49fb 100644 --- a/resources/definitions/ultimaker2.def.json +++ b/resources/definitions/ultimaker2.def.json @@ -17,7 +17,7 @@ "preferred_variant_name": "0.4 mm", "exclude_materials": ["generic_hips", "generic_petg", "generic_bam", "ultimaker_bam", "generic_pva", "ultimaker_pva", "generic_tough_pla", "ultimaker_tough_pla_black", "ultimaker_tough_pla_green", "ultimaker_tough_pla_red", "ultimaker_tough_pla_white"], "first_start_actions": ["UM2UpgradeSelection"], - "supported_actions":["UM2UpgradeSelection", "UpgradeFirmware"], + "supported_actions":["UM2UpgradeSelection"], "machine_extruder_trains": { "0": "ultimaker2_extruder_0" diff --git a/resources/definitions/ultimaker2_extended_plus.def.json b/resources/definitions/ultimaker2_extended_plus.def.json index c296ecd43e..0242115057 100644 --- a/resources/definitions/ultimaker2_extended_plus.def.json +++ b/resources/definitions/ultimaker2_extended_plus.def.json @@ -10,7 +10,6 @@ "file_formats": "text/x-gcode", "platform": "ultimaker2_platform.obj", "platform_texture": "Ultimaker2ExtendedPlusbackplate.png", - "supported_actions": ["UpgradeFirmware"], "machine_extruder_trains": { "0": "ultimaker2_extended_plus_extruder_0" diff --git a/resources/definitions/ultimaker2_go.def.json b/resources/definitions/ultimaker2_go.def.json index 5301fd7db9..e2ad2b00a1 100644 --- a/resources/definitions/ultimaker2_go.def.json +++ b/resources/definitions/ultimaker2_go.def.json @@ -13,7 +13,6 @@ "platform_texture": "Ultimaker2Gobackplate.png", "platform_offset": [0, 0, 0], "first_start_actions": [], - "supported_actions": ["UpgradeFirmware"], "machine_extruder_trains": { "0": "ultimaker2_go_extruder_0" diff --git a/resources/definitions/ultimaker2_plus.def.json b/resources/definitions/ultimaker2_plus.def.json index 45019789bf..bf48353f59 100644 --- a/resources/definitions/ultimaker2_plus.def.json +++ b/resources/definitions/ultimaker2_plus.def.json @@ -15,7 +15,6 @@ "has_machine_materials": true, "has_machine_quality": true, "first_start_actions": [], - "supported_actions": ["UpgradeFirmware"], "machine_extruder_trains": { "0": "ultimaker2_plus_extruder_0" diff --git a/resources/definitions/ultimaker_original.def.json b/resources/definitions/ultimaker_original.def.json index bb21e4b82e..4714fc1217 100644 --- a/resources/definitions/ultimaker_original.def.json +++ b/resources/definitions/ultimaker_original.def.json @@ -14,7 +14,7 @@ "has_machine_quality": true, "exclude_materials": ["generic_hips", "generic_petg", "generic_bam", "ultimaker_bam", "generic_pva", "ultimaker_pva", "generic_tough_pla", "ultimaker_tough_pla_black", "ultimaker_tough_pla_green", "ultimaker_tough_pla_red", "ultimaker_tough_pla_white"], "first_start_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel"], - "supported_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel", "UpgradeFirmware"], + "supported_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel"], "machine_extruder_trains": { "0": "ultimaker_original_extruder_0" diff --git a/resources/definitions/ultimaker_original_dual.def.json b/resources/definitions/ultimaker_original_dual.def.json index 1ffb6e840b..0dc1cb3d2d 100644 --- a/resources/definitions/ultimaker_original_dual.def.json +++ b/resources/definitions/ultimaker_original_dual.def.json @@ -22,7 +22,7 @@ "firmware_file": "MarlinUltimaker-{baudrate}-dual.hex", "firmware_hbk_file": "MarlinUltimaker-HBK-{baudrate}-dual.hex", "first_start_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel"], - "supported_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel", "UpgradeFirmware"] + "supported_actions": ["UMOUpgradeSelection", "UMOCheckup", "BedLevel"] }, "overrides": { diff --git a/resources/definitions/ultimaker_original_plus.def.json b/resources/definitions/ultimaker_original_plus.def.json index 46d95f8028..01523f34b7 100644 --- a/resources/definitions/ultimaker_original_plus.def.json +++ b/resources/definitions/ultimaker_original_plus.def.json @@ -12,7 +12,7 @@ "platform_texture": "UltimakerPlusbackplate.png", "quality_definition": "ultimaker_original", "first_start_actions": ["UMOCheckup", "BedLevel"], - "supported_actions": ["UMOCheckup", "BedLevel", "UpgradeFirmware"], + "supported_actions": ["UMOCheckup", "BedLevel"], "machine_extruder_trains": { "0": "ultimaker_original_plus_extruder_0" diff --git a/resources/definitions/wanhao_d6.def.json b/resources/definitions/wanhao_d6.def.json index 6164f4d016..e269615c4a 100644 --- a/resources/definitions/wanhao_d6.def.json +++ b/resources/definitions/wanhao_d6.def.json @@ -18,9 +18,6 @@ 0, -28, 0 - ], - "supported_actions": [ - "UpgradeFirmware" ] }, "overrides": { From 477862d779b5f590ec16d223e917582579c7972c Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Wed, 3 Oct 2018 23:07:37 +0200 Subject: [PATCH 29/34] Fix code style and unused imports --- plugins/FirmwareUpdater/__init__.py | 5 ++--- plugins/USBPrinting/__init__.py | 3 --- plugins/UltimakerMachineActions/__init__.py | 5 ++--- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/plugins/FirmwareUpdater/__init__.py b/plugins/FirmwareUpdater/__init__.py index 58c351a4ea..5a008d7d15 100644 --- a/plugins/FirmwareUpdater/__init__.py +++ b/plugins/FirmwareUpdater/__init__.py @@ -4,10 +4,9 @@ from . import FirmwareUpdaterMachineAction def getMetaData(): - return { - } + return {} def register(app): return { "machine_action": [ - FirmwareUpdaterMachineAction.FirmwareUpdaterMachineAction(), + FirmwareUpdaterMachineAction.FirmwareUpdaterMachineAction() ]} diff --git a/plugins/USBPrinting/__init__.py b/plugins/USBPrinting/__init__.py index 0cb68d3865..075ad2943b 100644 --- a/plugins/USBPrinting/__init__.py +++ b/plugins/USBPrinting/__init__.py @@ -2,9 +2,6 @@ # Cura is released under the terms of the LGPLv3 or higher. from . import USBPrinterOutputDeviceManager -from PyQt5.QtQml import qmlRegisterSingletonType -from UM.i18n import i18nCatalog -i18n_catalog = i18nCatalog("cura") def getMetaData(): diff --git a/plugins/UltimakerMachineActions/__init__.py b/plugins/UltimakerMachineActions/__init__.py index 30493536ce..e87949580a 100644 --- a/plugins/UltimakerMachineActions/__init__.py +++ b/plugins/UltimakerMachineActions/__init__.py @@ -1,4 +1,4 @@ -# Copyright (c) 2016 Ultimaker B.V. +# Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. from . import BedLevelMachineAction @@ -6,8 +6,7 @@ from . import UMOUpgradeSelection from . import UM2UpgradeSelection def getMetaData(): - return { - } + return {} def register(app): return { "machine_action": [ From 28dc32adaba8e9bae6361ba06fb0872b4a275530 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 4 Oct 2018 11:47:51 +0200 Subject: [PATCH 30/34] Fix typing in GenericOutputController --- cura/PrinterOutput/GenericOutputController.py | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/cura/PrinterOutput/GenericOutputController.py b/cura/PrinterOutput/GenericOutputController.py index c8caa85caf..9434feea62 100644 --- a/cura/PrinterOutput/GenericOutputController.py +++ b/cura/PrinterOutput/GenericOutputController.py @@ -1,7 +1,7 @@ # Copyright (c) 2018 Ultimaker B.V. # Cura is released under the terms of the LGPLv3 or higher. -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING, Set, Union, Optional from cura.PrinterOutput.PrinterOutputController import PrinterOutputController from PyQt5.QtCore import QTimer @@ -9,27 +9,28 @@ from PyQt5.QtCore import QTimer if TYPE_CHECKING: from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel + from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel class GenericOutputController(PrinterOutputController): - def __init__(self, output_device): + def __init__(self, output_device: "PrinterOutputDevice") -> None: super().__init__(output_device) self._preheat_bed_timer = QTimer() self._preheat_bed_timer.setSingleShot(True) self._preheat_bed_timer.timeout.connect(self._onPreheatBedTimerFinished) - self._preheat_printer = None + self._preheat_printer = None #type: Optional[PrinterOutputModel] self._preheat_hotends_timer = QTimer() self._preheat_hotends_timer.setSingleShot(True) self._preheat_hotends_timer.timeout.connect(self._onPreheatHotendsTimerFinished) - self._preheat_hotends = set() + self._preheat_hotends = set() #type: Set[ExtruderOutputModel] self._output_device.printersChanged.connect(self._onPrintersChanged) - self._active_printer = None + self._active_printer = None #type: Optional[PrinterOutputModel] - def _onPrintersChanged(self): + def _onPrintersChanged(self) -> None: if self._active_printer: self._active_printer.stateChanged.disconnect(self._onPrinterStateChanged) self._active_printer.targetBedTemperatureChanged.disconnect(self._onTargetBedTemperatureChanged) @@ -43,32 +44,33 @@ class GenericOutputController(PrinterOutputController): for extruder in self._active_printer.extruders: extruder.targetHotendTemperatureChanged.connect(self._onTargetHotendTemperatureChanged) - def _onPrinterStateChanged(self): - if self._active_printer.state != "idle": + def _onPrinterStateChanged(self) -> None: + if self._active_printer and self._active_printer.state != "idle": if self._preheat_bed_timer.isActive(): self._preheat_bed_timer.stop() - self._preheat_printer.updateIsPreheating(False) + if self._preheat_printer: + self._preheat_printer.updateIsPreheating(False) if self._preheat_hotends_timer.isActive(): self._preheat_hotends_timer.stop() for extruder in self._preheat_hotends: extruder.updateIsPreheating(False) - self._preheat_hotends = set() + self._preheat_hotends = set() #type: Set[ExtruderOutputModel] - def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed): + def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed) -> None: self._output_device.sendCommand("G91") self._output_device.sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed)) self._output_device.sendCommand("G90") - def homeHead(self, printer): + def homeHead(self, printer: "PrinterOutputModel") -> None: self._output_device.sendCommand("G28 X Y") - def homeBed(self, printer): + def homeBed(self, printer: "PrinterOutputModel") -> None: self._output_device.sendCommand("G28 Z") - def sendRawCommand(self, printer: "PrinterOutputModel", command: str): + def sendRawCommand(self, printer: "PrinterOutputModel", command: str) -> None: self._output_device.sendCommand(command.upper()) #Most printers only understand uppercase g-code commands. - def setJobState(self, job: "PrintJobOutputModel", state: str): + def setJobState(self, job: "PrintJobOutputModel", state: str) -> None: if state == "pause": self._output_device.pausePrint() job.updateState("paused") @@ -79,15 +81,15 @@ class GenericOutputController(PrinterOutputController): self._output_device.cancelPrint() pass - def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int): + def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: int) -> None: self._output_device.sendCommand("M140 S%s" % temperature) - def _onTargetBedTemperatureChanged(self): - if self._preheat_bed_timer.isActive() and self._preheat_printer.targetBedTemperature == 0: + def _onTargetBedTemperatureChanged(self) -> None: + if self._preheat_bed_timer.isActive() and self._preheat_printer and self._preheat_printer.targetBedTemperature == 0: self._preheat_bed_timer.stop() self._preheat_printer.updateIsPreheating(False) - def preheatBed(self, printer: "PrinterOutputModel", temperature, duration): + def preheatBed(self, printer: "PrinterOutputModel", temperature, duration) -> None: try: temperature = round(temperature) # The API doesn't allow floating point. duration = round(duration) @@ -100,21 +102,25 @@ class GenericOutputController(PrinterOutputController): self._preheat_printer = printer printer.updateIsPreheating(True) - def cancelPreheatBed(self, printer: "PrinterOutputModel"): + def cancelPreheatBed(self, printer: "PrinterOutputModel") -> None: self.setTargetBedTemperature(printer, temperature=0) self._preheat_bed_timer.stop() printer.updateIsPreheating(False) - def _onPreheatBedTimerFinished(self): + def _onPreheatBedTimerFinished(self) -> None: + if not self._preheat_printer: + return self.setTargetBedTemperature(self._preheat_printer, 0) self._preheat_printer.updateIsPreheating(False) def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: Union[int, float]) -> None: self._output_device.sendCommand("M104 S%s T%s" % (temperature, position)) - def _onTargetHotendTemperatureChanged(self): + def _onTargetHotendTemperatureChanged(self) -> None: if not self._preheat_hotends_timer.isActive(): return + if not self._active_printer: + return for extruder in self._active_printer.extruders: if extruder in self._preheat_hotends and extruder.targetHotendTemperature == 0: @@ -123,7 +129,7 @@ class GenericOutputController(PrinterOutputController): if not self._preheat_hotends: self._preheat_hotends_timer.stop() - def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration): + def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration) -> None: position = extruder.getPosition() number_of_extruders = len(extruder.getPrinter().extruders) if position >= number_of_extruders: @@ -141,7 +147,7 @@ class GenericOutputController(PrinterOutputController): self._preheat_hotends.add(extruder) extruder.updateIsPreheating(True) - def cancelPreheatHotend(self, extruder: "ExtruderOutputModel"): + def cancelPreheatHotend(self, extruder: "ExtruderOutputModel") -> None: self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), temperature=0) if extruder in self._preheat_hotends: extruder.updateIsPreheating(False) @@ -149,21 +155,22 @@ class GenericOutputController(PrinterOutputController): if not self._preheat_hotends and self._preheat_hotends_timer.isActive(): self._preheat_hotends_timer.stop() - def _onPreheatHotendsTimerFinished(self): + def _onPreheatHotendsTimerFinished(self) -> None: for extruder in self._preheat_hotends: self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0) - self._preheat_hotends = set() + self._preheat_hotends = set() #type: Set[ExtruderOutputModel] # Cancel any ongoing preheating timers, without setting back the temperature to 0 # This can be used eg at the start of a print - def stopPreheatTimers(self): + def stopPreheatTimers(self) -> None: if self._preheat_hotends_timer.isActive(): for extruder in self._preheat_hotends: extruder.updateIsPreheating(False) - self._preheat_hotends = set() + self._preheat_hotends = set() #type: Set[ExtruderOutputModel] self._preheat_hotends_timer.stop() if self._preheat_bed_timer.isActive(): - self._preheat_printer.updateIsPreheating(False) + if self._preheat_printer: + self._preheat_printer.updateIsPreheating(False) self._preheat_bed_timer.stop() From 5b2dc804cac706537f7daf5bd0d6c24bf4e3b5d8 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 4 Oct 2018 12:32:42 +0200 Subject: [PATCH 31/34] Fix a crash when adding a printer part of a cluster --- plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py index 4faa3abc64..4a172b6557 100644 --- a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py +++ b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py @@ -39,13 +39,13 @@ class FirmwareUpdaterMachineAction(MachineAction): CuraApplication.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey()) def _onOutputDevicesChanged(self) -> None: - if self._active_output_device: + if self._active_output_device and self._active_output_device.activePrinter: self._active_output_device.activePrinter.getController().canUpdateFirmwareChanged.disconnect(self._onControllerCanUpdateFirmwareChanged) output_devices = CuraApplication.getInstance().getMachineManager().printerOutputDevices self._active_output_device = output_devices[0] if output_devices else None - if self._active_output_device: + if self._active_output_device and self._active_output_device.activePrinter: self._active_output_device.activePrinter.getController().canUpdateFirmwareChanged.connect(self._onControllerCanUpdateFirmwareChanged) self.outputDeviceCanUpdateFirmwareChanged.emit() From 04bca109ba67404081f069da488832c027a51571 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Thu, 4 Oct 2018 12:48:35 +0200 Subject: [PATCH 32/34] Fix update/upgrade consistency --- plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py index 4a172b6557..981fb819eb 100644 --- a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py +++ b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py @@ -21,7 +21,7 @@ catalog = i18nCatalog("cura") ## Upgrade the firmware of a machine by USB with this action. class FirmwareUpdaterMachineAction(MachineAction): def __init__(self) -> None: - super().__init__("UpgradeFirmware", catalog.i18nc("@action", "Upgrade Firmware")) + super().__init__("UpgradeFirmware", catalog.i18nc("@action", "Update Firmware")) self._qml_url = "FirmwareUpdaterMachineAction.qml" ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded) From a36deea651b6139f9290d585bb8945a29058c408 Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 9 Oct 2018 16:26:45 +0200 Subject: [PATCH 33/34] Move updateFirmware to PrinterOutputDevice... along with codestyle and typing fixes --- cura/PrinterOutput/FirmwareUpdater.py | 22 +++++++++---------- cura/PrinterOutput/GenericOutputController.py | 8 +++---- cura/PrinterOutput/PrintJobOutputModel.py | 2 +- cura/PrinterOutputDevice.py | 14 +++++++++--- .../FirmwareUpdaterMachineAction.py | 7 +++--- .../FirmwareUpdaterMachineAction.qml | 4 ++-- plugins/USBPrinting/USBPrinterOutputDevice.py | 11 +--------- 7 files changed, 34 insertions(+), 34 deletions(-) diff --git a/cura/PrinterOutput/FirmwareUpdater.py b/cura/PrinterOutput/FirmwareUpdater.py index 92e92437ad..c6d9513ee0 100644 --- a/cura/PrinterOutput/FirmwareUpdater.py +++ b/cura/PrinterOutput/FirmwareUpdater.py @@ -22,16 +22,16 @@ class FirmwareUpdater(QObject): self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) - self._firmware_location = "" + self._firmware_file = "" self._firmware_progress = 0 self._firmware_update_state = FirmwareUpdateState.idle - def updateFirmware(self, file: Union[str, QUrl]) -> None: + def updateFirmware(self, firmware_file: Union[str, QUrl]) -> None: # the file path could be url-encoded. - if file.startswith("file://"): - self._firmware_location = QUrl(file).toLocalFile() + if firmware_file.startswith("file://"): + self._firmware_file = QUrl(firmware_file).toLocalFile() else: - self._firmware_location = file + self._firmware_file = firmware_file self._setFirmwareUpdateState(FirmwareUpdateState.updating) @@ -44,26 +44,26 @@ class FirmwareUpdater(QObject): def _cleanupAfterUpdate(self) -> None: # Clean up for next attempt. self._update_firmware_thread = Thread(target=self._updateFirmware, daemon=True) - self._firmware_location = "" + self._firmware_file = "" self._onFirmwareProgress(100) self._setFirmwareUpdateState(FirmwareUpdateState.completed) - @pyqtProperty(float, notify = firmwareProgressChanged) - def firmwareProgress(self) -> float: + @pyqtProperty(int, notify = firmwareProgressChanged) + def firmwareProgress(self) -> int: return self._firmware_progress @pyqtProperty(int, notify=firmwareUpdateStateChanged) def firmwareUpdateState(self) -> "FirmwareUpdateState": return self._firmware_update_state - def _setFirmwareUpdateState(self, state) -> None: + def _setFirmwareUpdateState(self, state: "FirmwareUpdateState") -> None: if self._firmware_update_state != state: self._firmware_update_state = state self.firmwareUpdateStateChanged.emit() # Callback function for firmware update progress. - def _onFirmwareProgress(self, progress, max_progress = 100) -> None: - self._firmware_progress = (progress / max_progress) * 100 # Convert to scale of 0-100 + def _onFirmwareProgress(self, progress: int, max_progress: int = 100) -> None: + self._firmware_progress = int(progress * 100 / max_progress) # Convert to scale of 0-100 self.firmwareProgressChanged.emit() diff --git a/cura/PrinterOutput/GenericOutputController.py b/cura/PrinterOutput/GenericOutputController.py index 9434feea62..c538ae79f8 100644 --- a/cura/PrinterOutput/GenericOutputController.py +++ b/cura/PrinterOutput/GenericOutputController.py @@ -20,15 +20,15 @@ class GenericOutputController(PrinterOutputController): self._preheat_bed_timer = QTimer() self._preheat_bed_timer.setSingleShot(True) self._preheat_bed_timer.timeout.connect(self._onPreheatBedTimerFinished) - self._preheat_printer = None #type: Optional[PrinterOutputModel] + self._preheat_printer = None # type: Optional[PrinterOutputModel] self._preheat_hotends_timer = QTimer() self._preheat_hotends_timer.setSingleShot(True) self._preheat_hotends_timer.timeout.connect(self._onPreheatHotendsTimerFinished) - self._preheat_hotends = set() #type: Set[ExtruderOutputModel] + self._preheat_hotends = set() # type: Set[ExtruderOutputModel] self._output_device.printersChanged.connect(self._onPrintersChanged) - self._active_printer = None #type: Optional[PrinterOutputModel] + self._active_printer = None # type: Optional[PrinterOutputModel] def _onPrintersChanged(self) -> None: if self._active_printer: @@ -54,7 +54,7 @@ class GenericOutputController(PrinterOutputController): self._preheat_hotends_timer.stop() for extruder in self._preheat_hotends: extruder.updateIsPreheating(False) - self._preheat_hotends = set() #type: Set[ExtruderOutputModel] + self._preheat_hotends = set() # type: Set[ExtruderOutputModel] def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed) -> None: self._output_device.sendCommand("G91") diff --git a/cura/PrinterOutput/PrintJobOutputModel.py b/cura/PrinterOutput/PrintJobOutputModel.py index 70878a7573..1415db16bd 100644 --- a/cura/PrinterOutput/PrintJobOutputModel.py +++ b/cura/PrinterOutput/PrintJobOutputModel.py @@ -91,7 +91,7 @@ class PrintJobOutputModel(QObject): def assignedPrinter(self): return self._assigned_printer - def updateAssignedPrinter(self, assigned_printer: Optional["PrinterOutputModel"]): + def updateAssignedPrinter(self, assigned_printer: Optional["PrinterOutputModel"]) -> None: if self._assigned_printer != assigned_printer: old_printer = self._assigned_printer self._assigned_printer = assigned_printer diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index c63f9c35b5..236b658eba 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -4,7 +4,7 @@ from UM.Decorators import deprecated from UM.i18n import i18nCatalog from UM.OutputDevice.OutputDevice import OutputDevice -from PyQt5.QtCore import pyqtProperty, QObject, QTimer, pyqtSignal +from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, QTimer, QUrl from PyQt5.QtWidgets import QMessageBox from UM.Logger import Logger @@ -12,9 +12,10 @@ from UM.FileHandler.FileHandler import FileHandler #For typing. from UM.Scene.SceneNode import SceneNode #For typing. from UM.Signal import signalemitter from UM.Qt.QtApplication import QtApplication +from UM.FlameProfiler import pyqtSlot from enum import IntEnum # For the connection state tracking. -from typing import Callable, List, Optional +from typing import Callable, List, Optional, Union MYPY = False if MYPY: @@ -230,4 +231,11 @@ class PrinterOutputDevice(QObject, OutputDevice): return self._firmware_name def getFirmwareUpdater(self) -> Optional["FirmwareUpdater"]: - return self._firmware_updater \ No newline at end of file + return self._firmware_updater + + @pyqtSlot(str) + def updateFirmware(self, firmware_file: Union[str, QUrl]) -> None: + if not self._firmware_updater: + return + + self._firmware_updater.updateFirmware(firmware_file) \ No newline at end of file diff --git a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py index 981fb819eb..0a3e3a0ff0 100644 --- a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py +++ b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.py @@ -15,6 +15,7 @@ MYPY = False if MYPY: from cura.PrinterOutput.FirmwareUpdater import FirmwareUpdater from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice + from UM.Settings.ContainerInterface import ContainerInterface catalog = i18nCatalog("cura") @@ -25,15 +26,15 @@ class FirmwareUpdaterMachineAction(MachineAction): self._qml_url = "FirmwareUpdaterMachineAction.qml" ContainerRegistry.getInstance().containerAdded.connect(self._onContainerAdded) - self._active_output_device = None #type: Optional[PrinterOutputDevice] - self._active_firmware_updater = None #type: Optional[FirmwareUpdater] + self._active_output_device = None # type: Optional[PrinterOutputDevice] + self._active_firmware_updater = None # type: Optional[FirmwareUpdater] CuraApplication.getInstance().engineCreatedSignal.connect(self._onEngineCreated) def _onEngineCreated(self) -> None: CuraApplication.getInstance().getMachineManager().outputDevicesChanged.connect(self._onOutputDevicesChanged) - def _onContainerAdded(self, container) -> None: + def _onContainerAdded(self, container: "ContainerInterface") -> None: # Add this action as a supported action to all machine definitions if they support USB connection if isinstance(container, DefinitionContainer) and container.getMetaDataEntry("type") == "machine" and container.getMetaDataEntry("supports_usb_connection"): CuraApplication.getInstance().getMachineActionManager().addSupportedAction(container.getId(), self.getKey()) diff --git a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml index ab5bb89347..9a56dbb20a 100644 --- a/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml +++ b/plugins/FirmwareUpdater/FirmwareUpdaterMachineAction.qml @@ -16,7 +16,7 @@ Cura.MachineAction anchors.fill: parent; property bool printerConnected: Cura.MachineManager.printerConnected property var activeOutputDevice: printerConnected ? Cura.MachineManager.printerOutputDevices[0] : null - property var canUpdateFirmware: activeOutputDevice ? activeOutputDevice.activePrinter.canUpdateFirmware : false + property bool canUpdateFirmware: activeOutputDevice ? activeOutputDevice.activePrinter.canUpdateFirmware : false Column { @@ -51,7 +51,7 @@ Cura.MachineAction anchors.horizontalCenter: parent.horizontalCenter width: childrenRect.width spacing: UM.Theme.getSize("default_margin").width - property var firmwareName: Cura.MachineManager.activeMachine.getDefaultFirmwareName() + property string firmwareName: Cura.MachineManager.activeMachine.getDefaultFirmwareName() Button { id: autoUpgradeButton diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index 1fd2fdeb5c..b5ada76e6c 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -15,8 +15,6 @@ from cura.PrinterOutput.GenericOutputController import GenericOutputController from .AutoDetectBaudJob import AutoDetectBaudJob from .AvrFirmwareUpdater import AvrFirmwareUpdater -from PyQt5.QtCore import pyqtSlot, pyqtSignal, pyqtProperty, QUrl - from serial import Serial, SerialException, SerialTimeoutException from threading import Thread, Event from time import time, sleep @@ -98,13 +96,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice): application = CuraApplication.getInstance() application.triggerNextExitCheck() - @pyqtSlot(str) - def updateFirmware(self, file: Union[str, QUrl]) -> None: - if not self._firmware_updater: - return - - self._firmware_updater.updateFirmware(file) - ## Reset USB device settings # def resetDeviceSettings(self) -> None: @@ -169,7 +160,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice): self._baud_rate = baud_rate def connect(self): - self._firmware_name = None # after each connection ensure that the firmware name is removed + self._firmware_name = None # after each connection ensure that the firmware name is removed if self._baud_rate is None: if self._use_auto_detect: From ab7fe3138d8bdfa2e1ef1d5a91be93709896099f Mon Sep 17 00:00:00 2001 From: fieldOfView Date: Tue, 9 Oct 2018 17:06:20 +0200 Subject: [PATCH 34/34] Remove unused imports --- cura/PrinterOutputDevice.py | 6 +++--- plugins/USBPrinting/AvrFirmwareUpdater.py | 8 ++++++-- plugins/USBPrinting/USBPrinterOutputDevice.py | 4 +--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cura/PrinterOutputDevice.py b/cura/PrinterOutputDevice.py index 236b658eba..969aa3c460 100644 --- a/cura/PrinterOutputDevice.py +++ b/cura/PrinterOutputDevice.py @@ -8,8 +8,6 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, QTimer, QUrl from PyQt5.QtWidgets import QMessageBox from UM.Logger import Logger -from UM.FileHandler.FileHandler import FileHandler #For typing. -from UM.Scene.SceneNode import SceneNode #For typing. from UM.Signal import signalemitter from UM.Qt.QtApplication import QtApplication from UM.FlameProfiler import pyqtSlot @@ -22,6 +20,8 @@ if MYPY: from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel from cura.PrinterOutput.ConfigurationModel import ConfigurationModel from cura.PrinterOutput.FirmwareUpdater import FirmwareUpdater + from UM.FileHandler.FileHandler import FileHandler + from UM.Scene.SceneNode import SceneNode i18n_catalog = i18nCatalog("cura") @@ -131,7 +131,7 @@ class PrinterOutputDevice(QObject, OutputDevice): return None - def requestWrite(self, nodes: List[SceneNode], file_name: Optional[str] = None, limit_mimetypes: bool = False, file_handler: Optional[FileHandler] = None, **kwargs: str) -> None: + def requestWrite(self, nodes: List["SceneNode"], file_name: Optional[str] = None, limit_mimetypes: bool = False, file_handler: Optional["FileHandler"] = None, **kwargs: str) -> None: raise NotImplementedError("requestWrite needs to be implemented") @pyqtProperty(QObject, notify = printersChanged) diff --git a/plugins/USBPrinting/AvrFirmwareUpdater.py b/plugins/USBPrinting/AvrFirmwareUpdater.py index 505e1ddb7e..b8650e9208 100644 --- a/plugins/USBPrinting/AvrFirmwareUpdater.py +++ b/plugins/USBPrinting/AvrFirmwareUpdater.py @@ -4,7 +4,6 @@ from UM.Logger import Logger from cura.CuraApplication import CuraApplication -from cura.PrinterOutputDevice import PrinterOutputDevice from cura.PrinterOutput.FirmwareUpdater import FirmwareUpdater, FirmwareUpdateState from .avr_isp import stk500v2, intelHex @@ -12,8 +11,13 @@ from serial import SerialException from time import sleep +MYPY = False +if MYPY: + from cura.PrinterOutputDevice import PrinterOutputDevice + + class AvrFirmwareUpdater(FirmwareUpdater): - def __init__(self, output_device: PrinterOutputDevice) -> None: + def __init__(self, output_device: "PrinterOutputDevice") -> None: super().__init__(output_device) def _updateFirmware(self) -> None: diff --git a/plugins/USBPrinting/USBPrinterOutputDevice.py b/plugins/USBPrinting/USBPrinterOutputDevice.py index b5ada76e6c..4c3e7ee131 100644 --- a/plugins/USBPrinting/USBPrinterOutputDevice.py +++ b/plugins/USBPrinting/USBPrinterOutputDevice.py @@ -4,7 +4,6 @@ from UM.Logger import Logger from UM.i18n import i18nCatalog from UM.Qt.Duration import DurationFormat -from UM.PluginRegistry import PluginRegistry from cura.CuraApplication import CuraApplication from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState @@ -17,13 +16,12 @@ from .AvrFirmwareUpdater import AvrFirmwareUpdater from serial import Serial, SerialException, SerialTimeoutException from threading import Thread, Event -from time import time, sleep +from time import time from queue import Queue from typing import Union, Optional, List, cast import re import functools # Used for reduce -import os catalog = i18nCatalog("cura")