PrinterOutputDevice.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. # Copyright (c) 2017 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from UM.i18n import i18nCatalog
  4. from UM.OutputDevice.OutputDevice import OutputDevice
  5. from PyQt5.QtCore import pyqtProperty, pyqtSlot, QObject, QTimer, pyqtSignal
  6. from PyQt5.QtWidgets import QMessageBox
  7. from enum import IntEnum # For the connection state tracking.
  8. from UM.Settings.ContainerRegistry import ContainerRegistry
  9. from UM.Logger import Logger
  10. from UM.Signal import signalemitter
  11. from UM.Application import Application
  12. i18n_catalog = i18nCatalog("cura")
  13. ## Printer output device adds extra interface options on top of output device.
  14. #
  15. # The assumption is made the printer is a FDM printer.
  16. #
  17. # Note that a number of settings are marked as "final". This is because decorators
  18. # are not inherited by children. To fix this we use the private counter part of those
  19. # functions to actually have the implementation.
  20. #
  21. # For all other uses it should be used in the same way as a "regular" OutputDevice.
  22. @signalemitter
  23. class PrinterOutputDevice(QObject, OutputDevice):
  24. def __init__(self, device_id, parent = None):
  25. super().__init__(device_id = device_id, parent = parent)
  26. self._container_registry = ContainerRegistry.getInstance()
  27. self._target_bed_temperature = 0
  28. self._bed_temperature = 0
  29. self._num_extruders = 1
  30. self._hotend_temperatures = [0] * self._num_extruders
  31. self._target_hotend_temperatures = [0] * self._num_extruders
  32. self._material_ids = [""] * self._num_extruders
  33. self._hotend_ids = [""] * self._num_extruders
  34. self._progress = 0
  35. self._head_x = 0
  36. self._head_y = 0
  37. self._head_z = 0
  38. self._connection_state = ConnectionState.closed
  39. self._connection_text = ""
  40. self._time_elapsed = 0
  41. self._time_total = 0
  42. self._job_state = ""
  43. self._job_name = ""
  44. self._error_text = ""
  45. self._accepts_commands = True
  46. self._preheat_bed_timeout = 900 # Default time-out for pre-heating the bed, in seconds.
  47. self._preheat_bed_timer = QTimer() # Timer that tracks how long to preheat still.
  48. self._preheat_bed_timer.setSingleShot(True)
  49. self._preheat_bed_timer.timeout.connect(self.cancelPreheatBed)
  50. self._printer_state = ""
  51. self._printer_type = "unknown"
  52. self._camera_active = False
  53. self._monitor_view_qml_path = ""
  54. self._monitor_item = None
  55. self._control_view_qml_path = ""
  56. self._control_item = None
  57. self._qml_context = None
  58. self._can_pause = True
  59. self._can_abort = True
  60. self._can_pre_heat_bed = True
  61. self._can_control_manually = True
  62. def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None):
  63. raise NotImplementedError("requestWrite needs to be implemented")
  64. ## Signals
  65. # Signal to be emitted when bed temp is changed
  66. bedTemperatureChanged = pyqtSignal()
  67. # Signal to be emitted when target bed temp is changed
  68. targetBedTemperatureChanged = pyqtSignal()
  69. # Signal when the progress is changed (usually when this output device is printing / sending lots of data)
  70. progressChanged = pyqtSignal()
  71. # Signal to be emitted when hotend temp is changed
  72. hotendTemperaturesChanged = pyqtSignal()
  73. # Signal to be emitted when target hotend temp is changed
  74. targetHotendTemperaturesChanged = pyqtSignal()
  75. # Signal to be emitted when head position is changed (x,y,z)
  76. headPositionChanged = pyqtSignal()
  77. # Signal to be emitted when either of the material ids is changed
  78. materialIdChanged = pyqtSignal(int, str, arguments = ["index", "id"])
  79. # Signal to be emitted when either of the hotend ids is changed
  80. hotendIdChanged = pyqtSignal(int, str, arguments = ["index", "id"])
  81. # Signal that is emitted every time connection state is changed.
  82. # it also sends it's own device_id (for convenience sake)
  83. connectionStateChanged = pyqtSignal(str)
  84. connectionTextChanged = pyqtSignal()
  85. timeElapsedChanged = pyqtSignal()
  86. timeTotalChanged = pyqtSignal()
  87. jobStateChanged = pyqtSignal()
  88. jobNameChanged = pyqtSignal()
  89. errorTextChanged = pyqtSignal()
  90. acceptsCommandsChanged = pyqtSignal()
  91. printerStateChanged = pyqtSignal()
  92. printerTypeChanged = pyqtSignal()
  93. # Signal to be emitted when some drastic change occurs in the remaining time (not when the time just passes on normally).
  94. preheatBedRemainingTimeChanged = pyqtSignal()
  95. # Does the printer support pre-heating the bed at all
  96. @pyqtProperty(bool, constant=True)
  97. def canPreHeatBed(self):
  98. return self._can_pre_heat_bed
  99. # Does the printer support pause at all
  100. @pyqtProperty(bool, constant=True)
  101. def canPause(self):
  102. return self._can_pause
  103. # Does the printer support abort at all
  104. @pyqtProperty(bool, constant=True)
  105. def canAbort(self):
  106. return self._can_abort
  107. # Does the printer support manual control at all
  108. @pyqtProperty(bool, constant=True)
  109. def canControlManually(self):
  110. return self._can_control_manually
  111. @pyqtProperty(QObject, constant=True)
  112. def monitorItem(self):
  113. # Note that we specifically only check if the monitor component is created.
  114. # It could be that it failed to actually create the qml item! If we check if the item was created, it will try to
  115. # create the item (and fail) every time.
  116. if not self._monitor_item:
  117. self._createMonitorViewFromQML()
  118. return self._monitor_item
  119. @pyqtProperty(QObject, constant=True)
  120. def controlItem(self):
  121. if not self._control_item:
  122. self._createControlViewFromQML()
  123. return self._control_item
  124. def _createControlViewFromQML(self):
  125. if not self._control_view_qml_path:
  126. return
  127. self._control_item = Application.getInstance().createQmlComponent(self._control_view_qml_path, {
  128. "OutputDevice": self
  129. })
  130. def _createMonitorViewFromQML(self):
  131. if not self._monitor_view_qml_path:
  132. return
  133. self._monitor_item = Application.getInstance().createQmlComponent(self._monitor_view_qml_path, {
  134. "OutputDevice": self
  135. })
  136. @pyqtProperty(str, notify=printerTypeChanged)
  137. def printerType(self):
  138. return self._printer_type
  139. @pyqtProperty(str, notify=printerStateChanged)
  140. def printerState(self):
  141. return self._printer_state
  142. @pyqtProperty(str, notify = jobStateChanged)
  143. def jobState(self):
  144. return self._job_state
  145. def _updatePrinterType(self, printer_type):
  146. if self._printer_type != printer_type:
  147. self._printer_type = printer_type
  148. self.printerTypeChanged.emit()
  149. def _updatePrinterState(self, printer_state):
  150. if self._printer_state != printer_state:
  151. self._printer_state = printer_state
  152. self.printerStateChanged.emit()
  153. def _updateJobState(self, job_state):
  154. if self._job_state != job_state:
  155. self._job_state = job_state
  156. self.jobStateChanged.emit()
  157. @pyqtSlot(str)
  158. def setJobState(self, job_state):
  159. self._setJobState(job_state)
  160. def _setJobState(self, job_state):
  161. Logger.log("w", "_setJobState is not implemented by this output device")
  162. @pyqtSlot()
  163. def startCamera(self):
  164. self._camera_active = True
  165. self._startCamera()
  166. def _startCamera(self):
  167. Logger.log("w", "_startCamera is not implemented by this output device")
  168. @pyqtSlot()
  169. def stopCamera(self):
  170. self._camera_active = False
  171. self._stopCamera()
  172. def _stopCamera(self):
  173. Logger.log("w", "_stopCamera is not implemented by this output device")
  174. @pyqtProperty(str, notify = jobNameChanged)
  175. def jobName(self):
  176. return self._job_name
  177. def setJobName(self, name):
  178. if self._job_name != name:
  179. self._job_name = name
  180. self.jobNameChanged.emit()
  181. ## Gives a human-readable address where the device can be found.
  182. @pyqtProperty(str, constant = True)
  183. def address(self):
  184. Logger.log("w", "address is not implemented by this output device.")
  185. ## A human-readable name for the device.
  186. @pyqtProperty(str, constant = True)
  187. def name(self):
  188. Logger.log("w", "name is not implemented by this output device.")
  189. return ""
  190. @pyqtProperty(str, notify = errorTextChanged)
  191. def errorText(self):
  192. return self._error_text
  193. ## Set the error-text that is shown in the print monitor in case of an error
  194. def setErrorText(self, error_text):
  195. if self._error_text != error_text:
  196. self._error_text = error_text
  197. self.errorTextChanged.emit()
  198. @pyqtProperty(bool, notify = acceptsCommandsChanged)
  199. def acceptsCommands(self):
  200. return self._accepts_commands
  201. ## Set a flag to signal the UI that the printer is not (yet) ready to receive commands
  202. def setAcceptsCommands(self, accepts_commands):
  203. if self._accepts_commands != accepts_commands:
  204. self._accepts_commands = accepts_commands
  205. self.acceptsCommandsChanged.emit()
  206. ## Get the bed temperature of the bed (if any)
  207. # This function is "final" (do not re-implement)
  208. # /sa _getBedTemperature implementation function
  209. @pyqtProperty(float, notify = bedTemperatureChanged)
  210. def bedTemperature(self):
  211. return self._bed_temperature
  212. ## Set the (target) bed temperature
  213. # This function is "final" (do not re-implement)
  214. # /param temperature new target temperature of the bed (in deg C)
  215. # /sa _setTargetBedTemperature implementation function
  216. @pyqtSlot(int)
  217. def setTargetBedTemperature(self, temperature):
  218. self._setTargetBedTemperature(temperature)
  219. if self._target_bed_temperature != temperature:
  220. self._target_bed_temperature = temperature
  221. self.targetBedTemperatureChanged.emit()
  222. ## The total duration of the time-out to pre-heat the bed, in seconds.
  223. #
  224. # \return The duration of the time-out to pre-heat the bed, in seconds.
  225. @pyqtProperty(int, constant = True)
  226. def preheatBedTimeout(self):
  227. return self._preheat_bed_timeout
  228. ## The remaining duration of the pre-heating of the bed.
  229. #
  230. # This is formatted in M:SS format.
  231. # \return The duration of the time-out to pre-heat the bed, formatted.
  232. @pyqtProperty(str, notify = preheatBedRemainingTimeChanged)
  233. def preheatBedRemainingTime(self):
  234. if not self._preheat_bed_timer.isActive():
  235. return ""
  236. period = self._preheat_bed_timer.remainingTime()
  237. if period <= 0:
  238. return ""
  239. minutes, period = divmod(period, 60000) #60000 milliseconds in a minute.
  240. seconds, _ = divmod(period, 1000) #1000 milliseconds in a second.
  241. if minutes <= 0 and seconds <= 0:
  242. return ""
  243. return "%d:%02d" % (minutes, seconds)
  244. ## Time the print has been printing.
  245. # Note that timeTotal - timeElapsed should give time remaining.
  246. @pyqtProperty(float, notify = timeElapsedChanged)
  247. def timeElapsed(self):
  248. return self._time_elapsed
  249. ## Total time of the print
  250. # Note that timeTotal - timeElapsed should give time remaining.
  251. @pyqtProperty(float, notify=timeTotalChanged)
  252. def timeTotal(self):
  253. return self._time_total
  254. @pyqtSlot(float)
  255. def setTimeTotal(self, new_total):
  256. if self._time_total != new_total:
  257. self._time_total = new_total
  258. self.timeTotalChanged.emit()
  259. @pyqtSlot(float)
  260. def setTimeElapsed(self, time_elapsed):
  261. if self._time_elapsed != time_elapsed:
  262. self._time_elapsed = time_elapsed
  263. self.timeElapsedChanged.emit()
  264. ## Home the head of the connected printer
  265. # This function is "final" (do not re-implement)
  266. # /sa _homeHead implementation function
  267. @pyqtSlot()
  268. def homeHead(self):
  269. self._homeHead()
  270. ## Home the head of the connected printer
  271. # This is an implementation function and should be overriden by children.
  272. def _homeHead(self):
  273. Logger.log("w", "_homeHead is not implemented by this output device")
  274. ## Home the bed of the connected printer
  275. # This function is "final" (do not re-implement)
  276. # /sa _homeBed implementation function
  277. @pyqtSlot()
  278. def homeBed(self):
  279. self._homeBed()
  280. ## Home the bed of the connected printer
  281. # This is an implementation function and should be overriden by children.
  282. # /sa homeBed
  283. def _homeBed(self):
  284. Logger.log("w", "_homeBed is not implemented by this output device")
  285. ## Protected setter for the bed temperature of the connected printer (if any).
  286. # /parameter temperature Temperature bed needs to go to (in deg celsius)
  287. # /sa setTargetBedTemperature
  288. def _setTargetBedTemperature(self, temperature):
  289. Logger.log("w", "_setTargetBedTemperature is not implemented by this output device")
  290. ## Pre-heats the heated bed of the printer.
  291. #
  292. # \param temperature The temperature to heat the bed to, in degrees
  293. # Celsius.
  294. # \param duration How long the bed should stay warm, in seconds.
  295. @pyqtSlot(float, float)
  296. def preheatBed(self, temperature, duration):
  297. Logger.log("w", "preheatBed is not implemented by this output device.")
  298. ## Cancels pre-heating the heated bed of the printer.
  299. #
  300. # If the bed is not pre-heated, nothing happens.
  301. @pyqtSlot()
  302. def cancelPreheatBed(self):
  303. Logger.log("w", "cancelPreheatBed is not implemented by this output device.")
  304. ## Protected setter for the current bed temperature.
  305. # This simply sets the bed temperature, but ensures that a signal is emitted.
  306. # /param temperature temperature of the bed.
  307. def _setBedTemperature(self, temperature):
  308. if self._bed_temperature != temperature:
  309. self._bed_temperature = temperature
  310. self.bedTemperatureChanged.emit()
  311. ## Get the target bed temperature if connected printer (if any)
  312. @pyqtProperty(int, notify = targetBedTemperatureChanged)
  313. def targetBedTemperature(self):
  314. return self._target_bed_temperature
  315. ## Set the (target) hotend temperature
  316. # This function is "final" (do not re-implement)
  317. # /param index the index of the hotend that needs to change temperature
  318. # /param temperature The temperature it needs to change to (in deg celsius).
  319. # /sa _setTargetHotendTemperature implementation function
  320. @pyqtSlot(int, int)
  321. def setTargetHotendTemperature(self, index, temperature):
  322. self._setTargetHotendTemperature(index, temperature)
  323. if self._target_hotend_temperatures[index] != temperature:
  324. self._target_hotend_temperatures[index] = temperature
  325. self.targetHotendTemperaturesChanged.emit()
  326. ## Implementation function of setTargetHotendTemperature.
  327. # /param index Index of the hotend to set the temperature of
  328. # /param temperature Temperature to set the hotend to (in deg C)
  329. # /sa setTargetHotendTemperature
  330. def _setTargetHotendTemperature(self, index, temperature):
  331. Logger.log("w", "_setTargetHotendTemperature is not implemented by this output device")
  332. @pyqtProperty("QVariantList", notify = targetHotendTemperaturesChanged)
  333. def targetHotendTemperatures(self):
  334. return self._target_hotend_temperatures
  335. @pyqtProperty("QVariantList", notify = hotendTemperaturesChanged)
  336. def hotendTemperatures(self):
  337. return self._hotend_temperatures
  338. ## Protected setter for the current hotend temperature.
  339. # This simply sets the hotend temperature, but ensures that a signal is emitted.
  340. # /param index Index of the hotend
  341. # /param temperature temperature of the hotend (in deg C)
  342. def _setHotendTemperature(self, index, temperature):
  343. if self._hotend_temperatures[index] != temperature:
  344. self._hotend_temperatures[index] = temperature
  345. self.hotendTemperaturesChanged.emit()
  346. @pyqtProperty("QVariantList", notify = materialIdChanged)
  347. def materialIds(self):
  348. return self._material_ids
  349. @pyqtProperty("QVariantList", notify = materialIdChanged)
  350. def materialNames(self):
  351. result = []
  352. for material_id in self._material_ids:
  353. if material_id is None:
  354. result.append(i18n_catalog.i18nc("@item:material", "No material loaded"))
  355. continue
  356. containers = self._container_registry.findInstanceContainersMetadata(type = "material", GUID = material_id)
  357. if containers:
  358. result.append(containers[0]["name"])
  359. else:
  360. result.append(i18n_catalog.i18nc("@item:material", "Unknown material"))
  361. return result
  362. ## List of the colours of the currently loaded materials.
  363. #
  364. # The list is in order of extruders. If there is no material in an
  365. # extruder, the colour is shown as transparent.
  366. #
  367. # The colours are returned in hex-format AARRGGBB or RRGGBB
  368. # (e.g. #800000ff for transparent blue or #00ff00 for pure green).
  369. @pyqtProperty("QVariantList", notify = materialIdChanged)
  370. def materialColors(self):
  371. result = []
  372. for material_id in self._material_ids:
  373. if material_id is None:
  374. result.append("#00000000") #No material.
  375. continue
  376. containers = self._container_registry.findInstanceContainersMetadata(type = "material", GUID = material_id)
  377. if containers:
  378. result.append(containers[0]["color_code"])
  379. else:
  380. result.append("#00000000") #Unknown material.
  381. return result
  382. ## Protected setter for the current material id.
  383. # /param index Index of the extruder
  384. # /param material_id id of the material
  385. def _setMaterialId(self, index, material_id):
  386. if material_id and material_id != "" and material_id != self._material_ids[index]:
  387. Logger.log("d", "Setting material id of hotend %d to %s" % (index, material_id))
  388. self._material_ids[index] = material_id
  389. self.materialIdChanged.emit(index, material_id)
  390. @pyqtProperty("QVariantList", notify = hotendIdChanged)
  391. def hotendIds(self):
  392. return self._hotend_ids
  393. ## Protected setter for the current hotend id.
  394. # /param index Index of the extruder
  395. # /param hotend_id id of the hotend
  396. def _setHotendId(self, index, hotend_id):
  397. if hotend_id and hotend_id != self._hotend_ids[index]:
  398. Logger.log("d", "Setting hotend id of hotend %d to %s" % (index, hotend_id))
  399. self._hotend_ids[index] = hotend_id
  400. self.hotendIdChanged.emit(index, hotend_id)
  401. elif not hotend_id:
  402. Logger.log("d", "Removing hotend id of hotend %d.", index)
  403. self._hotend_ids[index] = None
  404. self.hotendIdChanged.emit(index, None)
  405. ## Let the user decide if the hotends and/or material should be synced with the printer
  406. # NB: the UX needs to be implemented by the plugin
  407. def materialHotendChangedMessage(self, callback):
  408. Logger.log("w", "materialHotendChangedMessage needs to be implemented, returning 'Yes'")
  409. callback(QMessageBox.Yes)
  410. ## Attempt to establish connection
  411. def connect(self):
  412. raise NotImplementedError("connect needs to be implemented")
  413. ## Attempt to close the connection
  414. def close(self):
  415. raise NotImplementedError("close needs to be implemented")
  416. @pyqtProperty(bool, notify = connectionStateChanged)
  417. def connectionState(self):
  418. return self._connection_state
  419. ## Set the connection state of this output device.
  420. # /param connection_state ConnectionState enum.
  421. def setConnectionState(self, connection_state):
  422. if self._connection_state != connection_state:
  423. self._connection_state = connection_state
  424. self.connectionStateChanged.emit(self._id)
  425. @pyqtProperty(str, notify = connectionTextChanged)
  426. def connectionText(self):
  427. return self._connection_text
  428. ## Set a text that is shown on top of the print monitor tab
  429. def setConnectionText(self, connection_text):
  430. if self._connection_text != connection_text:
  431. self._connection_text = connection_text
  432. self.connectionTextChanged.emit()
  433. ## Ensure that close gets called when object is destroyed
  434. def __del__(self):
  435. self.close()
  436. ## Get the x position of the head.
  437. # This function is "final" (do not re-implement)
  438. @pyqtProperty(float, notify = headPositionChanged)
  439. def headX(self):
  440. return self._head_x
  441. ## Get the y position of the head.
  442. # This function is "final" (do not re-implement)
  443. @pyqtProperty(float, notify = headPositionChanged)
  444. def headY(self):
  445. return self._head_y
  446. ## Get the z position of the head.
  447. # In some machines it's actually the bed that moves. For convenience sake we simply see it all as head movements.
  448. # This function is "final" (do not re-implement)
  449. @pyqtProperty(float, notify = headPositionChanged)
  450. def headZ(self):
  451. return self._head_z
  452. ## Update the saved position of the head
  453. # This function should be called when a new position for the head is received.
  454. def _updateHeadPosition(self, x, y ,z):
  455. position_changed = False
  456. if self._head_x != x:
  457. self._head_x = x
  458. position_changed = True
  459. if self._head_y != y:
  460. self._head_y = y
  461. position_changed = True
  462. if self._head_z != z:
  463. self._head_z = z
  464. position_changed = True
  465. if position_changed:
  466. self.headPositionChanged.emit()
  467. ## Set the position of the head.
  468. # In some machines it's actually the bed that moves. For convenience sake we simply see it all as head movements.
  469. # This function is "final" (do not re-implement)
  470. # /param x new x location of the head.
  471. # /param y new y location of the head.
  472. # /param z new z location of the head.
  473. # /param speed Speed by which it needs to move (in mm/minute)
  474. # /sa _setHeadPosition implementation function
  475. @pyqtSlot("long", "long", "long")
  476. @pyqtSlot("long", "long", "long", "long")
  477. def setHeadPosition(self, x, y, z, speed = 3000):
  478. self._setHeadPosition(x, y , z, speed)
  479. ## Set the X position of the head.
  480. # This function is "final" (do not re-implement)
  481. # /param x x position head needs to move to.
  482. # /param speed Speed by which it needs to move (in mm/minute)
  483. # /sa _setHeadx implementation function
  484. @pyqtSlot("long")
  485. @pyqtSlot("long", "long")
  486. def setHeadX(self, x, speed = 3000):
  487. self._setHeadX(x, speed)
  488. ## Set the Y position of the head.
  489. # This function is "final" (do not re-implement)
  490. # /param y y position head needs to move to.
  491. # /param speed Speed by which it needs to move (in mm/minute)
  492. # /sa _setHeadY implementation function
  493. @pyqtSlot("long")
  494. @pyqtSlot("long", "long")
  495. def setHeadY(self, y, speed = 3000):
  496. self._setHeadY(y, speed)
  497. ## Set the Z position of the head.
  498. # In some machines it's actually the bed that moves. For convenience sake we simply see it all as head movements.
  499. # This function is "final" (do not re-implement)
  500. # /param z z position head needs to move to.
  501. # /param speed Speed by which it needs to move (in mm/minute)
  502. # /sa _setHeadZ implementation function
  503. @pyqtSlot("long")
  504. @pyqtSlot("long", "long")
  505. def setHeadZ(self, z, speed = 3000):
  506. self._setHeadZ(z, speed)
  507. ## Move the head of the printer.
  508. # Note that this is a relative move. If you want to move the head to a specific position you can use
  509. # setHeadPosition
  510. # This function is "final" (do not re-implement)
  511. # /param x distance in x to move
  512. # /param y distance in y to move
  513. # /param z distance in z to move
  514. # /param speed Speed by which it needs to move (in mm/minute)
  515. # /sa _moveHead implementation function
  516. @pyqtSlot("long", "long", "long")
  517. @pyqtSlot("long", "long", "long", "long")
  518. def moveHead(self, x = 0, y = 0, z = 0, speed = 3000):
  519. self._moveHead(x, y, z, speed)
  520. ## Implementation function of moveHead.
  521. # /param x distance in x to move
  522. # /param y distance in y to move
  523. # /param z distance in z to move
  524. # /param speed Speed by which it needs to move (in mm/minute)
  525. # /sa moveHead
  526. def _moveHead(self, x, y, z, speed):
  527. Logger.log("w", "_moveHead is not implemented by this output device")
  528. ## Implementation function of setHeadPosition.
  529. # /param x new x location of the head.
  530. # /param y new y location of the head.
  531. # /param z new z location of the head.
  532. # /param speed Speed by which it needs to move (in mm/minute)
  533. # /sa setHeadPosition
  534. def _setHeadPosition(self, x, y, z, speed):
  535. Logger.log("w", "_setHeadPosition is not implemented by this output device")
  536. ## Implementation function of setHeadX.
  537. # /param x new x location of the head.
  538. # /param speed Speed by which it needs to move (in mm/minute)
  539. # /sa setHeadX
  540. def _setHeadX(self, x, speed):
  541. Logger.log("w", "_setHeadX is not implemented by this output device")
  542. ## Implementation function of setHeadY.
  543. # /param y new y location of the head.
  544. # /param speed Speed by which it needs to move (in mm/minute)
  545. # /sa _setHeadY
  546. def _setHeadY(self, y, speed):
  547. Logger.log("w", "_setHeadY is not implemented by this output device")
  548. ## Implementation function of setHeadZ.
  549. # /param z new z location of the head.
  550. # /param speed Speed by which it needs to move (in mm/minute)
  551. # /sa _setHeadZ
  552. def _setHeadZ(self, z, speed):
  553. Logger.log("w", "_setHeadZ is not implemented by this output device")
  554. ## Get the progress of any currently active process.
  555. # This function is "final" (do not re-implement)
  556. # /sa _getProgress
  557. # /returns float progress of the process. -1 indicates that there is no process.
  558. @pyqtProperty(float, notify = progressChanged)
  559. def progress(self):
  560. return self._progress
  561. ## Set the progress of any currently active process
  562. # /param progress Progress of the process.
  563. def setProgress(self, progress):
  564. if self._progress != progress:
  565. self._progress = progress
  566. self.progressChanged.emit()
  567. ## The current processing state of the backend.
  568. class ConnectionState(IntEnum):
  569. closed = 0
  570. connecting = 1
  571. connected = 2
  572. busy = 3
  573. error = 4