123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- # Copyright (c) 2019 Ultimaker B.V.
- # Cura is released under the terms of the LGPLv3 or higher.
- from PyQt6.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant, pyqtSlot, QUrl
- from typing import List, Dict, Optional, TYPE_CHECKING
- from UM.Math.Vector import Vector
- from cura.PrinterOutput.Peripheral import Peripheral
- from cura.PrinterOutput.Models.PrinterConfigurationModel import PrinterConfigurationModel
- from cura.PrinterOutput.Models.ExtruderOutputModel import ExtruderOutputModel
- from UM.Logger import Logger
- if TYPE_CHECKING:
- from cura.PrinterOutput.Models.PrintJobOutputModel import PrintJobOutputModel
- from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
- class PrinterOutputModel(QObject):
- bedTemperatureChanged = pyqtSignal()
- targetBedTemperatureChanged = pyqtSignal()
- isPreheatingChanged = pyqtSignal()
- stateChanged = pyqtSignal()
- activePrintJobChanged = pyqtSignal()
- nameChanged = pyqtSignal()
- headPositionChanged = pyqtSignal()
- keyChanged = pyqtSignal()
- typeChanged = pyqtSignal()
- buildplateChanged = pyqtSignal()
- cameraUrlChanged = pyqtSignal()
- configurationChanged = pyqtSignal()
- canUpdateFirmwareChanged = pyqtSignal()
- def __init__(self, output_controller: "PrinterOutputController", number_of_extruders: int = 1, parent=None, firmware_version = "") -> None:
- super().__init__(parent)
- self._bed_temperature = -1 # type: float # Use -1 for no heated bed.
- self._target_bed_temperature = 0 # type: float
- self._name = ""
- self._key = "" # Unique identifier
- self._unique_name = "" # Unique name (used in Connect)
- 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._active_printer_configuration = PrinterConfigurationModel() # Indicates the current configuration setup in this printer
- self._head_position = Vector(0, 0, 0)
- self._active_print_job = None # type: Optional[PrintJobOutputModel]
- self._firmware_version = firmware_version
- self._printer_state = "unknown"
- self._is_preheating = False
- self._printer_type = ""
- self._buildplate = ""
- self._peripherals = [] # type: List[Peripheral]
- self._active_printer_configuration.extruderConfigurations = [extruder.extruderConfiguration for extruder in
- self._extruders]
- self._active_printer_configuration.configurationChanged.connect(self.configurationChanged)
- self._available_printer_configurations = [] # type: List[PrinterConfigurationModel]
- self._camera_url = QUrl() # type: QUrl
- @pyqtProperty(str, constant = True)
- def firmwareVersion(self) -> str:
- return self._firmware_version
- def setCameraUrl(self, camera_url: "QUrl") -> None:
- if self._camera_url != camera_url:
- self._camera_url = camera_url
- self.cameraUrlChanged.emit()
- @pyqtProperty(QUrl, fset = setCameraUrl, notify = cameraUrlChanged)
- def cameraUrl(self) -> "QUrl":
- return self._camera_url
- 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) -> bool:
- return self._is_preheating
- @pyqtProperty(str, notify = typeChanged)
- def type(self) -> str:
- return self._printer_type
- def updateType(self, printer_type: str) -> None:
- if self._printer_type != printer_type:
- self._printer_type = printer_type
- self._active_printer_configuration.printerType = self._printer_type
- self.typeChanged.emit()
- self.configurationChanged.emit()
- @pyqtProperty(str, notify = buildplateChanged)
- def buildplate(self) -> str:
- return self._buildplate
- def updateBuildplate(self, buildplate: str) -> None:
- if self._buildplate != buildplate:
- self._buildplate = buildplate
- self._active_printer_configuration.buildplateConfiguration = self._buildplate
- self.buildplateChanged.emit()
- self.configurationChanged.emit()
- @pyqtProperty(str, notify=keyChanged)
- def key(self) -> str:
- return self._key
- def updateKey(self, key: str) -> None:
- if self._key != key:
- self._key = key
- self.keyChanged.emit()
- @pyqtSlot()
- def homeHead(self) -> None:
- self._controller.homeHead(self)
- @pyqtSlot()
- def homeBed(self) -> None:
- self._controller.homeBed(self)
- @pyqtSlot(str)
- def sendRawCommand(self, command: str) -> None:
- self._controller.sendRawCommand(self, command)
- @pyqtProperty("QVariantList", constant = True)
- def extruders(self) -> List["ExtruderOutputModel"]:
- return self._extruders
- @pyqtProperty(QVariant, notify = headPositionChanged)
- 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: 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: 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: 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: 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: 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: float = 0, y: float = 0, z: float = 0, speed: float = 3000) -> None:
- self._controller.moveHead(self, x, y, z, speed)
- @pyqtSlot(float, float)
- def preheatBed(self, temperature: float, duration: float) -> None:
- """Pre-heats the heated bed of the printer.
- :param temperature: The temperature to heat the bed to, in degrees
- Celsius.
- :param duration: How long the bed should stay warm, in seconds.
- """
- self._controller.preheatBed(self, temperature, duration)
- @pyqtSlot()
- def cancelPreheatBed(self) -> None:
- self._controller.cancelPreheatBed(self)
- def getController(self) -> "PrinterOutputController":
- return self._controller
- @pyqtProperty(str, notify = nameChanged)
- def name(self) -> str:
- return self._name
- def setName(self, name: str) -> None:
- self.updateName(name)
- def updateName(self, name: str) -> None:
- if self._name != name:
- self._name = name
- self.nameChanged.emit()
- @pyqtProperty(str, notify = nameChanged)
- def uniqueName(self) -> str:
- return self._unique_name
- def updateUniqueName(self, unique_name: str) -> None:
- if self._unique_name != unique_name:
- self._unique_name = unique_name
- self.nameChanged.emit()
- def updateBedTemperature(self, temperature: float) -> None:
- """Update the bed temperature. This only changes it locally."""
- if self._bed_temperature != temperature:
- self._bed_temperature = temperature
- self.bedTemperatureChanged.emit()
- def updateTargetBedTemperature(self, temperature: float) -> None:
- if self._target_bed_temperature != temperature:
- self._target_bed_temperature = temperature
- self.targetBedTemperatureChanged.emit()
- @pyqtSlot(float)
- def setTargetBedTemperature(self, temperature: float) -> None:
- """Set the target bed temperature. This ensures that it's actually sent to the remote."""
- self._controller.setTargetBedTemperature(self, temperature)
- self.updateTargetBedTemperature(temperature)
- def updateActivePrintJob(self, print_job: Optional["PrintJobOutputModel"]) -> None:
- if self._active_print_job != print_job:
- old_print_job = self._active_print_job
- if print_job is not None:
- print_job.updateAssignedPrinter(self)
- self._active_print_job = print_job
- if old_print_job is not None:
- old_print_job.updateAssignedPrinter(None)
- self.activePrintJobChanged.emit()
- 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) -> Optional["PrintJobOutputModel"]:
- return self._active_print_job
- @pyqtProperty(str, notify = stateChanged)
- def state(self) -> str:
- return self._printer_state
- @pyqtProperty(float, notify = bedTemperatureChanged)
- def bedTemperature(self) -> float:
- return self._bed_temperature
- @pyqtProperty(float, notify = targetBedTemperatureChanged)
- def targetBedTemperature(self) -> float:
- return self._target_bed_temperature
- # Does the printer support pre-heating the bed at all
- @pyqtProperty(bool, constant = True)
- 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> bool:
- if self._controller:
- return self._controller.can_update_firmware
- return False
- # Stub to connect UM.Signal to pyqtSignal
- def _onControllerCanUpdateFirmwareChanged(self) -> None:
- self.canUpdateFirmwareChanged.emit()
- # Returns the active configuration (material, variant and buildplate) of the current printer
- @pyqtProperty(QObject, notify = configurationChanged)
- def printerConfiguration(self) -> Optional[PrinterConfigurationModel]:
- if self._active_printer_configuration.isValid():
- return self._active_printer_configuration
- return None
- peripheralsChanged = pyqtSignal()
- @pyqtProperty(str, notify = peripheralsChanged)
- def peripherals(self) -> str:
- return ", ".join([peripheral.name for peripheral in self._peripherals])
- def addPeripheral(self, peripheral: Peripheral) -> None:
- self._peripherals.append(peripheral)
- self.peripheralsChanged.emit()
- def removePeripheral(self, peripheral: Peripheral) -> None:
- self._peripherals.remove(peripheral)
- self.peripheralsChanged.emit()
- availableConfigurationsChanged = pyqtSignal()
- # The availableConfigurations are configuration options that a printer can switch to, but doesn't currently have
- # active (eg; Automatic tool changes, material loaders, etc).
- @pyqtProperty("QVariantList", notify = availableConfigurationsChanged)
- def availableConfigurations(self) -> List[PrinterConfigurationModel]:
- return self._available_printer_configurations
- def addAvailableConfiguration(self, new_configuration: PrinterConfigurationModel) -> None:
- if new_configuration not in self._available_printer_configurations:
- self._available_printer_configurations.append(new_configuration)
- self.availableConfigurationsChanged.emit()
- def removeAvailableConfiguration(self, config_to_remove: PrinterConfigurationModel) -> None:
- try:
- self._available_printer_configurations.remove(config_to_remove)
- except ValueError:
- Logger.log("w", "Unable to remove configuration that isn't in the list of available configurations")
- else:
- self.availableConfigurationsChanged.emit()
- def setAvailableConfigurations(self, new_configurations: List[PrinterConfigurationModel]) -> None:
- if self._available_printer_configurations != new_configurations:
- self._available_printer_configurations = new_configurations
- self.availableConfigurationsChanged.emit()
|