mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-06-30 06:45:14 +08:00
Merge branch 'master' of github.com:Ultimaker/Cura
This commit is contained in:
commit
b20a349b44
@ -25,7 +25,7 @@ class ExtruderConfigurationModel(QObject):
|
|||||||
return self._position
|
return self._position
|
||||||
|
|
||||||
def setMaterial(self, material: Optional[MaterialOutputModel]) -> None:
|
def setMaterial(self, material: Optional[MaterialOutputModel]) -> None:
|
||||||
if self._hotend_id != material:
|
if self._material != material:
|
||||||
self._material = material
|
self._material = material
|
||||||
self.extruderConfigurationChanged.emit()
|
self.extruderConfigurationChanged.emit()
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ class ExtruderConfigurationModel(QObject):
|
|||||||
def activeMaterial(self) -> Optional[MaterialOutputModel]:
|
def activeMaterial(self) -> Optional[MaterialOutputModel]:
|
||||||
return self._material
|
return self._material
|
||||||
|
|
||||||
@pyqtProperty(QObject, fset=setMaterial, notify=extruderConfigurationChanged)
|
@pyqtProperty(QObject, fset = setMaterial, notify = extruderConfigurationChanged)
|
||||||
def material(self) -> Optional[MaterialOutputModel]:
|
def material(self) -> Optional[MaterialOutputModel]:
|
||||||
return self._material
|
return self._material
|
||||||
|
|
||||||
|
@ -58,6 +58,14 @@ class PrinterConfigurationModel(QObject):
|
|||||||
return False
|
return False
|
||||||
return self._printer_type != ""
|
return self._printer_type != ""
|
||||||
|
|
||||||
|
def hasAnyMaterialLoaded(self) -> bool:
|
||||||
|
if not self.isValid():
|
||||||
|
return False
|
||||||
|
for configuration in self._extruder_configurations:
|
||||||
|
if configuration.activeMaterial and configuration.activeMaterial.type != "empty":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
message_chunks = []
|
message_chunks = []
|
||||||
message_chunks.append("Printer type: " + self._printer_type)
|
message_chunks.append("Printer type: " + self._printer_type)
|
||||||
|
@ -50,7 +50,7 @@ class PrinterOutputModel(QObject):
|
|||||||
|
|
||||||
self._active_printer_configuration.extruderConfigurations = [extruder.extruderConfiguration for extruder in
|
self._active_printer_configuration.extruderConfigurations = [extruder.extruderConfiguration for extruder in
|
||||||
self._extruders]
|
self._extruders]
|
||||||
|
self._active_printer_configuration.configurationChanged.connect(self.configurationChanged)
|
||||||
self._available_printer_configurations = [] # type: List[PrinterConfigurationModel]
|
self._available_printer_configurations = [] # type: List[PrinterConfigurationModel]
|
||||||
|
|
||||||
self._camera_url = QUrl() # type: QUrl
|
self._camera_url = QUrl() # type: QUrl
|
||||||
|
@ -222,7 +222,7 @@ class PrinterOutputDevice(QObject, OutputDevice):
|
|||||||
def _updateUniqueConfigurations(self) -> None:
|
def _updateUniqueConfigurations(self) -> None:
|
||||||
all_configurations = set()
|
all_configurations = set()
|
||||||
for printer in self._printers:
|
for printer in self._printers:
|
||||||
if printer.printerConfiguration is not None:
|
if printer.printerConfiguration is not None and printer.printerConfiguration.hasAnyMaterialLoaded():
|
||||||
all_configurations.add(printer.printerConfiguration)
|
all_configurations.add(printer.printerConfiguration)
|
||||||
all_configurations.update(printer.availableConfigurations)
|
all_configurations.update(printer.availableConfigurations)
|
||||||
new_configurations = sorted(all_configurations, key = lambda config: config.printerType)
|
new_configurations = sorted(all_configurations, key = lambda config: config.printerType)
|
||||||
|
@ -9,7 +9,8 @@ from .ClusterPrinterConfigurationMaterial import ClusterPrinterConfigurationMate
|
|||||||
from ..BaseModel import BaseModel
|
from ..BaseModel import BaseModel
|
||||||
|
|
||||||
|
|
||||||
## Class representing a cloud cluster printer configuration
|
## Class representing a cloud cluster printer configuration
|
||||||
|
# Also used for representing slots in a Material Station (as from Cura's perspective these are the same).
|
||||||
class ClusterPrintCoreConfiguration(BaseModel):
|
class ClusterPrintCoreConfiguration(BaseModel):
|
||||||
|
|
||||||
## Creates a new cloud cluster printer configuration object
|
## Creates a new cloud cluster printer configuration object
|
||||||
@ -18,7 +19,7 @@ class ClusterPrintCoreConfiguration(BaseModel):
|
|||||||
# \param nozzle_diameter: The diameter of the print core at this position in millimeters, e.g. '0.4'.
|
# \param nozzle_diameter: The diameter of the print core at this position in millimeters, e.g. '0.4'.
|
||||||
# \param print_core_id: The type of print core inserted at this position, e.g. 'AA 0.4'.
|
# \param print_core_id: The type of print core inserted at this position, e.g. 'AA 0.4'.
|
||||||
def __init__(self, extruder_index: int,
|
def __init__(self, extruder_index: int,
|
||||||
material: Union[None, Dict[str, Any], ClusterPrinterConfigurationMaterial],
|
material: Union[None, Dict[str, Any], ClusterPrinterConfigurationMaterial] = None,
|
||||||
print_core_id: Optional[str] = None, **kwargs) -> None:
|
print_core_id: Optional[str] = None, **kwargs) -> None:
|
||||||
self.extruder_index = extruder_index
|
self.extruder_index = extruder_index
|
||||||
self.material = self.parseModel(ClusterPrinterConfigurationMaterial, material) if material else None
|
self.material = self.parseModel(ClusterPrinterConfigurationMaterial, material) if material else None
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
# Copyright (c) 2019 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from typing import Union, Dict, Any, List
|
||||||
|
|
||||||
|
from ..BaseModel import BaseModel
|
||||||
|
from .ClusterPrinterMaterialStationSlot import ClusterPrinterMaterialStationSlot
|
||||||
|
|
||||||
|
|
||||||
|
## Class representing the data of a Material Station in the cluster.
|
||||||
|
class ClusterPrinterMaterialStation(BaseModel):
|
||||||
|
|
||||||
|
## Creates a new Material Station status.
|
||||||
|
# \param status: The status of the material station.
|
||||||
|
# \param: supported: Whether the material station is supported on this machine or not.
|
||||||
|
# \param material_slots: The active slots configurations of this material station.
|
||||||
|
def __init__(self, status: str, supported: bool = False,
|
||||||
|
material_slots: Union[None, Dict[str, Any], ClusterPrinterMaterialStationSlot] = None,
|
||||||
|
**kwargs) -> None:
|
||||||
|
self.status = status
|
||||||
|
self.supported = supported
|
||||||
|
self.material_slots = self.parseModels(ClusterPrinterMaterialStationSlot, material_slots)\
|
||||||
|
if material_slots else [] # type: List[ClusterPrinterMaterialStationSlot]
|
||||||
|
super().__init__(**kwargs)
|
@ -0,0 +1,17 @@
|
|||||||
|
# Copyright (c) 2019 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from .ClusterPrintCoreConfiguration import ClusterPrintCoreConfiguration
|
||||||
|
|
||||||
|
|
||||||
|
## Class representing the data of a single slot in the material station.
|
||||||
|
class ClusterPrinterMaterialStationSlot(ClusterPrintCoreConfiguration):
|
||||||
|
|
||||||
|
## Create a new material station slot object.
|
||||||
|
# \param slot_index: The index of the slot in the material station (ranging 0 to 5).
|
||||||
|
# \param compatible: Whether the configuration is compatible with the print core.
|
||||||
|
# \param material_remaining: How much material is remaining on the spool (between 0 and 1, or -1 for missing data).
|
||||||
|
def __init__(self, slot_index: int, compatible: bool, material_remaining: float, **kwargs):
|
||||||
|
self.slot_index = slot_index
|
||||||
|
self.compatible = compatible
|
||||||
|
self.material_remaining = material_remaining
|
||||||
|
super().__init__(**kwargs)
|
@ -1,14 +1,18 @@
|
|||||||
# Copyright (c) 2019 Ultimaker B.V.
|
# Copyright (c) 2019 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from itertools import product
|
||||||
from typing import List, Union, Dict, Optional, Any
|
from typing import List, Union, Dict, Optional, Any
|
||||||
|
|
||||||
from PyQt5.QtCore import QUrl
|
from PyQt5.QtCore import QUrl
|
||||||
|
|
||||||
|
from cura.PrinterOutput.Models.PrinterConfigurationModel import PrinterConfigurationModel
|
||||||
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
|
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
|
||||||
from cura.PrinterOutput.Models.PrinterOutputModel import PrinterOutputModel
|
from cura.PrinterOutput.Models.PrinterOutputModel import PrinterOutputModel
|
||||||
|
|
||||||
from .ClusterBuildPlate import ClusterBuildPlate
|
from .ClusterBuildPlate import ClusterBuildPlate
|
||||||
from .ClusterPrintCoreConfiguration import ClusterPrintCoreConfiguration
|
from .ClusterPrintCoreConfiguration import ClusterPrintCoreConfiguration
|
||||||
|
from .ClusterPrinterMaterialStation import ClusterPrinterMaterialStation
|
||||||
|
from .ClusterPrinterMaterialStationSlot import ClusterPrinterMaterialStationSlot
|
||||||
from ..BaseModel import BaseModel
|
from ..BaseModel import BaseModel
|
||||||
|
|
||||||
|
|
||||||
@ -26,17 +30,19 @@ class ClusterPrinterStatus(BaseModel):
|
|||||||
# \param uuid: The unique ID of the printer, also known as GUID.
|
# \param uuid: The unique ID of the printer, also known as GUID.
|
||||||
# \param configuration: The active print core configurations of this printer.
|
# \param configuration: The active print core configurations of this printer.
|
||||||
# \param reserved_by: A printer can be claimed by a specific print job.
|
# \param reserved_by: A printer can be claimed by a specific print job.
|
||||||
# \param maintenance_required: Indicates if maintenance is necessary
|
# \param maintenance_required: Indicates if maintenance is necessary.
|
||||||
# \param firmware_update_status: Whether the printer's firmware is up-to-date, value is one of: "up_to_date",
|
# \param firmware_update_status: Whether the printer's firmware is up-to-date, value is one of: "up_to_date",
|
||||||
# "pending_update", "update_available", "update_in_progress", "update_failed", "update_impossible"
|
# "pending_update", "update_available", "update_in_progress", "update_failed", "update_impossible".
|
||||||
# \param latest_available_firmware: The version of the latest firmware that is available
|
# \param latest_available_firmware: The version of the latest firmware that is available.
|
||||||
# \param build_plate: The build plate that is on the printer
|
# \param build_plate: The build plate that is on the printer.
|
||||||
|
# \param material_station: The material station that is on the printer.
|
||||||
def __init__(self, enabled: bool, firmware_version: str, friendly_name: str, ip_address: str, machine_variant: str,
|
def __init__(self, enabled: bool, firmware_version: str, friendly_name: str, ip_address: str, machine_variant: str,
|
||||||
status: str, unique_name: str, uuid: str,
|
status: str, unique_name: str, uuid: str,
|
||||||
configuration: List[Union[Dict[str, Any], ClusterPrintCoreConfiguration]],
|
configuration: List[Union[Dict[str, Any], ClusterPrintCoreConfiguration]],
|
||||||
reserved_by: Optional[str] = None, maintenance_required: Optional[bool] = None,
|
reserved_by: Optional[str] = None, maintenance_required: Optional[bool] = None,
|
||||||
firmware_update_status: Optional[str] = None, latest_available_firmware: Optional[str] = None,
|
firmware_update_status: Optional[str] = None, latest_available_firmware: Optional[str] = None,
|
||||||
build_plate: Union[Dict[str, Any], ClusterBuildPlate] = None, **kwargs) -> None:
|
build_plate: Union[Dict[str, Any], ClusterBuildPlate] = None,
|
||||||
|
material_station: Union[Dict[str, Any], ClusterPrinterMaterialStation] = None, **kwargs) -> None:
|
||||||
|
|
||||||
self.configuration = self.parseModels(ClusterPrintCoreConfiguration, configuration)
|
self.configuration = self.parseModels(ClusterPrintCoreConfiguration, configuration)
|
||||||
self.enabled = enabled
|
self.enabled = enabled
|
||||||
@ -52,6 +58,8 @@ class ClusterPrinterStatus(BaseModel):
|
|||||||
self.firmware_update_status = firmware_update_status
|
self.firmware_update_status = firmware_update_status
|
||||||
self.latest_available_firmware = latest_available_firmware
|
self.latest_available_firmware = latest_available_firmware
|
||||||
self.build_plate = self.parseModel(ClusterBuildPlate, build_plate) if build_plate else None
|
self.build_plate = self.parseModel(ClusterBuildPlate, build_plate) if build_plate else None
|
||||||
|
self.material_station = self.parseModel(ClusterPrinterMaterialStation,
|
||||||
|
material_station) if material_station else None
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
## Creates a new output model.
|
## Creates a new output model.
|
||||||
@ -71,8 +79,53 @@ class ClusterPrinterStatus(BaseModel):
|
|||||||
model.updateBuildplate(self.build_plate.type if self.build_plate else "glass")
|
model.updateBuildplate(self.build_plate.type if self.build_plate else "glass")
|
||||||
model.setCameraUrl(QUrl("http://{}:8080/?action=stream".format(self.ip_address)))
|
model.setCameraUrl(QUrl("http://{}:8080/?action=stream".format(self.ip_address)))
|
||||||
|
|
||||||
if model.printerConfiguration is not None:
|
# Set the possible configurations based on whether a Material Station is present or not.
|
||||||
for configuration, extruder_output, extruder_config in \
|
if self.material_station is not None and len(self.material_station.material_slots):
|
||||||
zip(self.configuration, model.extruders, model.printerConfiguration.extruderConfigurations):
|
self._updateAvailableConfigurations(model)
|
||||||
configuration.updateOutputModel(extruder_output)
|
if self.configuration is not None:
|
||||||
configuration.updateConfigurationModel(extruder_config)
|
self._updateActiveConfiguration(model)
|
||||||
|
|
||||||
|
def _updateActiveConfiguration(self, model: PrinterOutputModel) -> None:
|
||||||
|
configurations = zip(self.configuration, model.extruders, model.printerConfiguration.extruderConfigurations)
|
||||||
|
for configuration, extruder_output, extruder_config in configurations:
|
||||||
|
configuration.updateOutputModel(extruder_output)
|
||||||
|
configuration.updateConfigurationModel(extruder_config)
|
||||||
|
|
||||||
|
def _updateAvailableConfigurations(self, model: PrinterOutputModel) -> None:
|
||||||
|
# Generate a list of configurations for the left extruder.
|
||||||
|
left_configurations = [slot for slot in self.material_station.material_slots if self._isSupportedConfiguration(
|
||||||
|
slot = slot,
|
||||||
|
extruder_index = 0
|
||||||
|
)]
|
||||||
|
# Generate a list of configurations for the right extruder.
|
||||||
|
right_configurations = [slot for slot in self.material_station.material_slots if self._isSupportedConfiguration(
|
||||||
|
slot = slot,
|
||||||
|
extruder_index = 1
|
||||||
|
)]
|
||||||
|
# Create a list of all available combinations between both print cores.
|
||||||
|
available_configurations = [self._createAvailableConfigurationFromPrinterConfiguration(
|
||||||
|
left_slot = left_slot,
|
||||||
|
right_slot = right_slot,
|
||||||
|
printer_configuration = model.printerConfiguration
|
||||||
|
) for left_slot, right_slot in product(left_configurations, right_configurations)]
|
||||||
|
# Let Cura know which available configurations there are.
|
||||||
|
model.setAvailableConfigurations(available_configurations)
|
||||||
|
|
||||||
|
## Check if a configuration is supported in order to make it selectable by the user.
|
||||||
|
# We filter out any slot that is not supported by the extruder index, print core type or if the material is empty.
|
||||||
|
@staticmethod
|
||||||
|
def _isSupportedConfiguration(slot: ClusterPrinterMaterialStationSlot, extruder_index: int) -> bool:
|
||||||
|
return slot.extruder_index == extruder_index and slot.compatible and slot.material and \
|
||||||
|
slot.material_remaining != 0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _createAvailableConfigurationFromPrinterConfiguration(left_slot: ClusterPrinterMaterialStationSlot,
|
||||||
|
right_slot: ClusterPrinterMaterialStationSlot,
|
||||||
|
printer_configuration: PrinterConfigurationModel
|
||||||
|
) -> PrinterConfigurationModel:
|
||||||
|
available_configuration = PrinterConfigurationModel()
|
||||||
|
available_configuration.setExtruderConfigurations([left_slot.createConfigurationModel(),
|
||||||
|
right_slot.createConfigurationModel()])
|
||||||
|
available_configuration.setPrinterType(printer_configuration.printerType)
|
||||||
|
available_configuration.setBuildplateConfiguration(printer_configuration.buildplateConfiguration)
|
||||||
|
return available_configuration
|
||||||
|
@ -3,6 +3,8 @@ from unittest.mock import MagicMock
|
|||||||
import pytest
|
import pytest
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from cura.PrinterOutput.Models.ExtruderConfigurationModel import ExtruderConfigurationModel
|
||||||
|
from cura.PrinterOutput.Models.MaterialOutputModel import MaterialOutputModel
|
||||||
from cura.PrinterOutput.Models.PrinterConfigurationModel import PrinterConfigurationModel
|
from cura.PrinterOutput.Models.PrinterConfigurationModel import PrinterConfigurationModel
|
||||||
from cura.PrinterOutput.Models.PrinterOutputModel import PrinterOutputModel
|
from cura.PrinterOutput.Models.PrinterOutputModel import PrinterOutputModel
|
||||||
from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice
|
from cura.PrinterOutput.PrinterOutputDevice import PrinterOutputDevice
|
||||||
@ -61,4 +63,26 @@ def test_uniqueConfigurations(printer_output_device):
|
|||||||
# Once the type of printer is set, it's active configuration counts as being set.
|
# Once the type of printer is set, it's active configuration counts as being set.
|
||||||
# In that case, that should also be added to the list of available configurations
|
# In that case, that should also be added to the list of available configurations
|
||||||
printer.updateType("blarg!")
|
printer.updateType("blarg!")
|
||||||
assert printer_output_device.uniqueConfigurations == [configuration, printer.printerConfiguration]
|
loaded_material = MaterialOutputModel(guid = "", type = "PLA", color = "Blue", brand = "Generic", name = "Blue PLA")
|
||||||
|
loaded_left_extruder = ExtruderConfigurationModel(0)
|
||||||
|
loaded_left_extruder.setMaterial(loaded_material)
|
||||||
|
loaded_right_extruder = ExtruderConfigurationModel(1)
|
||||||
|
loaded_right_extruder.setMaterial(loaded_material)
|
||||||
|
printer.printerConfiguration.setExtruderConfigurations([loaded_left_extruder, loaded_right_extruder])
|
||||||
|
assert printer_output_device.uniqueConfigurations == [configuration, printer.printerConfiguration]
|
||||||
|
|
||||||
|
|
||||||
|
def test_uniqueConfigurations_empty_is_filtered_out(printer_output_device):
|
||||||
|
printer = PrinterOutputModel(MagicMock())
|
||||||
|
# Add a printer and fire the signal that ensures they get hooked up correctly.
|
||||||
|
printer_output_device._printers = [printer]
|
||||||
|
printer_output_device._onPrintersChanged()
|
||||||
|
|
||||||
|
printer.updateType("blarg!")
|
||||||
|
empty_material = MaterialOutputModel(guid = "", type = "empty", color = "empty", brand = "Generic", name = "Empty")
|
||||||
|
empty_left_extruder = ExtruderConfigurationModel(0)
|
||||||
|
empty_left_extruder.setMaterial(empty_material)
|
||||||
|
empty_right_extruder = ExtruderConfigurationModel(1)
|
||||||
|
empty_right_extruder.setMaterial(empty_material)
|
||||||
|
printer.printerConfiguration.setExtruderConfigurations([empty_left_extruder, empty_right_extruder])
|
||||||
|
assert printer_output_device.uniqueConfigurations == []
|
||||||
|
Loading…
x
Reference in New Issue
Block a user