mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-01 08:14:22 +08:00
190 lines
8.8 KiB
Python
190 lines
8.8 KiB
Python
# Copyright (c) 2017 Ultimaker B.V.
|
|
# Cura is released under the terms of the LGPLv3 or higher.
|
|
|
|
from UM.Logger import Logger
|
|
|
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
|
|
|
from cura.PrinterOutput.NetworkedPrinterOutputDevice import NetworkedPrinterOutputDevice
|
|
from cura.PrinterOutput.PrinterOutputModel import PrinterOutputModel
|
|
from cura.PrinterOutput.PrintJobOutputModel import PrintJobOutputModel
|
|
from cura.PrinterOutput.MaterialOutputModel import MaterialOutputModel
|
|
|
|
from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply
|
|
from PyQt5.QtGui import QDesktopServices
|
|
from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty
|
|
|
|
import json
|
|
import os
|
|
|
|
|
|
class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|
printJobsChanged = pyqtSignal()
|
|
|
|
# This is a bit of a hack, as the notify can only use signals that are defined by the class that they are in.
|
|
# Inheritance doesn't seem to work. Tying them together does work, but i'm open for better suggestions.
|
|
clusterPrintersChanged = pyqtSignal()
|
|
|
|
def __init__(self, device_id, address, properties, parent = None):
|
|
super().__init__(device_id = device_id, address = address, properties=properties, parent = parent)
|
|
self._api_prefix = "/cluster-api/v1/"
|
|
|
|
self._number_of_extruders = 2
|
|
|
|
self._print_jobs = []
|
|
|
|
self._monitor_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ClusterMonitorItem.qml")
|
|
self._control_view_qml_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ClusterControlItem.qml")
|
|
|
|
# See comments about this hack with the clusterPrintersChanged signal
|
|
self.printersChanged.connect(self.clusterPrintersChanged)
|
|
|
|
@pyqtSlot()
|
|
def openPrintJobControlPanel(self):
|
|
Logger.log("d", "Opening print job control panel...")
|
|
QDesktopServices.openUrl(QUrl("http://" + self._address + "/print_jobs"))
|
|
|
|
@pyqtSlot()
|
|
def openPrinterControlPanel(self):
|
|
Logger.log("d", "Opening printer control panel...")
|
|
QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers"))
|
|
|
|
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
|
def printJobs(self):
|
|
return self._print_jobs
|
|
|
|
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
|
def queuedPrintJobs(self):
|
|
return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is None]
|
|
|
|
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
|
def activePrintJobs(self):
|
|
return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is not None]
|
|
|
|
@pyqtProperty("QVariantList", notify=clusterPrintersChanged)
|
|
def connectedPrintersTypeCount(self):
|
|
printer_count = {}
|
|
for printer in self._printers:
|
|
if printer.type in printer_count:
|
|
printer_count[printer.type] += 1
|
|
else:
|
|
printer_count[printer.type] = 1
|
|
result = []
|
|
for machine_type in printer_count:
|
|
result.append({"machine_type": machine_type, "count": printer_count[machine_type]})
|
|
return result
|
|
|
|
def _update(self):
|
|
if not super()._update():
|
|
return
|
|
self.get("printers/", onFinished=self._onGetPrintersDataFinished)
|
|
self.get("print_jobs/", onFinished=self._onGetPrintJobsFinished)
|
|
|
|
def _onGetPrintJobsFinished(self, reply: QNetworkReply):
|
|
status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
|
|
if status_code == 200:
|
|
try:
|
|
result = json.loads(bytes(reply.readAll()).decode("utf-8"))
|
|
except json.decoder.JSONDecodeError:
|
|
Logger.log("w", "Received an invalid print jobs message: Not valid JSON.")
|
|
return
|
|
print_jobs_seen = []
|
|
for print_job_data in result:
|
|
print_job = None
|
|
for job in self._print_jobs:
|
|
if job.key == print_job_data["uuid"]:
|
|
print_job = job
|
|
break
|
|
|
|
if print_job is None:
|
|
print_job = PrintJobOutputModel(output_controller = None,
|
|
key = print_job_data["uuid"],
|
|
name = print_job_data["name"])
|
|
print_job.updateTimeTotal(print_job_data["time_total"])
|
|
print_job.updateTimeElapsed(print_job_data["time_elapsed"])
|
|
print_job.updateState(print_job_data["status"])
|
|
if print_job.state == "printing":
|
|
# Print job should be assigned to a printer.
|
|
printer = self._getPrinterByKey(print_job_data["printer_uuid"])
|
|
if printer:
|
|
printer.updateActivePrintJob(print_job)
|
|
|
|
print_jobs_seen.append(print_job)
|
|
for old_job in self._print_jobs:
|
|
if old_job not in print_jobs_seen:
|
|
# Print job needs to be removed.
|
|
old_job.assignedPrinter.updateActivePrintJob(None)
|
|
|
|
self._print_jobs = print_jobs_seen
|
|
self.printJobsChanged.emit()
|
|
|
|
def _onGetPrintersDataFinished(self, reply: QNetworkReply):
|
|
status_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
|
|
if status_code == 200:
|
|
try:
|
|
result = json.loads(bytes(reply.readAll()).decode("utf-8"))
|
|
except json.decoder.JSONDecodeError:
|
|
Logger.log("w", "Received an invalid printers state message: Not valid JSON.")
|
|
return
|
|
printer_list_changed = False
|
|
# TODO: Ensure that printers that have been removed are also removed locally.
|
|
for printer_data in result:
|
|
uuid = printer_data["uuid"]
|
|
|
|
printer = None
|
|
for device in self._printers:
|
|
if device.key == uuid:
|
|
printer = device
|
|
break
|
|
|
|
if printer is None:
|
|
printer = PrinterOutputModel(output_controller=None, number_of_extruders=self._number_of_extruders)
|
|
self._printers.append(printer)
|
|
printer_list_changed = True
|
|
|
|
printer.updateName(printer_data["friendly_name"])
|
|
printer.updateKey(uuid)
|
|
printer.updateType(printer_data["machine_variant"])
|
|
if not printer_data["enabled"]:
|
|
printer.updateState("disabled")
|
|
else:
|
|
printer.updateState(printer_data["status"])
|
|
|
|
for index in range(0, self._number_of_extruders):
|
|
extruder = printer.extruders[index]
|
|
extruder_data = printer_data["configuration"][index]
|
|
try:
|
|
hotend_id = extruder_data["print_core_id"]
|
|
except KeyError:
|
|
hotend_id = ""
|
|
extruder.updateHotendID(hotend_id)
|
|
|
|
material_data = extruder_data["material"]
|
|
if extruder.activeMaterial is None or extruder.activeMaterial.guid != material_data["guid"]:
|
|
containers = ContainerRegistry.getInstance().findInstanceContainers(type="material",
|
|
GUID=material_data["guid"])
|
|
if containers:
|
|
color = containers[0].getMetaDataEntry("color_code")
|
|
brand = containers[0].getMetaDataEntry("brand")
|
|
material_type = containers[0].getMetaDataEntry("material")
|
|
name = containers[0].getName()
|
|
else:
|
|
Logger.log("w", "Unable to find material with guid {guid}. Using data as provided by cluster".format(guid = material_data["guid"]))
|
|
# Unknown material.
|
|
color = material_data["color"]
|
|
brand = material_data["brand"]
|
|
material_type = material_data["material"]
|
|
name = "Unknown"
|
|
|
|
material = MaterialOutputModel(guid = material_data["guid"],
|
|
type = material_type,
|
|
brand = brand,
|
|
color = color,
|
|
name = name)
|
|
extruder.updateActiveMaterial(material)
|
|
|
|
if printer_list_changed:
|
|
self.printersChanged.emit()
|
|
else:
|
|
Logger.log("w",
|
|
"Got status code {status_code} while trying to get printer data".format(status_code=status_code)) |