PrinterOutputModel.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. # Copyright (c) 2018 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. printerTypeChanged = 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 # Use -1 for no heated bed.
  29. self._target_bed_temperature = 0
  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_name = ""
  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 = printerTypeChanged)
  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.printerTypeChanged.emit()
  71. self.configurationChanged.emit()
  72. @pyqtProperty(str, notify = buildplateChanged)
  73. def buildplate(self) -> str:
  74. return self._buildplate_name
  75. def updateBuildplateName(self, buildplate_name: str) -> None:
  76. if self._buildplate_name != buildplate_name:
  77. self._buildplate_name = buildplate_name
  78. self._printer_configuration.buildplateConfiguration = self._buildplate_name
  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._setName(name)
  149. self.updateName(name)
  150. def updateName(self, name: str) -> None:
  151. if self._name != name:
  152. self._name = name
  153. self.nameChanged.emit()
  154. ## Update the bed temperature. This only changes it locally.
  155. def updateBedTemperature(self, temperature: int) -> None:
  156. if self._bed_temperature != temperature:
  157. self._bed_temperature = temperature
  158. self.bedTemperatureChanged.emit()
  159. def updateTargetBedTemperature(self, temperature: int) -> None:
  160. if self._target_bed_temperature != temperature:
  161. self._target_bed_temperature = temperature
  162. self.targetBedTemperatureChanged.emit()
  163. ## Set the target bed temperature. This ensures that it's actually sent to the remote.
  164. @pyqtSlot(int)
  165. def setTargetBedTemperature(self, temperature: int) -> None:
  166. self._controller.setTargetBedTemperature(self, temperature)
  167. self.updateTargetBedTemperature(temperature)
  168. def updateActivePrintJob(self, print_job: Optional["PrintJobOutputModel"]) -> None:
  169. if self._active_print_job != print_job:
  170. old_print_job = self._active_print_job
  171. if print_job is not None:
  172. print_job.updateAssignedPrinter(self)
  173. self._active_print_job = print_job
  174. if old_print_job is not None:
  175. old_print_job.updateAssignedPrinter(None)
  176. self.activePrintJobChanged.emit()
  177. def updateState(self, printer_state: str) -> None:
  178. if self._printer_state != printer_state:
  179. self._printer_state = printer_state
  180. self.stateChanged.emit()
  181. @pyqtProperty(QObject, notify = activePrintJobChanged)
  182. def activePrintJob(self) -> Optional["PrintJobOutputModel"]:
  183. return self._active_print_job
  184. @pyqtProperty(str, notify=stateChanged)
  185. def state(self) -> str:
  186. return self._printer_state
  187. @pyqtProperty(int, notify=bedTemperatureChanged)
  188. def bedTemperature(self) -> int:
  189. return self._bed_temperature
  190. @pyqtProperty(int, notify=targetBedTemperatureChanged)
  191. def targetBedTemperature(self) -> int:
  192. return self._target_bed_temperature
  193. # Does the printer support pre-heating the bed at all
  194. @pyqtProperty(bool, constant=True)
  195. def canPreHeatBed(self) -> bool:
  196. if self._controller:
  197. return self._controller.can_pre_heat_bed
  198. return False
  199. # Does the printer support pre-heating the bed at all
  200. @pyqtProperty(bool, constant=True)
  201. def canPreHeatHotends(self) -> bool:
  202. if self._controller:
  203. return self._controller.can_pre_heat_hotends
  204. return False
  205. # Does the printer support sending raw G-code at all
  206. @pyqtProperty(bool, constant=True)
  207. def canSendRawGcode(self) -> bool:
  208. if self._controller:
  209. return self._controller.can_send_raw_gcode
  210. return False
  211. # Does the printer support pause at all
  212. @pyqtProperty(bool, constant=True)
  213. def canPause(self) -> bool:
  214. if self._controller:
  215. return self._controller.can_pause
  216. return False
  217. # Does the printer support abort at all
  218. @pyqtProperty(bool, constant=True)
  219. def canAbort(self) -> bool:
  220. if self._controller:
  221. return self._controller.can_abort
  222. return False
  223. # Does the printer support manual control at all
  224. @pyqtProperty(bool, constant=True)
  225. def canControlManually(self) -> bool:
  226. if self._controller:
  227. return self._controller.can_control_manually
  228. return False
  229. # Does the printer support upgrading firmware
  230. @pyqtProperty(bool, notify = canUpdateFirmwareChanged)
  231. def canUpdateFirmware(self) -> bool:
  232. if self._controller:
  233. return self._controller.can_update_firmware
  234. return False
  235. # Stub to connect UM.Signal to pyqtSignal
  236. def _onControllerCanUpdateFirmwareChanged(self) -> None:
  237. self.canUpdateFirmwareChanged.emit()
  238. # Returns the configuration (material, variant and buildplate) of the current printer
  239. @pyqtProperty(QObject, notify = configurationChanged)
  240. def printerConfiguration(self) -> Optional[ConfigurationModel]:
  241. if self._printer_configuration.isValid():
  242. return self._printer_configuration
  243. return None