mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-08 06:23:59 -06:00
Merge branch 'master' into feature_support_eraser_ux
This commit is contained in:
commit
11be8f158f
109 changed files with 2615 additions and 660 deletions
|
@ -122,7 +122,7 @@ class ThreeMFReader(MeshReader):
|
|||
um_node.callDecoration("setActiveExtruder", default_stack.getId())
|
||||
|
||||
# Get the definition & set it
|
||||
definition_id = getMachineDefinitionIDForQualitySearch(global_container_stack)
|
||||
definition_id = getMachineDefinitionIDForQualitySearch(global_container_stack.definition)
|
||||
um_node.callDecoration("getStack").getTop().setDefinition(definition_id)
|
||||
|
||||
setting_container = um_node.callDecoration("getStack").getTop()
|
||||
|
|
|
@ -265,13 +265,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||
for material_container_file in material_container_files:
|
||||
container_id = self._stripFileToId(material_container_file)
|
||||
|
||||
from hashlib import sha1
|
||||
hex_container_id = sha1(container_id.encode('utf-8')).hexdigest()
|
||||
|
||||
serialized = archive.open(material_container_file).read().decode("utf-8")
|
||||
metadata_list = xml_material_profile.deserializeMetadata(serialized, hex_container_id)
|
||||
reverse_map = {metadata["id"].replace(hex_container_id, container_id): container_id.replace(hex_container_id, container_id)
|
||||
for metadata in metadata_list}
|
||||
metadata_list = xml_material_profile.deserializeMetadata(serialized, container_id)
|
||||
reverse_map = {metadata["id"]: container_id for metadata in metadata_list}
|
||||
reverse_material_id_dict.update(reverse_map)
|
||||
|
||||
material_labels.append(self._getMaterialLabelFromSerialized(serialized))
|
||||
|
@ -598,7 +594,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||
Logger.log("w", "Workspace did not contain visible settings. Leaving visibility unchanged")
|
||||
else:
|
||||
global_preferences.setValue("general/visible_settings", visible_settings)
|
||||
global_preferences.setValue("general/preset_setting_visibility_choice", "Custom")
|
||||
global_preferences.setValue("cura/active_setting_visibility_preset", "custom")
|
||||
|
||||
categories_expanded = temp_preferences.getValue("cura/categories_expanded")
|
||||
if categories_expanded is None:
|
||||
|
@ -723,7 +719,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||
|
||||
# Get the correct extruder definition IDs for quality changes
|
||||
from cura.Machines.QualityManager import getMachineDefinitionIDForQualitySearch
|
||||
machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(global_stack)
|
||||
machine_definition_id_for_quality = getMachineDefinitionIDForQualitySearch(global_stack.definition)
|
||||
machine_definition_for_quality = self._container_registry.findDefinitionContainers(id = machine_definition_id_for_quality)[0]
|
||||
|
||||
quality_changes_info = self._machine_info.quality_changes_info
|
||||
|
@ -754,15 +750,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
|||
quality_changes_containers = self._container_registry.findInstanceContainers(name = quality_changes_name,
|
||||
type = "quality_changes")
|
||||
for container in quality_changes_containers:
|
||||
extruder_definition_id = container.getMetaDataEntry("extruder")
|
||||
if not extruder_definition_id:
|
||||
extruder_position = container.getMetaDataEntry("position")
|
||||
if extruder_position is None:
|
||||
quality_changes_info.global_info.container = container
|
||||
else:
|
||||
extruder_definition_metadata = self._container_registry.findDefinitionContainersMetadata(id = extruder_definition_id)[0]
|
||||
position = extruder_definition_metadata["position"]
|
||||
if position not in quality_changes_info.extruder_info_dict:
|
||||
quality_changes_info.extruder_info_dict[position] = ContainerInfo(None, None, None)
|
||||
container_info = quality_changes_info.extruder_info_dict[position]
|
||||
if extruder_position not in quality_changes_info.extruder_info_dict:
|
||||
quality_changes_info.extruder_info_dict[extruder_position] = ContainerInfo(None, None, None)
|
||||
container_info = quality_changes_info.extruder_info_dict[extruder_position]
|
||||
container_info.container = container
|
||||
|
||||
# If there is no quality changes for any extruder, create one.
|
||||
|
|
|
@ -10,7 +10,6 @@ from UM.Logger import Logger
|
|||
from UM.Message import Message
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.Resources import Resources
|
||||
from UM.Settings.Validator import ValidatorState #To find if a setting is in an error state. We can't slice then.
|
||||
from UM.Platform import Platform
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
from UM.Qt.Duration import DurationFormat
|
||||
|
@ -32,6 +31,7 @@ import Arcus
|
|||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
|
||||
class CuraEngineBackend(QObject, Backend):
|
||||
|
||||
backendError = Signal()
|
||||
|
@ -62,23 +62,26 @@ class CuraEngineBackend(QObject, Backend):
|
|||
default_engine_location = execpath
|
||||
break
|
||||
|
||||
self._application = Application.getInstance()
|
||||
self._multi_build_plate_model = None
|
||||
self._machine_error_checker = None
|
||||
|
||||
if not default_engine_location:
|
||||
raise EnvironmentError("Could not find CuraEngine")
|
||||
|
||||
Logger.log("i", "Found CuraEngine at: %s" %(default_engine_location))
|
||||
Logger.log("i", "Found CuraEngine at: %s", default_engine_location)
|
||||
|
||||
default_engine_location = os.path.abspath(default_engine_location)
|
||||
Preferences.getInstance().addPreference("backend/location", default_engine_location)
|
||||
|
||||
# Workaround to disable layer view processing if layer view is not active.
|
||||
self._layer_view_active = False
|
||||
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
|
||||
Application.getInstance().getMultiBuildPlateModel().activeBuildPlateChanged.connect(self._onActiveViewChanged)
|
||||
self._onActiveViewChanged()
|
||||
|
||||
self._stored_layer_data = []
|
||||
self._stored_optimized_layer_data = {} # key is build plate number, then arrays are stored until they go to the ProcessSlicesLayersJob
|
||||
|
||||
self._scene = Application.getInstance().getController().getScene()
|
||||
self._scene = self._application.getController().getScene()
|
||||
self._scene.sceneChanged.connect(self._onSceneChanged)
|
||||
|
||||
# Triggers for auto-slicing. Auto-slicing is triggered as follows:
|
||||
|
@ -86,20 +89,10 @@ class CuraEngineBackend(QObject, Backend):
|
|||
# - whenever there is a value change, we start the timer
|
||||
# - sometimes an error check can get scheduled for a value change, in that case, we ONLY want to start the
|
||||
# auto-slicing timer when that error check is finished
|
||||
# If there is an error check, it will set the "_is_error_check_scheduled" flag, stop the auto-slicing timer,
|
||||
# and only wait for the error check to be finished to start the auto-slicing timer again.
|
||||
# If there is an error check, stop the auto-slicing timer, and only wait for the error check to be finished
|
||||
# to start the auto-slicing timer again.
|
||||
#
|
||||
self._global_container_stack = None
|
||||
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||
self._onGlobalStackChanged()
|
||||
|
||||
Application.getInstance().stacksValidationFinished.connect(self._onStackErrorCheckFinished)
|
||||
# extruder enable / disable. Actually wanted to use machine manager here, but the initialization order causes it to crash
|
||||
ExtruderManager.getInstance().extrudersChanged.connect(self._extruderChanged)
|
||||
|
||||
# A flag indicating if an error check was scheduled
|
||||
# If so, we will stop the auto-slice timer and start upon the error check
|
||||
self._is_error_check_scheduled = False
|
||||
|
||||
# Listeners for receiving messages from the back-end.
|
||||
self._message_handlers["cura.proto.Layer"] = self._onLayerMessage
|
||||
|
@ -125,13 +118,6 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._last_num_objects = defaultdict(int) # Count number of objects to see if there is something changed
|
||||
self._postponed_scene_change_sources = [] # scene change is postponed (by a tool)
|
||||
|
||||
self.backendQuit.connect(self._onBackendQuit)
|
||||
self.backendConnected.connect(self._onBackendConnected)
|
||||
|
||||
# When a tool operation is in progress, don't slice. So we need to listen for tool operations.
|
||||
Application.getInstance().getController().toolOperationStarted.connect(self._onToolOperationStarted)
|
||||
Application.getInstance().getController().toolOperationStopped.connect(self._onToolOperationStopped)
|
||||
|
||||
self._slice_start_time = None
|
||||
|
||||
Preferences.getInstance().addPreference("general/auto_slice", True)
|
||||
|
@ -146,6 +132,30 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self.determineAutoSlicing()
|
||||
Preferences.getInstance().preferenceChanged.connect(self._onPreferencesChanged)
|
||||
|
||||
self._application.initializationFinished.connect(self.initialize)
|
||||
|
||||
def initialize(self):
|
||||
self._multi_build_plate_model = self._application.getMultiBuildPlateModel()
|
||||
|
||||
self._application.getController().activeViewChanged.connect(self._onActiveViewChanged)
|
||||
self._multi_build_plate_model.activeBuildPlateChanged.connect(self._onActiveViewChanged)
|
||||
|
||||
self._application.globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||
self._onGlobalStackChanged()
|
||||
|
||||
# extruder enable / disable. Actually wanted to use machine manager here, but the initialization order causes it to crash
|
||||
ExtruderManager.getInstance().extrudersChanged.connect(self._extruderChanged)
|
||||
|
||||
self.backendQuit.connect(self._onBackendQuit)
|
||||
self.backendConnected.connect(self._onBackendConnected)
|
||||
|
||||
# When a tool operation is in progress, don't slice. So we need to listen for tool operations.
|
||||
self._application.getController().toolOperationStarted.connect(self._onToolOperationStarted)
|
||||
self._application.getController().toolOperationStopped.connect(self._onToolOperationStopped)
|
||||
|
||||
self._machine_error_checker = self._application.getMachineErrorChecker()
|
||||
self._machine_error_checker.errorCheckFinished.connect(self._onStackErrorCheckFinished)
|
||||
|
||||
## Terminate the engine process.
|
||||
#
|
||||
# This function should terminate the engine process.
|
||||
|
@ -531,11 +541,9 @@ class CuraEngineBackend(QObject, Backend):
|
|||
|
||||
elif property == "validationState":
|
||||
if self._use_timer:
|
||||
self._is_error_check_scheduled = True
|
||||
self._change_timer.stop()
|
||||
|
||||
def _onStackErrorCheckFinished(self):
|
||||
self._is_error_check_scheduled = False
|
||||
if not self._slicing and self._build_plates_to_be_sliced:
|
||||
self.needsSlicing()
|
||||
self._onChanged()
|
||||
|
@ -561,12 +569,15 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self.processingProgress.emit(message.amount)
|
||||
self.backendStateChange.emit(BackendState.Processing)
|
||||
|
||||
# testing
|
||||
def _invokeSlice(self):
|
||||
if self._use_timer:
|
||||
# if the error check is scheduled, wait for the error check finish signal to trigger auto-slice,
|
||||
# otherwise business as usual
|
||||
if self._is_error_check_scheduled:
|
||||
if self._machine_error_checker is None:
|
||||
self._change_timer.stop()
|
||||
return
|
||||
|
||||
if self._machine_error_checker.needToWaitForResult:
|
||||
self._change_timer.stop()
|
||||
else:
|
||||
self._change_timer.start()
|
||||
|
@ -632,7 +643,11 @@ class CuraEngineBackend(QObject, Backend):
|
|||
if self._use_timer:
|
||||
# if the error check is scheduled, wait for the error check finish signal to trigger auto-slice,
|
||||
# otherwise business as usual
|
||||
if self._is_error_check_scheduled:
|
||||
if self._machine_error_checker is None:
|
||||
self._change_timer.stop()
|
||||
return
|
||||
|
||||
if self._machine_error_checker.needToWaitForResult:
|
||||
self._change_timer.stop()
|
||||
else:
|
||||
self._change_timer.start()
|
||||
|
@ -786,7 +801,7 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self._change_timer.start()
|
||||
|
||||
def _extruderChanged(self):
|
||||
for build_plate_number in range(Application.getInstance().getMultiBuildPlateModel().maxBuildPlate + 1):
|
||||
for build_plate_number in range(self._multi_build_plate_model.maxBuildPlate + 1):
|
||||
if build_plate_number not in self._build_plates_to_be_sliced:
|
||||
self._build_plates_to_be_sliced.append(build_plate_number)
|
||||
self._invokeSlice()
|
||||
|
|
|
@ -281,7 +281,7 @@ class StartSliceJob(Job):
|
|||
default_extruder_position = int(Application.getInstance().getMachineManager().defaultExtruderPosition)
|
||||
result = {}
|
||||
for key in stack.getAllKeys():
|
||||
setting_type = stack.getProperty(key, "type")
|
||||
setting_type = stack.definition.getProperty(key, "type")
|
||||
value = stack.getProperty(key, "value")
|
||||
if setting_type == "extruder" and value == -1:
|
||||
# replace with the default value
|
||||
|
|
|
@ -382,6 +382,11 @@ Cura.MachineAction
|
|||
property string settingKey: "machine_nozzle_size"
|
||||
property string label: catalog.i18nc("@label", "Nozzle size")
|
||||
property string unit: catalog.i18nc("@label", "mm")
|
||||
function afterOnEditingFinished()
|
||||
{
|
||||
// Somehow the machine_nozzle_size dependent settings are not updated otherwise
|
||||
Cura.MachineManager.forceUpdateAllSettings()
|
||||
}
|
||||
property bool isExtruderSetting: true
|
||||
}
|
||||
|
||||
|
@ -889,4 +894,4 @@ Cura.MachineAction
|
|||
watchedProperties: [ "value" ]
|
||||
storeIndex: manager.containerIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,14 +22,7 @@ class MonitorStage(CuraStage):
|
|||
|
||||
def _setActivePrintJob(self, print_job):
|
||||
if self._active_print_job != print_job:
|
||||
if self._active_print_job:
|
||||
self._active_print_job.stateChanged.disconnect(self._updateIconSource)
|
||||
self._active_print_job = print_job
|
||||
if self._active_print_job:
|
||||
self._active_print_job.stateChanged.connect(self._updateIconSource)
|
||||
|
||||
# Ensure that the right icon source is returned.
|
||||
self._updateIconSource()
|
||||
|
||||
def _setActivePrinter(self, printer):
|
||||
if self._active_printer != printer:
|
||||
|
@ -43,9 +36,6 @@ class MonitorStage(CuraStage):
|
|||
else:
|
||||
self._setActivePrintJob(None)
|
||||
|
||||
# Ensure that the right icon source is returned.
|
||||
self._updateIconSource()
|
||||
|
||||
def _onActivePrintJobChanged(self):
|
||||
self._setActivePrintJob(self._active_printer.activePrintJob)
|
||||
|
||||
|
@ -58,22 +48,13 @@ class MonitorStage(CuraStage):
|
|||
new_output_device = Application.getInstance().getMachineManager().printerOutputDevices[0]
|
||||
if new_output_device != self._printer_output_device:
|
||||
if self._printer_output_device:
|
||||
self._printer_output_device.acceptsCommandsChanged.disconnect(self._updateIconSource)
|
||||
self._printer_output_device.connectionStateChanged.disconnect(self._updateIconSource)
|
||||
self._printer_output_device.printersChanged.disconnect(self._onActivePrinterChanged)
|
||||
|
||||
self._printer_output_device = new_output_device
|
||||
|
||||
self._printer_output_device.acceptsCommandsChanged.connect(self._updateIconSource)
|
||||
self._printer_output_device.printersChanged.connect(self._onActivePrinterChanged)
|
||||
self._printer_output_device.connectionStateChanged.connect(self._updateIconSource)
|
||||
self._setActivePrinter(self._printer_output_device.activePrinter)
|
||||
|
||||
# Force an update of the icon source
|
||||
self._updateIconSource()
|
||||
except IndexError:
|
||||
#If index error occurs, then the icon on monitor button also should be updated
|
||||
self._updateIconSource()
|
||||
pass
|
||||
|
||||
def _onEngineCreated(self):
|
||||
|
@ -82,7 +63,6 @@ class MonitorStage(CuraStage):
|
|||
self._onOutputDevicesChanged()
|
||||
self._updateMainOverlay()
|
||||
self._updateSidebar()
|
||||
self._updateIconSource()
|
||||
|
||||
def _updateMainOverlay(self):
|
||||
main_component_path = os.path.join(PluginRegistry.getInstance().getPluginPath("MonitorStage"), "MonitorMainView.qml")
|
||||
|
@ -92,46 +72,3 @@ class MonitorStage(CuraStage):
|
|||
# TODO: currently the sidebar component for prepare and monitor stages is the same, this will change with the printer output device refactor!
|
||||
sidebar_component_path = os.path.join(Resources.getPath(Application.getInstance().ResourceTypes.QmlFiles), "Sidebar.qml")
|
||||
self.addDisplayComponent("sidebar", sidebar_component_path)
|
||||
|
||||
def _updateIconSource(self):
|
||||
if Application.getInstance().getTheme() is not None:
|
||||
icon_name = self._getActiveOutputDeviceStatusIcon()
|
||||
self.setIconSource(Application.getInstance().getTheme().getIcon(icon_name))
|
||||
|
||||
## Find the correct status icon depending on the active output device state
|
||||
def _getActiveOutputDeviceStatusIcon(self):
|
||||
# We assume that you are monitoring the device with the highest priority.
|
||||
try:
|
||||
output_device = Application.getInstance().getMachineManager().printerOutputDevices[0]
|
||||
except IndexError:
|
||||
return "tab_status_unknown"
|
||||
|
||||
if not output_device.acceptsCommands:
|
||||
return "tab_status_unknown"
|
||||
|
||||
if output_device.activePrinter is None:
|
||||
return "tab_status_connected"
|
||||
|
||||
# TODO: refactor to use enum instead of hardcoded strings?
|
||||
if output_device.activePrinter.state == "maintenance":
|
||||
return "tab_status_busy"
|
||||
|
||||
if output_device.activePrinter.activePrintJob is None:
|
||||
return "tab_status_connected"
|
||||
|
||||
if output_device.activePrinter.activePrintJob.state in ["printing", "pre_print", "pausing", "resuming"]:
|
||||
return "tab_status_busy"
|
||||
|
||||
if output_device.activePrinter.activePrintJob.state == "wait_cleanup":
|
||||
return "tab_status_finished"
|
||||
|
||||
if output_device.activePrinter.activePrintJob.state in ["ready", ""]:
|
||||
return "tab_status_connected"
|
||||
|
||||
if output_device.activePrinter.activePrintJob.state == "paused":
|
||||
return "tab_status_paused"
|
||||
|
||||
if output_device.activePrinter.activePrintJob.state == "error":
|
||||
return "tab_status_stopped"
|
||||
|
||||
return "tab_status_unknown"
|
||||
|
|
|
@ -158,9 +158,10 @@ class SimulationView(View):
|
|||
return self._nozzle_node
|
||||
|
||||
def _onSceneChanged(self, node):
|
||||
self.setActivity(False)
|
||||
self.calculateMaxLayers()
|
||||
self.calculateMaxPathsOnLayer(self._current_layer_num)
|
||||
if node.getMeshData() is not None:
|
||||
self.setActivity(False)
|
||||
self.calculateMaxLayers()
|
||||
self.calculateMaxPathsOnLayer(self._current_layer_num)
|
||||
|
||||
def isBusy(self):
|
||||
return self._busy
|
||||
|
|
|
@ -22,7 +22,7 @@ from PyQt5.QtCore import pyqtSlot, QUrl, pyqtSignal, pyqtProperty, QObject
|
|||
|
||||
from time import time
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from typing import Optional, Dict, List
|
||||
|
||||
import json
|
||||
import os
|
||||
|
@ -79,7 +79,6 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
|
||||
self._latest_reply_handler = None
|
||||
|
||||
|
||||
def requestWrite(self, nodes, file_name=None, filter_by_machine=False, file_handler=None, **kwargs):
|
||||
self.writeStarted.emit(self)
|
||||
|
||||
|
@ -116,7 +115,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
|
||||
@pyqtSlot()
|
||||
@pyqtSlot(str)
|
||||
def sendPrintJob(self, target_printer = ""):
|
||||
def sendPrintJob(self, target_printer: str = ""):
|
||||
Logger.log("i", "Sending print job to printer.")
|
||||
if self._sending_gcode:
|
||||
self._error_message = Message(
|
||||
|
@ -157,11 +156,11 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
return True
|
||||
|
||||
@pyqtProperty(QObject, notify=activePrinterChanged)
|
||||
def activePrinter(self) -> Optional["PrinterOutputModel"]:
|
||||
def activePrinter(self) -> Optional[PrinterOutputModel]:
|
||||
return self._active_printer
|
||||
|
||||
@pyqtSlot(QObject)
|
||||
def setActivePrinter(self, printer):
|
||||
def setActivePrinter(self, printer: Optional[PrinterOutputModel]):
|
||||
if self._active_printer != printer:
|
||||
if self._active_printer and self._active_printer.camera:
|
||||
self._active_printer.camera.stop()
|
||||
|
@ -173,7 +172,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
self._compressing_gcode = False
|
||||
self._sending_gcode = False
|
||||
|
||||
def _onUploadPrintJobProgress(self, bytes_sent, bytes_total):
|
||||
def _onUploadPrintJobProgress(self, bytes_sent:int, bytes_total:int):
|
||||
if bytes_total > 0:
|
||||
new_progress = bytes_sent / bytes_total * 100
|
||||
# Treat upload progress as response. Uploading can take more than 10 seconds, so if we don't, we can get
|
||||
|
@ -186,7 +185,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
self._progress_message.setProgress(0)
|
||||
self._progress_message.hide()
|
||||
|
||||
def _progressMessageActionTriggered(self, message_id=None, action_id=None):
|
||||
def _progressMessageActionTriggered(self, message_id: Optional[str]=None, action_id: Optional[str]=None) -> None:
|
||||
if action_id == "Abort":
|
||||
Logger.log("d", "User aborted sending print to remote.")
|
||||
self._progress_message.hide()
|
||||
|
@ -202,29 +201,29 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
|
||||
|
||||
@pyqtSlot()
|
||||
def openPrintJobControlPanel(self):
|
||||
def openPrintJobControlPanel(self) -> None:
|
||||
Logger.log("d", "Opening print job control panel...")
|
||||
QDesktopServices.openUrl(QUrl("http://" + self._address + "/print_jobs"))
|
||||
|
||||
@pyqtSlot()
|
||||
def openPrinterControlPanel(self):
|
||||
def openPrinterControlPanel(self) -> None:
|
||||
Logger.log("d", "Opening printer control panel...")
|
||||
QDesktopServices.openUrl(QUrl("http://" + self._address + "/printers"))
|
||||
|
||||
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
||||
def printJobs(self):
|
||||
def printJobs(self)-> List[PrintJobOutputModel] :
|
||||
return self._print_jobs
|
||||
|
||||
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
||||
def queuedPrintJobs(self):
|
||||
def queuedPrintJobs(self) -> List[PrintJobOutputModel]:
|
||||
return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is None or print_job.state == "queued"]
|
||||
|
||||
@pyqtProperty("QVariantList", notify=printJobsChanged)
|
||||
def activePrintJobs(self):
|
||||
def activePrintJobs(self) -> List[PrintJobOutputModel]:
|
||||
return [print_job for print_job in self._print_jobs if print_job.assignedPrinter is not None and print_job.state != "queued"]
|
||||
|
||||
@pyqtProperty("QVariantList", notify=clusterPrintersChanged)
|
||||
def connectedPrintersTypeCount(self):
|
||||
def connectedPrintersTypeCount(self) -> List[PrinterOutputModel]:
|
||||
printer_count = {}
|
||||
for printer in self._printers:
|
||||
if printer.type in printer_count:
|
||||
|
@ -237,22 +236,22 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
return result
|
||||
|
||||
@pyqtSlot(int, result=str)
|
||||
def formatDuration(self, seconds):
|
||||
def formatDuration(self, seconds: int) -> str:
|
||||
return Duration(seconds).getDisplayString(DurationFormat.Format.Short)
|
||||
|
||||
@pyqtSlot(int, result=str)
|
||||
def getTimeCompleted(self, time_remaining):
|
||||
def getTimeCompleted(self, time_remaining: int) -> str:
|
||||
current_time = time()
|
||||
datetime_completed = datetime.fromtimestamp(current_time + time_remaining)
|
||||
return "{hour:02d}:{minute:02d}".format(hour=datetime_completed.hour, minute=datetime_completed.minute)
|
||||
|
||||
@pyqtSlot(int, result=str)
|
||||
def getDateCompleted(self, time_remaining):
|
||||
def getDateCompleted(self, time_remaining: int) -> str:
|
||||
current_time = time()
|
||||
datetime_completed = datetime.fromtimestamp(current_time + time_remaining)
|
||||
return (datetime_completed.strftime("%a %b ") + "{day}".format(day=datetime_completed.day)).upper()
|
||||
|
||||
def _printJobStateChanged(self):
|
||||
def _printJobStateChanged(self) -> None:
|
||||
username = self._getUserName()
|
||||
|
||||
if username is None:
|
||||
|
@ -275,13 +274,13 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
# Keep a list of all completed jobs so we know if something changed next time.
|
||||
self._finished_jobs = finished_jobs
|
||||
|
||||
def _update(self):
|
||||
def _update(self) -> None:
|
||||
if not super()._update():
|
||||
return
|
||||
self.get("printers/", onFinished=self._onGetPrintersDataFinished)
|
||||
self.get("print_jobs/", onFinished=self._onGetPrintJobsFinished)
|
||||
|
||||
def _onGetPrintJobsFinished(self, reply: QNetworkReply):
|
||||
def _onGetPrintJobsFinished(self, reply: QNetworkReply) -> None:
|
||||
if not checkValidGetReply(reply):
|
||||
return
|
||||
|
||||
|
@ -323,7 +322,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
if job_list_changed:
|
||||
self.printJobsChanged.emit() # Do a single emit for all print job changes.
|
||||
|
||||
def _onGetPrintersDataFinished(self, reply: QNetworkReply):
|
||||
def _onGetPrintersDataFinished(self, reply: QNetworkReply) -> None:
|
||||
if not checkValidGetReply(reply):
|
||||
return
|
||||
|
||||
|
@ -352,34 +351,45 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
if removed_printers or printer_list_changed:
|
||||
self.printersChanged.emit()
|
||||
|
||||
def _createPrinterModel(self, data):
|
||||
def _createPrinterModel(self, data: Dict) -> PrinterOutputModel:
|
||||
printer = PrinterOutputModel(output_controller=ClusterUM3PrinterOutputController(self),
|
||||
number_of_extruders=self._number_of_extruders)
|
||||
printer.setCamera(NetworkCamera("http://" + data["ip_address"] + ":8080/?action=stream"))
|
||||
self._printers.append(printer)
|
||||
return printer
|
||||
|
||||
def _createPrintJobModel(self, data):
|
||||
def _createPrintJobModel(self, data: Dict) -> PrintJobOutputModel:
|
||||
print_job = PrintJobOutputModel(output_controller=ClusterUM3PrinterOutputController(self),
|
||||
key=data["uuid"], name= data["name"])
|
||||
print_job.stateChanged.connect(self._printJobStateChanged)
|
||||
self._print_jobs.append(print_job)
|
||||
return print_job
|
||||
|
||||
def _updatePrintJob(self, print_job, data):
|
||||
def _updatePrintJob(self, print_job: PrintJobOutputModel, data: Dict) -> None:
|
||||
print_job.updateTimeTotal(data["time_total"])
|
||||
print_job.updateTimeElapsed(data["time_elapsed"])
|
||||
print_job.updateState(data["status"])
|
||||
print_job.updateOwner(data["owner"])
|
||||
|
||||
def _updatePrinter(self, printer, data):
|
||||
def _updatePrinter(self, printer: PrinterOutputModel, data: Dict) -> None:
|
||||
# For some unknown reason the cluster wants UUID for everything, except for sending a job directly to a printer.
|
||||
# Then we suddenly need the unique name. So in order to not have to mess up all the other code, we save a mapping.
|
||||
self._printer_uuid_to_unique_name_mapping[data["uuid"]] = data["unique_name"]
|
||||
|
||||
definitions = ContainerRegistry.getInstance().findDefinitionContainers(name = data["machine_variant"])
|
||||
if not definitions:
|
||||
Logger.log("w", "Unable to find definition for machine variant %s", data["machine_variant"])
|
||||
return
|
||||
|
||||
machine_definition = definitions[0]
|
||||
|
||||
printer.updateName(data["friendly_name"])
|
||||
printer.updateKey(data["uuid"])
|
||||
printer.updateType(data["machine_variant"])
|
||||
|
||||
# Do not store the buildplate information that comes from connect if the current printer has not buildplate information
|
||||
if "build_plate" in data and machine_definition.getMetaDataEntry("has_variant_buildplates", False):
|
||||
printer.updateBuildplateName(data["build_plate"]["type"])
|
||||
if not data["enabled"]:
|
||||
printer.updateState("disabled")
|
||||
else:
|
||||
|
@ -416,7 +426,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
brand=brand, color=color, name=name)
|
||||
extruder.updateActiveMaterial(material)
|
||||
|
||||
def _removeJob(self, job):
|
||||
def _removeJob(self, job: PrintJobOutputModel):
|
||||
if job not in self._print_jobs:
|
||||
return False
|
||||
|
||||
|
@ -427,7 +437,7 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||
|
||||
return True
|
||||
|
||||
def _removePrinter(self, printer):
|
||||
def _removePrinter(self, printer: PrinterOutputModel):
|
||||
self._printers.remove(printer)
|
||||
if self._active_printer == printer:
|
||||
self._active_printer = None
|
||||
|
|
|
@ -97,6 +97,25 @@ class DiscoverUM3Action(MachineAction):
|
|||
else:
|
||||
return []
|
||||
|
||||
@pyqtSlot(str)
|
||||
def setGroupName(self, group_name):
|
||||
Logger.log("d", "Attempting to set the group name of the active machine to %s", group_name)
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if global_container_stack:
|
||||
meta_data = global_container_stack.getMetaData()
|
||||
if "connect_group_name" in meta_data:
|
||||
previous_connect_group_name = meta_data["connect_group_name"]
|
||||
global_container_stack.setMetaDataEntry("connect_group_name", group_name)
|
||||
# Find all the places where there is the same group name and change it accordingly
|
||||
Application.getInstance().getMachineManager().replaceContainersMetadata(key = "connect_group_name", value = previous_connect_group_name, new_value = group_name)
|
||||
else:
|
||||
global_container_stack.addMetaDataEntry("connect_group_name", group_name)
|
||||
global_container_stack.addMetaDataEntry("hidden", False)
|
||||
|
||||
if self._network_plugin:
|
||||
# Ensure that the connection states are refreshed.
|
||||
self._network_plugin.reCheckConnections()
|
||||
|
||||
@pyqtSlot(str)
|
||||
def setKey(self, key):
|
||||
Logger.log("d", "Attempting to set the network key of the active machine to %s", key)
|
||||
|
@ -104,11 +123,13 @@ class DiscoverUM3Action(MachineAction):
|
|||
if global_container_stack:
|
||||
meta_data = global_container_stack.getMetaData()
|
||||
if "um_network_key" in meta_data:
|
||||
previous_network_key= meta_data["um_network_key"]
|
||||
global_container_stack.setMetaDataEntry("um_network_key", key)
|
||||
# Delete old authentication data.
|
||||
Logger.log("d", "Removing old authentication id %s for device %s", global_container_stack.getMetaDataEntry("network_authentication_id", None), key)
|
||||
global_container_stack.removeMetaDataEntry("network_authentication_id")
|
||||
global_container_stack.removeMetaDataEntry("network_authentication_key")
|
||||
Application.getInstance().getMachineManager().replaceContainersMetadata(key = "um_network_key", value = previous_network_key, new_value = key)
|
||||
else:
|
||||
global_container_stack.addMetaDataEntry("um_network_key", key)
|
||||
|
||||
|
|
|
@ -32,10 +32,12 @@ Cura.MachineAction
|
|||
if(base.selectedDevice && base.completeProperties)
|
||||
{
|
||||
var printerKey = base.selectedDevice.key
|
||||
var printerName = base.selectedDevice.name // TODO To change when the groups have a name
|
||||
if(manager.getStoredKey() != printerKey)
|
||||
{
|
||||
manager.setKey(printerKey);
|
||||
completed();
|
||||
manager.setKey(printerKey)
|
||||
manager.setGroupName(printerName) // TODO To change when the groups have a name
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -303,7 +305,7 @@ Cura.MachineAction
|
|||
Button
|
||||
{
|
||||
text: catalog.i18nc("@action:button", "Connect")
|
||||
enabled: (base.selectedDevice && base.completeProperties) ? true : false
|
||||
enabled: (base.selectedDevice && base.completeProperties && base.selectedDevice.clusterSize > 0) ? true : false
|
||||
onClicked: connectToPrinter()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ class AutoDetectBaudJob(Job):
|
|||
def run(self):
|
||||
Logger.log("d", "Auto detect baud rate started.")
|
||||
timeout = 3
|
||||
tries = 2
|
||||
|
||||
programmer = Stk500v2()
|
||||
serial = None
|
||||
|
@ -31,36 +32,38 @@ class AutoDetectBaudJob(Job):
|
|||
except:
|
||||
programmer.close()
|
||||
|
||||
for baud_rate in self._all_baud_rates:
|
||||
Logger.log("d", "Checking {serial} if baud rate {baud_rate} works".format(serial= self._serial_port, baud_rate = baud_rate))
|
||||
for retry in range(tries):
|
||||
for baud_rate in self._all_baud_rates:
|
||||
Logger.log("d", "Checking {serial} if baud rate {baud_rate} works".format(serial= self._serial_port, baud_rate = baud_rate))
|
||||
|
||||
if serial is None:
|
||||
try:
|
||||
serial = Serial(str(self._serial_port), baud_rate, timeout = timeout, writeTimeout = timeout)
|
||||
except SerialException as e:
|
||||
Logger.logException("w", "Unable to create serial")
|
||||
continue
|
||||
else:
|
||||
# We already have a serial connection, just change the baud rate.
|
||||
try:
|
||||
serial.baudrate = baud_rate
|
||||
except:
|
||||
continue
|
||||
sleep(1.5) # Ensure that we are not talking to the boot loader. 1.5 seconds seems to be the magic number
|
||||
successful_responses = 0
|
||||
|
||||
serial.write(b"\n") # Ensure we clear out previous responses
|
||||
serial.write(b"M105\n")
|
||||
|
||||
timeout_time = time() + timeout
|
||||
|
||||
while timeout_time > time():
|
||||
line = serial.readline()
|
||||
if b"ok T:" in line:
|
||||
successful_responses += 1
|
||||
if successful_responses >= 3:
|
||||
self.setResult(baud_rate)
|
||||
return
|
||||
if serial is None:
|
||||
try:
|
||||
serial = Serial(str(self._serial_port), baud_rate, timeout = timeout, writeTimeout = timeout)
|
||||
except SerialException as e:
|
||||
Logger.logException("w", "Unable to create serial")
|
||||
continue
|
||||
else:
|
||||
# We already have a serial connection, just change the baud rate.
|
||||
try:
|
||||
serial.baudrate = baud_rate
|
||||
except:
|
||||
continue
|
||||
sleep(1.5) # Ensure that we are not talking to the boot loader. 1.5 seconds seems to be the magic number
|
||||
successful_responses = 0
|
||||
|
||||
serial.write(b"\n") # Ensure we clear out previous responses
|
||||
serial.write(b"M105\n")
|
||||
|
||||
timeout_time = time() + timeout
|
||||
|
||||
while timeout_time > time():
|
||||
line = serial.readline()
|
||||
if b"ok T:" in line:
|
||||
successful_responses += 1
|
||||
if successful_responses >= 3:
|
||||
self.setResult(baud_rate)
|
||||
return
|
||||
|
||||
serial.write(b"M105\n")
|
||||
sleep(15) # Give the printer some time to init and try again.
|
||||
self.setResult(None) # Unable to detect the correct baudrate.
|
||||
|
|
|
@ -116,7 +116,8 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
|
||||
@pyqtSlot(str)
|
||||
def updateFirmware(self, file):
|
||||
self._firmware_location = file
|
||||
# the file path is qurl encoded.
|
||||
self._firmware_location = file.replace("file://", "")
|
||||
self.showFirmwareInterface()
|
||||
self.setFirmwareUpdateState(FirmwareUpdateState.updating)
|
||||
self._update_firmware_thread.start()
|
||||
|
@ -126,9 +127,11 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
if self._connection_state != ConnectionState.closed:
|
||||
self.close()
|
||||
|
||||
hex_file = intelHex.readHex(self._firmware_location)
|
||||
if len(hex_file) == 0:
|
||||
Logger.log("e", "Unable to read provided hex file. Could not update firmware")
|
||||
try:
|
||||
hex_file = intelHex.readHex(self._firmware_location)
|
||||
assert len(hex_file) > 0
|
||||
except (FileNotFoundError, AssertionError):
|
||||
Logger.log("e", "Unable to read provided hex file. Could not update firmware.")
|
||||
self.setFirmwareUpdateState(FirmwareUpdateState.firmware_not_found_error)
|
||||
return
|
||||
|
||||
|
@ -198,7 +201,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
# Reset line number. If this is not done, first line is sometimes ignored
|
||||
self._gcode.insert(0, "M110")
|
||||
self._gcode_position = 0
|
||||
self._is_printing = True
|
||||
self._print_start_time = time()
|
||||
|
||||
self._print_estimated_time = int(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.Seconds))
|
||||
|
@ -206,6 +208,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
for i in range(0, 4): # Push first 4 entries before accepting other inputs
|
||||
self._sendNextGcodeLine()
|
||||
|
||||
self._is_printing = True
|
||||
self.writeFinished.emit(self)
|
||||
|
||||
def _autoDetectFinished(self, job: AutoDetectBaudJob):
|
||||
|
@ -267,7 +270,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
if not command.endswith(b"\n"):
|
||||
command += b"\n"
|
||||
try:
|
||||
self._serial.write(b"\n")
|
||||
self._serial.write(command)
|
||||
except SerialTimeoutException:
|
||||
Logger.log("w", "Timeout when sending command to printer via USB.")
|
||||
|
@ -284,7 +286,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
self.sendCommand("M105")
|
||||
self._last_temperature_request = time()
|
||||
|
||||
if b"ok T:" in line or line.startswith(b"T:"): # Temperature message
|
||||
if b"ok T:" in line or line.startswith(b"T:") or b"ok B:" in line or line.startswith(b"B:"): # Temperature message. 'T:' for extruder and 'B:' for bed
|
||||
extruder_temperature_matches = re.findall(b"T(\d*): ?([\d\.]+) ?\/?([\d\.]+)?", line)
|
||||
# Update all temperature values
|
||||
for match, extruder in zip(extruder_temperature_matches, self._printers[0].extruders):
|
||||
|
@ -302,6 +304,9 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
self._printers[0].updateTargetBedTemperature(float(match[1]))
|
||||
|
||||
if self._is_printing:
|
||||
if line.startswith(b'!!'):
|
||||
Logger.log('e', "Printer signals fatal error. Cancelling print. {}".format(line))
|
||||
self.cancelPrint()
|
||||
if b"ok" in line:
|
||||
if not self._command_queue.empty():
|
||||
self._sendCommand(self._command_queue.get())
|
||||
|
|
|
@ -56,6 +56,8 @@ _EXTRUDER_TO_POSITION = {
|
|||
## Upgrades configurations from the state they were in at version 3.2 to the
|
||||
# state they should be in at version 3.3.
|
||||
class VersionUpgrade32to33(VersionUpgrade):
|
||||
|
||||
temporary_group_name_counter = 1
|
||||
## Gets the version number from a CFG file in Uranium's 3.2 format.
|
||||
#
|
||||
# Since the format may change, this is implemented for the 3.2 format only
|
||||
|
@ -74,6 +76,28 @@ class VersionUpgrade32to33(VersionUpgrade):
|
|||
setting_version = int(parser.get("metadata", "setting_version", fallback = 0))
|
||||
return format_version * 1000000 + setting_version
|
||||
|
||||
## Upgrades a container stack from version 3.2 to 3.3.
|
||||
#
|
||||
# \param serialised The serialised form of a container stack.
|
||||
# \param filename The name of the file to upgrade.
|
||||
def upgradeStack(self, serialized, filename):
|
||||
parser = configparser.ConfigParser(interpolation = None)
|
||||
parser.read_string(serialized)
|
||||
|
||||
if "metadata" in parser and "um_network_key" in parser["metadata"]:
|
||||
if "hidden" not in parser["metadata"]:
|
||||
parser["metadata"]["hidden"] = "False"
|
||||
if "connect_group_name" not in parser["metadata"]:
|
||||
parser["metadata"]["connect_group_name"] = "Temporary group name #" + str(self.temporary_group_name_counter)
|
||||
self.temporary_group_name_counter += 1
|
||||
|
||||
#Update version number.
|
||||
parser["general"]["version"] = "4"
|
||||
|
||||
result = io.StringIO()
|
||||
parser.write(result)
|
||||
return [filename], [result.getvalue()]
|
||||
|
||||
## Upgrades non-quality-changes instance containers to have the new version
|
||||
# number.
|
||||
def upgradeInstanceContainer(self, serialized, filename):
|
||||
|
|
|
@ -9,11 +9,22 @@ def getMetaData():
|
|||
return {
|
||||
"version_upgrade": {
|
||||
# From To Upgrade function
|
||||
("machine_stack", 3000004): ("machine_stack", 4000004, upgrade.upgradeStack),
|
||||
("extruder_train", 3000004): ("extruder_train", 4000004, upgrade.upgradeStack),
|
||||
|
||||
("definition_changes", 2000004): ("definition_changes", 3000004, upgrade.upgradeInstanceContainer),
|
||||
("quality_changes", 2000004): ("quality_changes", 3000004, upgrade.upgradeQualityChanges),
|
||||
("user", 2000004): ("user", 3000004, upgrade.upgradeInstanceContainer)
|
||||
},
|
||||
"sources": {
|
||||
"machine_stack": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"./machine_instances"}
|
||||
},
|
||||
"extruder_train": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"./extruders"}
|
||||
},
|
||||
"definition_changes": {
|
||||
"get_version": upgrade.getCfgVersion,
|
||||
"location": {"./definition_changes"}
|
||||
|
|
|
@ -277,7 +277,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
|
||||
# Compatible is a special case, as it's added as a meta data entry (instead of an instance).
|
||||
material_container = variant_dict["material_container"]
|
||||
compatible = container.getMetaDataEntry("compatible")
|
||||
compatible = material_container.getMetaDataEntry("compatible")
|
||||
if compatible is not None:
|
||||
builder.start("setting", {"key": "hardware compatible"})
|
||||
if compatible:
|
||||
|
@ -838,15 +838,11 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
if machine_compatibility:
|
||||
new_material_id = container_id + "_" + machine_id
|
||||
|
||||
# The child or derived material container may already exist. This can happen when a material in a
|
||||
# project file and the a material in Cura have the same ID.
|
||||
# In the case if a derived material already exists, override that material container because if
|
||||
# the data in the parent material has been changed, the derived ones should be updated too.
|
||||
found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_material_id)
|
||||
if found_materials:
|
||||
new_material_metadata = found_materials[0]
|
||||
else:
|
||||
new_material_metadata = {}
|
||||
# Do not look for existing container/container metadata with the same ID although they may exist.
|
||||
# In project loading and perhaps some other places, we only want to get information (metadata)
|
||||
# from a file without changing the current state of the system. If we overwrite the existing
|
||||
# metadata here, deserializeMetadata() will not be safe for retrieving information.
|
||||
new_material_metadata = {}
|
||||
|
||||
new_material_metadata.update(base_metadata)
|
||||
new_material_metadata["id"] = new_material_id
|
||||
|
@ -854,8 +850,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
new_material_metadata["machine_manufacturer"] = machine_manufacturer
|
||||
new_material_metadata["definition"] = machine_id
|
||||
|
||||
if len(found_materials) == 0: #This is a new material.
|
||||
result_metadata.append(new_material_metadata)
|
||||
result_metadata.append(new_material_metadata)
|
||||
|
||||
buildplates = machine.iterfind("./um:buildplate", cls.__namespaces)
|
||||
buildplate_map = {}
|
||||
|
@ -866,12 +861,12 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
if buildplate_id is None:
|
||||
continue
|
||||
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = buildplate_id)
|
||||
if not variant_containers:
|
||||
variant_metadata = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = buildplate_id)
|
||||
if not variant_metadata:
|
||||
# It is not really properly defined what "ID" is so also search for variants by name.
|
||||
variant_containers = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = buildplate_id)
|
||||
variant_metadata = ContainerRegistry.getInstance().findInstanceContainersMetadata(definition = machine_id, name = buildplate_id)
|
||||
|
||||
if not variant_containers:
|
||||
if not variant_metadata:
|
||||
continue
|
||||
|
||||
settings = buildplate.iterfind("./um:setting", cls.__namespaces)
|
||||
|
@ -900,12 +895,8 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
|
||||
new_hotend_specific_material_id = container_id + "_" + machine_id + "_" + hotend_name.replace(" ", "_")
|
||||
|
||||
# Same as machine compatibility, keep the derived material containers consistent with the parent material
|
||||
found_materials = ContainerRegistry.getInstance().findInstanceContainersMetadata(id = new_hotend_specific_material_id)
|
||||
if found_materials:
|
||||
new_hotend_material_metadata = found_materials[0]
|
||||
else:
|
||||
new_hotend_material_metadata = {}
|
||||
# Same as above, do not overwrite existing metadata.
|
||||
new_hotend_material_metadata = {}
|
||||
|
||||
new_hotend_material_metadata.update(base_metadata)
|
||||
new_hotend_material_metadata["variant_name"] = hotend_name
|
||||
|
@ -917,8 +908,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
new_hotend_material_metadata["buildplate_compatible"] = buildplate_map["buildplate_compatible"]
|
||||
new_hotend_material_metadata["buildplate_recommended"] = buildplate_map["buildplate_recommended"]
|
||||
|
||||
if len(found_materials) == 0:
|
||||
result_metadata.append(new_hotend_material_metadata)
|
||||
result_metadata.append(new_hotend_material_metadata)
|
||||
|
||||
# there is only one ID for a machine. Once we have reached here, it means we have already found
|
||||
# a workable ID for that machine, so there is no need to continue
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue