mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-08-09 14:55:03 -06:00
Merge branch 'master' into feature_multiextruder_machinesettings
This commit is contained in:
commit
4d12ab1296
157 changed files with 24335 additions and 2374 deletions
|
@ -179,6 +179,7 @@ class GCodeReader(MeshReader):
|
|||
|
||||
def _processGCode(self, G, line, position, path):
|
||||
func = getattr(self, "_gCode%s" % G, None)
|
||||
line = line.split(";", 1)[0] # Remove comments (if any)
|
||||
if func is not None:
|
||||
s = line.upper().split(" ")
|
||||
x, y, z, e = None, None, None, None
|
||||
|
|
|
@ -200,7 +200,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
|||
|
||||
def _onAuthenticationRequired(self, reply, authenticator):
|
||||
if self._authentication_id is not None and self._authentication_key is not None:
|
||||
Logger.log("d", "Authentication was required. Setting up authenticator with ID %s and key", self._authentication_id, self._getSafeAuthKey())
|
||||
Logger.log("d", "Authentication was required. Setting up authenticator with ID %s and key %s", self._authentication_id, self._getSafeAuthKey())
|
||||
authenticator.setUser(self._authentication_id)
|
||||
authenticator.setPassword(self._authentication_key)
|
||||
else:
|
||||
|
@ -283,10 +283,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
|||
#
|
||||
# /param temperature The new target temperature of the bed.
|
||||
def _setTargetBedTemperature(self, temperature):
|
||||
if self._target_bed_temperature == temperature:
|
||||
if not self._updateTargetBedTemperature(temperature):
|
||||
return
|
||||
self._target_bed_temperature = temperature
|
||||
self.targetBedTemperatureChanged.emit()
|
||||
|
||||
url = QUrl("http://" + self._address + self._api_prefix + "printer/bed/temperature/target")
|
||||
data = str(temperature)
|
||||
|
@ -294,6 +292,17 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
|||
put_request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
self._manager.put(put_request, data.encode())
|
||||
|
||||
## Updates the target bed temperature from the printer, and emit a signal if it was changed.
|
||||
#
|
||||
# /param temperature The new target temperature of the bed.
|
||||
# /return boolean, True if the temperature was changed, false if the new temperature has the same value as the already stored temperature
|
||||
def _updateTargetBedTemperature(self, temperature):
|
||||
if self._target_bed_temperature == temperature:
|
||||
return False
|
||||
self._target_bed_temperature = temperature
|
||||
self.targetBedTemperatureChanged.emit()
|
||||
return True
|
||||
|
||||
def _stopCamera(self):
|
||||
self._camera_timer.stop()
|
||||
if self._image_reply:
|
||||
|
@ -528,7 +537,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
|||
bed_temperature = self._json_printer_state["bed"]["temperature"]["current"]
|
||||
self._setBedTemperature(bed_temperature)
|
||||
target_bed_temperature = self._json_printer_state["bed"]["temperature"]["target"]
|
||||
self._setTargetBedTemperature(target_bed_temperature)
|
||||
self._updateTargetBedTemperature(target_bed_temperature)
|
||||
|
||||
head_x = self._json_printer_state["heads"][0]["position"]["x"]
|
||||
head_y = self._json_printer_state["heads"][0]["position"]["y"]
|
||||
|
@ -716,7 +725,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
|||
|
||||
## Start requesting data from printer
|
||||
def connect(self):
|
||||
self.close() # Ensure that previous connection (if any) is killed.
|
||||
if self.isConnected():
|
||||
self.close() # Close previous connection
|
||||
|
||||
self._createNetworkManager()
|
||||
|
||||
|
@ -815,10 +825,10 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
|||
return # Stop trying to zip, abort was called.
|
||||
|
||||
if self._use_gzip:
|
||||
batched_line += line
|
||||
# if the gcode was read from a gcode file, self._gcode will be a list of all lines in that file.
|
||||
# Compressing line by line in this case is extremely slow, so we need to batch them.
|
||||
if len(batched_line) < max_chars_per_line:
|
||||
batched_line += line
|
||||
continue
|
||||
|
||||
byte_array_file_data += _compress_data_and_notify_qt(batched_line)
|
||||
|
@ -1088,7 +1098,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
|||
|
||||
self._authentication_key = data["key"]
|
||||
self._authentication_id = data["id"]
|
||||
Logger.log("i", "Got a new authentication ID (%s) and KEY (%S). Waiting for authorization.", self._authentication_id, self._getSafeAuthKey())
|
||||
Logger.log("i", "Got a new authentication ID (%s) and KEY (%s). Waiting for authorization.", self._authentication_id, self._getSafeAuthKey())
|
||||
|
||||
# Check if the authentication is accepted.
|
||||
self._checkAuthentication()
|
||||
|
|
|
@ -157,13 +157,15 @@ class NetworkPrinterOutputDevicePlugin(OutputDevicePlugin):
|
|||
|
||||
for key in self._printers:
|
||||
if key == active_machine.getMetaDataEntry("um_network_key"):
|
||||
Logger.log("d", "Connecting [%s]..." % key)
|
||||
self._printers[key].connect()
|
||||
self._printers[key].connectionStateChanged.connect(self._onPrinterConnectionStateChanged)
|
||||
if not self._printers[key].isConnected():
|
||||
Logger.log("d", "Connecting [%s]..." % key)
|
||||
self._printers[key].connect()
|
||||
self._printers[key].connectionStateChanged.connect(self._onPrinterConnectionStateChanged)
|
||||
else:
|
||||
if self._printers[key].isConnected():
|
||||
Logger.log("d", "Closing connection [%s]..." % key)
|
||||
self._printers[key].close()
|
||||
self._printers[key].connectionStateChanged.disconnect(self._onPrinterConnectionStateChanged)
|
||||
|
||||
## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
|
||||
def addPrinter(self, name, address, properties):
|
||||
|
@ -181,9 +183,9 @@ class NetworkPrinterOutputDevicePlugin(OutputDevicePlugin):
|
|||
printer = self._printers.pop(name, None)
|
||||
if printer:
|
||||
if printer.isConnected():
|
||||
printer.disconnect()
|
||||
printer.connectionStateChanged.disconnect(self._onPrinterConnectionStateChanged)
|
||||
Logger.log("d", "removePrinter, disconnecting [%s]..." % name)
|
||||
printer.disconnect()
|
||||
self.printerListChanged.emit()
|
||||
|
||||
## Handler for when the connection state of one of the detected printers changes
|
||||
|
|
|
@ -148,6 +148,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
## Start a print based on a g-code.
|
||||
# \param gcode_list List with gcode (strings).
|
||||
def printGCode(self, gcode_list):
|
||||
Logger.log("d", "Started printing g-code")
|
||||
if self._progress or self._connection_state != ConnectionState.connected:
|
||||
self._error_message = Message(catalog.i18nc("@info:status", "Unable to start a new job because the printer is busy or not connected."))
|
||||
self._error_message.show()
|
||||
|
@ -183,6 +184,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
|
||||
## Private function (threaded) that actually uploads the firmware.
|
||||
def _updateFirmware(self):
|
||||
Logger.log("d", "Attempting to update firmware")
|
||||
self._error_code = 0
|
||||
self.setProgress(0, 100)
|
||||
self._firmware_update_finished = False
|
||||
|
@ -536,6 +538,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
self._sendNextGcodeLine()
|
||||
elif b"resend" in line.lower() or b"rs" in line: # Because a resend can be asked with "resend" and "rs"
|
||||
try:
|
||||
Logger.log("d", "Got a resend response")
|
||||
self._gcode_position = int(line.replace(b"N:",b" ").replace(b"N",b" ").replace(b":",b" ").split()[-1])
|
||||
except:
|
||||
if b"rs" in line:
|
||||
|
@ -563,19 +566,19 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
line = line[:line.find(";")]
|
||||
line = line.strip()
|
||||
|
||||
# Don't send empty lines. But we do have to send something, so send m105 instead.
|
||||
if line == "":
|
||||
# Don't send empty lines. But we do have to send something, so send
|
||||
# m105 instead.
|
||||
# Don't send the M0 or M1 to the machine, as M0 and M1 are handled as
|
||||
# an LCD menu pause.
|
||||
if line == "" or line == "M0" or line == "M1":
|
||||
line = "M105"
|
||||
|
||||
try:
|
||||
if line == "M0" or line == "M1":
|
||||
line = "M105" # Don't send the M0 or M1 to the machine, as M0 and M1 are handled as an LCD menu pause.
|
||||
if ("G0" in line or "G1" in line) and "Z" in line:
|
||||
z = float(re.search("Z([0-9\.]*)", line).group(1))
|
||||
if self._current_z != z:
|
||||
self._current_z = z
|
||||
except Exception as e:
|
||||
Logger.log("e", "Unexpected error with printer connection: %s" % e)
|
||||
Logger.log("e", "Unexpected error with printer connection, could not parse current Z: %s: %s" % (e, line))
|
||||
self._setErrorState("Unexpected error: %s" %e)
|
||||
checksum = functools.reduce(lambda x,y: x^y, map(ord, "N%d%s" % (self._gcode_position, line)))
|
||||
|
||||
|
@ -674,4 +677,4 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
|||
def cancelPreheatBed(self):
|
||||
Logger.log("i", "Cancelling pre-heating of the bed.")
|
||||
self._setTargetBedTemperature(0)
|
||||
self.preheatBedRemainingTimeChanged.emit()
|
||||
self.preheatBedRemainingTimeChanged.emit()
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import copy
|
||||
import io
|
||||
from typing import Optional
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from UM.Resources import Resources
|
||||
|
@ -11,7 +12,7 @@ from UM.Util import parseBool
|
|||
from cura.CuraApplication import CuraApplication
|
||||
|
||||
import UM.Dictionary
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Settings.InstanceContainer import InstanceContainer, InvalidInstanceError
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
|
||||
## Handles serializing and deserializing material containers from an XML file
|
||||
|
@ -118,6 +119,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
metadata.pop("variant", "")
|
||||
metadata.pop("type", "")
|
||||
metadata.pop("base_file", "")
|
||||
metadata.pop("approximate_diameter", "")
|
||||
|
||||
## Begin Name Block
|
||||
builder.start("name")
|
||||
|
@ -369,8 +371,30 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
self._dirty = False
|
||||
self._path = ""
|
||||
|
||||
def getConfigurationTypeFromSerialized(self, serialized: str) -> Optional[str]:
|
||||
return "material"
|
||||
|
||||
def getVersionFromSerialized(self, serialized: str) -> Optional[int]:
|
||||
version = None
|
||||
data = ET.fromstring(serialized)
|
||||
metadata = data.iterfind("./um:metadata/*", self.__namespaces)
|
||||
for entry in metadata:
|
||||
tag_name = _tag_without_namespace(entry)
|
||||
if tag_name == "version":
|
||||
try:
|
||||
version = int(entry.text)
|
||||
except Exception as e:
|
||||
raise InvalidInstanceError("Invalid version string '%s': %s" % (entry.text, e))
|
||||
break
|
||||
if version is None:
|
||||
raise InvalidInstanceError("Missing version in metadata")
|
||||
return version
|
||||
|
||||
## Overridden from InstanceContainer
|
||||
def deserialize(self, serialized):
|
||||
# update the serialized data first
|
||||
from UM.Settings.Interfaces import ContainerInterface
|
||||
serialized = ContainerInterface.deserialize(self, serialized)
|
||||
data = ET.fromstring(serialized)
|
||||
|
||||
# Reset previous metadata
|
||||
|
@ -405,10 +429,10 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
continue
|
||||
meta_data[tag_name] = entry.text
|
||||
|
||||
if not "description" in meta_data:
|
||||
if "description" not in meta_data:
|
||||
meta_data["description"] = ""
|
||||
|
||||
if not "adhesion_info" in meta_data:
|
||||
if "adhesion_info" not in meta_data:
|
||||
meta_data["adhesion_info"] = ""
|
||||
|
||||
property_values = {}
|
||||
|
@ -437,6 +461,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
Logger.log("d", "Unsupported material setting %s", key)
|
||||
self._cached_values = global_setting_values
|
||||
|
||||
meta_data["approximate_diameter"] = round(diameter)
|
||||
meta_data["compatible"] = global_compatibility
|
||||
self.setMetaData(meta_data)
|
||||
self._dirty = False
|
||||
|
@ -581,7 +606,8 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
"Ultimaker 2 Extended": "ultimaker2_extended",
|
||||
"Ultimaker 2 Extended+": "ultimaker2_extended_plus",
|
||||
"Ultimaker Original": "ultimaker_original",
|
||||
"Ultimaker Original+": "ultimaker_original_plus"
|
||||
"Ultimaker Original+": "ultimaker_original_plus",
|
||||
"IMADE3D JellyBOX": "imade3d_jellybox"
|
||||
}
|
||||
|
||||
# Map of recognised namespaces with a proper prefix.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue