PrinterOutputModel.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. # Copyright (c) 2019 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from PyQt5.QtCore import pyqtSignal, pyqtProperty, QObject, QVariant, pyqtSlot, QUrl
  4. from typing import List, Dict, Optional
  5. from UM.Math.Vector import Vector
  6. from cura.PrinterOutput.ConfigurationModel import ConfigurationModel
  7. from cura.PrinterOutput.ExtruderOutputModel import ExtruderOutputModel
  8. MYPY = False
  9. if MYPY:
  10. from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
  11. from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
  12. class PrinterOutputModel(QObject):
  13. bedTemperatureChanged = pyqtSignal()
  14. targetBedTemperatureChanged = pyqtSignal()
  15. isPreheatingChanged = pyqtSignal()
  16. stateChanged = pyqtSignal()
  17. activePrintJobChanged = pyqtSignal()
  18. nameChanged = pyqtSignal()
  19. headPositionChanged = pyqtSignal()
  20. keyChanged = pyqtSignal()
  21. typeChanged = pyqtSignal()
  22. buildplateChanged = pyqtSignal()
  23. cameraUrlChanged = pyqtSignal()
  24. configurationChanged = pyqtSignal()
  25. canUpdateFirmwareChanged = pyqtSignal()
  26. def __init__(self, output_controller: "PrinterOutputController", number_of_extruders: int = 1, parent=None, firmware_version = "") -> None:
  27. super().__init__(parent)
  28. self._bed_temperature = -1 # type: float # Use -1 for no heated bed.
  29. self._target_bed_temperature = 0 # type: float
  30. self._name = ""
  31. self._key = "" # Unique identifier
  32. self._controller = output_controller
  33. self._controller.canUpdateFirmwareChanged.connect(self._onControllerCanUpdateFirmwareChanged)
  34. self._extruders = [ExtruderOutputModel(printer = self, position = i) for i in range(number_of_extruders)]
  35. self._printer_configuration = ConfigurationModel() # Indicates the current configuration setup in this printer
  36. self._head_position = Vector(0, 0, 0)
  37. self._active_print_job = None # type: Optional[PrintJobOutputModel]
  38. self._firmware_version = firmware_version
  39. self._printer_state = "unknown"
  40. self._is_preheating = False
  41. self._printer_type = ""
  42. self._buildplate = ""
  43. self._printer_configuration.extruderConfigurations = [extruder.extruderConfiguration for extruder in
  44. self._extruders]
  45. self._camera_url = QUrl() # type: QUrl
  46. @pyqtProperty(str, constant = True)
  47. def firmwareVersion(self) -> str:
  48. return self._firmware_version
  49. def setCameraUrl(self, camera_url: "QUrl") -> None:
  50. if self._camera_url != camera_url:
  51. self._camera_url = camera_url
  52. self.cameraUrlChanged.emit()
  53. @pyqtProperty(QUrl, fset = setCameraUrl, notify = cameraUrlChanged)
  54. def cameraUrl(self) -> "QUrl":
  55. return self._camera_url
  56. def updateIsPreheating(self, pre_heating: bool) -> None:
  57. if self._is_preheating != pre_heating:
  58. self._is_preheating = pre_heating
  59. self.isPreheatingChanged.emit()
  60. @pyqtProperty(bool, notify=isPreheatingChanged)
  61. def isPreheating(self) -> bool:
  62. return self._is_preheating
  63. @pyqtProperty(str, notify = typeChanged)
  64. def type(self) -> str:
  65. return self._printer_type
  66. def updateType(self, printer_type: str) -> None:
  67. if self._printer_type != printer_type:
  68. self._printer_type = printer_type
  69. self._printer_configuration.printerType = self._printer_type
  70. self.typeChanged.emit()
  71. self.configurationChanged.emit()
  72. @pyqtProperty(str, notify = buildplateChanged)
  73. def buildplate(self) -> str:
  74. return self._buildplate
  75. def updateBuildplate(self, buildplate: str) -> None:
  76. if self._buildplate != buildplate:
  77. self._buildplate = buildplate
  78. self._printer_configuration.buildplateConfiguration = self._buildplate
  79. self.buildplateChanged.emit()
  80. self.configurationChanged.emit()
  81. @pyqtProperty(str, notify=keyChanged)
  82. def key(self) -> str:
  83. return self._key
  84. def updateKey(self, key: str) -> None:
  85. if self._key != key:
  86. self._key = key
  87. self.keyChanged.emit()
  88. @pyqtSlot()
  89. def homeHead(self) -> None:
  90. self._controller.homeHead(self)
  91. @pyqtSlot()
  92. def homeBed(self) -> None:
  93. self._controller.homeBed(self)
  94. @pyqtSlot(str)
  95. def sendRawCommand(self, command: str) -> None:
  96. self._controller.sendRawCommand(self, command)
  97. @pyqtProperty("QVariantList", constant = True)
  98. def extruders(self) -> List["ExtruderOutputModel"]:
  99. return self._extruders
  100. @pyqtProperty(QVariant, notify = headPositionChanged)
  101. def headPosition(self) -> Dict[str, float]:
  102. return {"x": self._head_position.x, "y": self._head_position.y, "z": self.head_position.z}
  103. def updateHeadPosition(self, x: float, y: float, z: float) -> None:
  104. if self._head_position.x != x or self._head_position.y != y or self._head_position.z != z:
  105. self._head_position = Vector(x, y, z)
  106. self.headPositionChanged.emit()
  107. @pyqtProperty(float, float, float)
  108. @pyqtProperty(float, float, float, float)
  109. def setHeadPosition(self, x: float, y: float, z: float, speed: float = 3000) -> None:
  110. self.updateHeadPosition(x, y, z)
  111. self._controller.setHeadPosition(self, x, y, z, speed)
  112. @pyqtProperty(float)
  113. @pyqtProperty(float, float)
  114. def setHeadX(self, x: float, speed: float = 3000) -> None:
  115. self.updateHeadPosition(x, self._head_position.y, self._head_position.z)
  116. self._controller.setHeadPosition(self, x, self._head_position.y, self._head_position.z, speed)
  117. @pyqtProperty(float)
  118. @pyqtProperty(float, float)
  119. def setHeadY(self, y: float, speed: float = 3000) -> None:
  120. self.updateHeadPosition(self._head_position.x, y, self._head_position.z)
  121. self._controller.setHeadPosition(self, self._head_position.x, y, self._head_position.z, speed)
  122. @pyqtProperty(float)
  123. @pyqtProperty(float, float)
  124. def setHeadZ(self, z: float, speed:float = 3000) -> None:
  125. self.updateHeadPosition(self._head_position.x, self._head_position.y, z)
  126. self._controller.setHeadPosition(self, self._head_position.x, self._head_position.y, z, speed)
  127. @pyqtSlot(float, float, float)
  128. @pyqtSlot(float, float, float, float)
  129. def moveHead(self, x: float = 0, y: float = 0, z: float = 0, speed: float = 3000) -> None:
  130. self._controller.moveHead(self, x, y, z, speed)
  131. ## Pre-heats the heated bed of the printer.
  132. #
  133. # \param temperature The temperature to heat the bed to, in degrees
  134. # Celsius.
  135. # \param duration How long the bed should stay warm, in seconds.
  136. @pyqtSlot(float, float)
  137. def preheatBed(self, temperature: float, duration: float) -> None:
  138. self._controller.preheatBed(self, temperature, duration)
  139. @pyqtSlot()
  140. def cancelPreheatBed(self) -> None:
  141. self._controller.cancelPreheatBed(self)
  142. def getController(self) -> "PrinterOutputController":
  143. return self._controller
  144. @pyqtProperty(str, notify = nameChanged)
  145. def name(self) -> str:
  146. return self._name
  147. def setName(self, name: str) -> None:
  148. self.updateName(name)
  149. def updateName(self, name: str) -> None:
  150. if self._name != name:
  151. self._name = name
  152. self.nameChanged.emit()
  153. ## Update the bed temperature. This only changes it locally.
  154. def updateBedTemperature(self, temperature: float) -> None:
  155. if self._bed_temperature != temperature:
  156. self._bed_temperature = temperature
  157. self.bedTemperatureChanged.emit()
  158. def updateTargetBedTemperature(self, temperature: float) -> None:
  159. if self._target_bed_temperature != temperature:
  160. self._target_bed_temperature = temperature
  161. self.targetBedTemperatureChanged.emit()
  162. ## Set the target bed temperature. This ensures that it's actually sent to the remote.
  163. @pyqtSlot(float)
  164. def setTargetBedTemperature(self, temperature: float) -> None:
  165. self._controller.setTargetBedTemperature(self, temperature)
  166. self.updateTargetBedTemperature(temperature)
  167. def updateActivePrintJob(self, print_job: Optional["PrintJobOutputModel"]) -> None:
  168. if self._active_print_job != print_job:
  169. old_print_job = self._active_print_job
  170. if print_job is not None:
  171. print_job.updateAssignedPrinter(self)
  172. self._active_print_job = print_job
  173. if old_print_job is not None:
  174. old_print_job.updateAssignedPrinter(None)
  175. self.activePrintJobChanged.emit()
  176. def updateState(self, printer_state: str) -> None:
  177. if self._printer_state != printer_state:
  178. self._printer_state = printer_state
  179. self.stateChanged.emit()
  180. @pyqtProperty(QObject, notify = activePrintJobChanged)
  181. def activePrintJob(self) -> Optional["PrintJobOutputModel"]:
  182. return self._active_print_job
  183. @pyqtProperty(str, notify = stateChanged)
  184. def state(self) -> str:
  185. return self._printer_state
  186. @pyqtProperty(float, notify = bedTemperatureChanged)
  187. def bedTemperature(self) -> float:
  188. return self._bed_temperature
  189. @pyqtProperty(float, notify = targetBedTemperatureChanged)
  190. def targetBedTemperature(self) -> float:
  191. return self._target_bed_temperature
  192. # Does the printer support pre-heating the bed at all
  193. @pyqtProperty(bool, constant = True)
  194. def canPreHeatBed(self) -> bool:
  195. if self._controller:
  196. return self._controller.can_pre_heat_bed
  197. return False
  198. # Does the printer support pre-heating the bed at all
  199. @pyqtProperty(bool, constant = True)
  200. def canPreHeatHotends(self) -> bool:
  201. if self._controller:
  202. return self._controller.can_pre_heat_hotends
  203. return False
  204. # Does the printer support sending raw G-code at all
  205. @pyqtProperty(bool, constant = True)
  206. def canSendRawGcode(self) -> bool:
  207. if self._controller:
  208. return self._controller.can_send_raw_gcode
  209. return False
  210. # Does the printer support pause at all
  211. @pyqtProperty(bool, constant = True)
  212. def canPause(self) -> bool:
  213. if self._controller:
  214. return self._controller.can_pause
  215. return False
  216. # Does the printer support abort at all
  217. @pyqtProperty(bool, constant = True)
  218. def canAbort(self) -> bool:
  219. if self._controller:
  220. return self._controller.can_abort
  221. return False
  222. # Does the printer support manual control at all
  223. @pyqtProperty(bool, constant = True)
  224. def canControlManually(self) -> bool:
  225. if self._controller:
  226. return self._controller.can_control_manually
  227. return False
  228. # Does the printer support upgrading firmware
  229. @pyqtProperty(bool, notify = canUpdateFirmwareChanged)
  230. def canUpdateFirmware(self) -> bool:
  231. if self._controller:
  232. return self._controller.can_update_firmware
  233. return False
  234. # Stub to connect UM.Signal to pyqtSignal
  235. def _onControllerCanUpdateFirmwareChanged(self) -> None:
  236. self.canUpdateFirmwareChanged.emit()
  237. # Returns the configuration (material, variant and buildplate) of the current printer
  238. @pyqtProperty(QObject, notify = configurationChanged)
  239. def printerConfiguration(self) -> Optional[ConfigurationModel]:
  240. if self._printer_configuration.isValid():
  241. return self._printer_configuration
  242. return None