GenericOutputController.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. # Copyright (c) 2018 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. from typing import TYPE_CHECKING, Set, Union, Optional
  4. from PyQt6.QtCore import QTimer
  5. from .PrinterOutputController import PrinterOutputController
  6. if TYPE_CHECKING:
  7. from .Models.PrintJobOutputModel import PrintJobOutputModel
  8. from .Models.PrinterOutputModel import PrinterOutputModel
  9. from .PrinterOutputDevice import PrinterOutputDevice
  10. from .Models.ExtruderOutputModel import ExtruderOutputModel
  11. class GenericOutputController(PrinterOutputController):
  12. def __init__(self, output_device: "PrinterOutputDevice") -> None:
  13. super().__init__(output_device)
  14. self._preheat_bed_timer = QTimer()
  15. self._preheat_bed_timer.setSingleShot(True)
  16. self._preheat_bed_timer.timeout.connect(self._onPreheatBedTimerFinished)
  17. self._preheat_printer = None # type: Optional[PrinterOutputModel]
  18. self._preheat_hotends_timer = QTimer()
  19. self._preheat_hotends_timer.setSingleShot(True)
  20. self._preheat_hotends_timer.timeout.connect(self._onPreheatHotendsTimerFinished)
  21. self._preheat_hotends = set() # type: Set[ExtruderOutputModel]
  22. self._output_device.printersChanged.connect(self._onPrintersChanged)
  23. self._active_printer = None # type: Optional[PrinterOutputModel]
  24. def _onPrintersChanged(self) -> None:
  25. if self._active_printer:
  26. self._active_printer.stateChanged.disconnect(self._onPrinterStateChanged)
  27. self._active_printer.targetBedTemperatureChanged.disconnect(self._onTargetBedTemperatureChanged)
  28. for extruder in self._active_printer.extruders:
  29. extruder.targetHotendTemperatureChanged.disconnect(self._onTargetHotendTemperatureChanged)
  30. self._active_printer = self._output_device.activePrinter
  31. if self._active_printer:
  32. self._active_printer.stateChanged.connect(self._onPrinterStateChanged)
  33. self._active_printer.targetBedTemperatureChanged.connect(self._onTargetBedTemperatureChanged)
  34. for extruder in self._active_printer.extruders:
  35. extruder.targetHotendTemperatureChanged.connect(self._onTargetHotendTemperatureChanged)
  36. def _onPrinterStateChanged(self) -> None:
  37. if self._active_printer and self._active_printer.state != "idle":
  38. if self._preheat_bed_timer.isActive():
  39. self._preheat_bed_timer.stop()
  40. if self._preheat_printer:
  41. self._preheat_printer.updateIsPreheating(False)
  42. if self._preheat_hotends_timer.isActive():
  43. self._preheat_hotends_timer.stop()
  44. for extruder in self._preheat_hotends:
  45. extruder.updateIsPreheating(False)
  46. self._preheat_hotends = set()
  47. def moveHead(self, printer: "PrinterOutputModel", x, y, z, speed) -> None:
  48. self._output_device.sendCommand("G91")
  49. self._output_device.sendCommand("G0 X%s Y%s Z%s F%s" % (x, y, z, speed))
  50. self._output_device.sendCommand("G90")
  51. def homeHead(self, printer: "PrinterOutputModel") -> None:
  52. self._output_device.sendCommand("G28 X Y")
  53. def homeBed(self, printer: "PrinterOutputModel") -> None:
  54. self._output_device.sendCommand("G28 Z")
  55. def sendRawCommand(self, printer: "PrinterOutputModel", command: str) -> None:
  56. self._output_device.sendCommand(command.upper()) #Most printers only understand uppercase g-code commands.
  57. def setJobState(self, job: "PrintJobOutputModel", state: str) -> None:
  58. if state == "pause":
  59. self._output_device.pausePrint()
  60. job.updateState("paused")
  61. elif state == "print":
  62. self._output_device.resumePrint()
  63. job.updateState("printing")
  64. elif state == "abort":
  65. self._output_device.cancelPrint()
  66. pass
  67. def setTargetBedTemperature(self, printer: "PrinterOutputModel", temperature: float) -> None:
  68. self._output_device.sendCommand("M140 S%s" % round(temperature)) # The API doesn't allow floating point.
  69. def _onTargetBedTemperatureChanged(self) -> None:
  70. if self._preheat_bed_timer.isActive() and self._preheat_printer and self._preheat_printer.targetBedTemperature == 0:
  71. self._preheat_bed_timer.stop()
  72. self._preheat_printer.updateIsPreheating(False)
  73. def preheatBed(self, printer: "PrinterOutputModel", temperature, duration) -> None:
  74. try:
  75. temperature = round(temperature) # The API doesn't allow floating point.
  76. duration = round(duration)
  77. except ValueError:
  78. return # Got invalid values, can't pre-heat.
  79. self.setTargetBedTemperature(printer, temperature = temperature)
  80. self._preheat_bed_timer.setInterval(duration * 1000)
  81. self._preheat_bed_timer.start()
  82. self._preheat_printer = printer
  83. printer.updateIsPreheating(True)
  84. def cancelPreheatBed(self, printer: "PrinterOutputModel") -> None:
  85. self.setTargetBedTemperature(printer, temperature = 0)
  86. self._preheat_bed_timer.stop()
  87. printer.updateIsPreheating(False)
  88. def _onPreheatBedTimerFinished(self) -> None:
  89. if not self._preheat_printer:
  90. return
  91. self.setTargetBedTemperature(self._preheat_printer, 0)
  92. self._preheat_printer.updateIsPreheating(False)
  93. def setTargetHotendTemperature(self, printer: "PrinterOutputModel", position: int, temperature: Union[int, float]) -> None:
  94. self._output_device.sendCommand("M104 S%s T%s" % (temperature, position))
  95. def _onTargetHotendTemperatureChanged(self) -> None:
  96. if not self._preheat_hotends_timer.isActive():
  97. return
  98. if not self._active_printer:
  99. return
  100. for extruder in self._active_printer.extruders:
  101. if extruder in self._preheat_hotends and extruder.targetHotendTemperature == 0:
  102. extruder.updateIsPreheating(False)
  103. self._preheat_hotends.remove(extruder)
  104. if not self._preheat_hotends:
  105. self._preheat_hotends_timer.stop()
  106. def preheatHotend(self, extruder: "ExtruderOutputModel", temperature, duration) -> None:
  107. position = extruder.getPosition()
  108. number_of_extruders = len(extruder.getPrinter().extruders)
  109. if position >= number_of_extruders:
  110. return # Got invalid extruder nr, can't pre-heat.
  111. try:
  112. temperature = round(temperature) # The API doesn't allow floating point.
  113. duration = round(duration)
  114. except ValueError:
  115. return # Got invalid values, can't pre-heat.
  116. self.setTargetHotendTemperature(extruder.getPrinter(), position, temperature=temperature)
  117. self._preheat_hotends_timer.setInterval(duration * 1000)
  118. self._preheat_hotends_timer.start()
  119. self._preheat_hotends.add(extruder)
  120. extruder.updateIsPreheating(True)
  121. def cancelPreheatHotend(self, extruder: "ExtruderOutputModel") -> None:
  122. self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), temperature=0)
  123. if extruder in self._preheat_hotends:
  124. extruder.updateIsPreheating(False)
  125. self._preheat_hotends.remove(extruder)
  126. if not self._preheat_hotends and self._preheat_hotends_timer.isActive():
  127. self._preheat_hotends_timer.stop()
  128. def _onPreheatHotendsTimerFinished(self) -> None:
  129. for extruder in self._preheat_hotends:
  130. self.setTargetHotendTemperature(extruder.getPrinter(), extruder.getPosition(), 0)
  131. self._preheat_hotends = set()
  132. # Cancel any ongoing preheating timers, without setting back the temperature to 0
  133. # This can be used eg at the start of a print
  134. def stopPreheatTimers(self) -> None:
  135. if self._preheat_hotends_timer.isActive():
  136. for extruder in self._preheat_hotends:
  137. extruder.updateIsPreheating(False)
  138. self._preheat_hotends = set()
  139. self._preheat_hotends_timer.stop()
  140. if self._preheat_bed_timer.isActive():
  141. if self._preheat_printer:
  142. self._preheat_printer.updateIsPreheating(False)
  143. self._preheat_bed_timer.stop()