Merge branch 'master' of github.com:Ultimaker/Cura

This commit is contained in:
Ghostkeeper 2017-12-01 15:37:11 +01:00
commit af8176d309
No known key found for this signature in database
GPG Key ID: 5252B696FB5E7C7A
3 changed files with 122 additions and 42 deletions

View File

@ -252,6 +252,8 @@ class NetworkClusterPrinterOutputDevice(NetworkPrinterOutputDevice.NetworkPrinte
self._error_message.show() self._error_message.show()
return return
self.writeStarted.emit(self) # Allow postprocessing before sending data to the printer
if len(self._printers) > 1: if len(self._printers) > 1:
self.spawnPrintView() # Ask user how to print it. self.spawnPrintView() # Ask user how to print it.
elif len(self._printers) == 1: elif len(self._printers) == 1:

View File

@ -13,6 +13,7 @@ from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState from cura.PrinterOutputDevice import PrinterOutputDevice, ConnectionState
from UM.Message import Message from UM.Message import Message
from UM.Qt.Duration import DurationFormat
from PyQt5.QtCore import QUrl, pyqtSlot, pyqtSignal, pyqtProperty from PyQt5.QtCore import QUrl, pyqtSlot, pyqtSignal, pyqtProperty
@ -52,6 +53,8 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._heatup_wait_start_time = time.time() self._heatup_wait_start_time = time.time()
self.jobStateChanged.connect(self._onJobStateChanged)
## Queue for commands that need to be send. Used when command is sent when a print is active. ## Queue for commands that need to be send. Used when command is sent when a print is active.
self._command_queue = queue.Queue() self._command_queue = queue.Queue()
@ -60,7 +63,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
## Set when print is started in order to check running time. ## Set when print is started in order to check running time.
self._print_start_time = None self._print_start_time = None
self._print_start_time_100 = None self._print_estimated_time = None
## Keep track where in the provided g-code the print is ## Keep track where in the provided g-code the print is
self._gcode_position = 0 self._gcode_position = 0
@ -125,6 +128,29 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
def _homeBed(self): def _homeBed(self):
self._sendCommand("G28 Z") self._sendCommand("G28 Z")
## 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
## Updates the target hotend temperature from the printer, and emit a signal if it was changed.
#
# /param index The index of the hotend.
# /param temperature The new target temperature of the hotend.
# /return boolean, True if the temperature was changed, false if the new temperature has the same value as the already stored temperature
def _updateTargetHotendTemperature(self, index, temperature):
if self._target_hotend_temperatures[index] == temperature:
return False
self._target_hotend_temperatures[index] = temperature
self.targetHotendTemperaturesChanged.emit()
return True
## A name for the device. ## A name for the device.
@pyqtProperty(str, constant = True) @pyqtProperty(str, constant = True)
def name(self): def name(self):
@ -164,7 +190,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
# Reset line number. If this is not done, first line is sometimes ignored # Reset line number. If this is not done, first line is sometimes ignored
self._gcode.insert(0, "M110") self._gcode.insert(0, "M110")
self._gcode_position = 0 self._gcode_position = 0
self._print_start_time_100 = None
self._is_printing = True self._is_printing = True
self._print_start_time = time.time() self._print_start_time = time.time()
@ -447,7 +472,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
# #
# \param nodes A collection of scene nodes to send. This is ignored. # \param nodes A collection of scene nodes to send. This is ignored.
# \param file_name \type{string} A suggestion for a file name to write. # \param file_name \type{string} A suggestion for a file name to write.
# This is ignored.
# \param filter_by_machine Whether to filter MIME types by machine. This # \param filter_by_machine Whether to filter MIME types by machine. This
# is ignored. # is ignored.
# \param kwargs Keyword arguments. # \param kwargs Keyword arguments.
@ -463,6 +487,9 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._error_message.show() self._error_message.show()
return return
self.setJobName(file_name)
self._print_estimated_time = int(Application.getInstance().getPrintInformation().currentPrintTime.getDisplayString(DurationFormat.Format.Seconds))
Application.getInstance().showPrintMonitor.emit(True) Application.getInstance().showPrintMonitor.emit(True)
self.startPrint() self.startPrint()
@ -483,6 +510,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
## Listen thread function. ## Listen thread function.
def _listen(self): def _listen(self):
Logger.log("i", "Printer connection listen thread started for %s" % self._serial_port) Logger.log("i", "Printer connection listen thread started for %s" % self._serial_port)
container_stack = Application.getInstance().getGlobalContainerStack()
temperature_request_timeout = time.time() temperature_request_timeout = time.time()
ok_timeout = time.time() ok_timeout = time.time()
while self._connection_state == ConnectionState.connected: while self._connection_state == ConnectionState.connected:
@ -512,16 +540,40 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
self._setErrorState(line[6:]) self._setErrorState(line[6:])
elif b" T:" in line or line.startswith(b"T:"): # Temperature message elif b" T:" in line or line.startswith(b"T:"): # Temperature message
temperature_matches = re.findall(b"T(\d*): ?([\d\.]+) ?\/?([\d\.]+)?", line)
temperature_set = False
try: try:
self._setHotendTemperature(self._temperature_requested_extruder_index, float(re.search(b"T: *([0-9\.]*)", line).group(1))) for match in temperature_matches:
if match[0]:
extruder_nr = int(match[0])
if extruder_nr >= container_stack.getProperty("machine_extruder_count", "value"):
continue
if match[1]:
self._setHotendTemperature(extruder_nr, float(match[1]))
temperature_set = True
if match[2]:
self._updateTargetHotendTemperature(extruder_nr, float(match[2]))
else:
requested_temperatures = match
if not temperature_set and requested_temperatures:
if requested_temperatures[1]:
self._setHotendTemperature(self._temperature_requested_extruder_index, float(requested_temperatures[1]))
if requested_temperatures[2]:
self._updateTargetHotendTemperature(self._temperature_requested_extruder_index, float(requested_temperatures[2]))
except: except:
pass Logger.log("w", "Could not parse hotend temperatures from response: %s", line)
if b"B:" in line: # Check if it's a bed temperature # Check if there's also a bed temperature
temperature_matches = re.findall(b"B: ?([\d\.]+) ?\/?([\d\.]+)?", line)
if container_stack.getProperty("machine_heated_bed", "value") and len(temperature_matches) > 0:
match = temperature_matches[0]
try: try:
self._setBedTemperature(float(re.search(b"B: *([0-9\.]*)", line).group(1))) if match[0]:
except Exception as e: self._setBedTemperature(float(match[0]))
pass if match[1]:
#TODO: temperature changed callback self._updateTargetBedTemperature(float(match[1]))
except:
Logger.log("w", "Could not parse bed temperature from response: %s", line)
elif b"_min" in line or b"_max" in line: elif b"_min" in line or b"_max" in line:
tag, value = line.split(b":", 1) tag, value = line.split(b":", 1)
self._setEndstopState(tag,(b"H" in value or b"TRIGGERED" in value)) self._setEndstopState(tag,(b"H" in value or b"TRIGGERED" in value))
@ -560,8 +612,6 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
def _sendNextGcodeLine(self): def _sendNextGcodeLine(self):
if self._gcode_position >= len(self._gcode): if self._gcode_position >= len(self._gcode):
return return
if self._gcode_position == 100:
self._print_start_time_100 = time.time()
line = self._gcode[self._gcode_position] line = self._gcode[self._gcode_position]
if ";" in line: if ";" in line:
@ -585,8 +635,18 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
checksum = functools.reduce(lambda x,y: x^y, map(ord, "N%d%s" % (self._gcode_position, line))) checksum = functools.reduce(lambda x,y: x^y, map(ord, "N%d%s" % (self._gcode_position, line)))
self._sendCommand("N%d%s*%d" % (self._gcode_position, line, checksum)) self._sendCommand("N%d%s*%d" % (self._gcode_position, line, checksum))
progress = (self._gcode_position / len(self._gcode))
elapsed_time = int(time.time() - self._print_start_time)
self.setTimeElapsed(elapsed_time)
estimated_time = self._print_estimated_time
if progress > .1:
estimated_time = self._print_estimated_time * (1-progress) + elapsed_time
self.setTimeTotal(estimated_time)
self._gcode_position += 1 self._gcode_position += 1
self.setProgress((self._gcode_position / len(self._gcode)) * 100) self.setProgress(progress * 100)
self.progressChanged.emit() self.progressChanged.emit()
## Set the state of the print. ## Set the state of the print.
@ -601,6 +661,13 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
elif job_state == "abort": elif job_state == "abort":
self.cancelPrint() self.cancelPrint()
def _onJobStateChanged(self):
# clear the job name & times when printing is done or aborted
if self._job_state == "ready":
self.setJobName("")
self.setTimeElapsed(0)
self.setTimeTotal(0)
## Set the progress of the print. ## Set the progress of the print.
# It will be normalized (based on max_progress) to range 0 - 100 # It will be normalized (based on max_progress) to range 0 - 100
def setProgress(self, progress, max_progress = 100): def setProgress(self, progress, max_progress = 100):

View File

@ -350,21 +350,20 @@ Rectangle
var total_seconds = parseInt(base.printDuration.getDisplayString(UM.DurationFormat.Seconds)) var total_seconds = parseInt(base.printDuration.getDisplayString(UM.DurationFormat.Seconds))
// A message is created and displayed when the user hover the time label // A message is created and displayed when the user hover the time label
var content = catalog.i18nc("@tooltip", "<b>Time specification</b><br/><table>"); var tooltip_html = "<b>%1</b><br/><table width=\"100%\">".arg(catalog.i18nc("@tooltip", "Time specification"));
for(var feature in print_time) for(var feature in print_time)
{ {
if(!print_time[feature].isTotalDurationZero) if(!print_time[feature].isTotalDurationZero)
{ {
content += "<tr><td colspan='2'>" + feature + "</td></tr>" + tooltip_html += "<tr><td>" + feature + ":</td>" +
"<tr>" + "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1</td>".arg(print_time[feature].getDisplayString(UM.DurationFormat.ISO8601).slice(0,-3)) +
"<td width='60%'>" + print_time[feature].getDisplayString(UM.DurationFormat.Short) + "</td>" + "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1%</td>".arg(Math.round(100 * parseInt(print_time[feature].getDisplayString(UM.DurationFormat.Seconds)) / total_seconds)) +
"<td width='40%'>&nbsp;&nbsp;" + Math.round(100 * parseInt(print_time[feature].getDisplayString(UM.DurationFormat.Seconds)) / total_seconds) + "%" +
"</td></tr>"; "</td></tr>";
} }
} }
content += "</table>"; tooltip_html += "</table>";
base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), content); base.showTooltip(parent, Qt.point(-UM.Theme.getSize("sidebar_margin").width, 0), tooltip_html);
} }
} }
onExited: onExited:
@ -376,9 +375,26 @@ Rectangle
Label Label
{ {
function formatRow(items)
{
var row_html = "<tr>";
for(var item = 0; item < items.length; item++)
{
if (item == 0)
{
row_html += "<td valign=\"bottom\">%1</td>".arg(items[item]);
}
else
{
row_html += "<td align=\"right\" valign=\"bottom\">&nbsp;&nbsp;%1</td>".arg(items[item]);
}
}
row_html += "</tr>";
return row_html;
}
function getSpecsData(){ function getSpecsData()
{
var lengths = []; var lengths = [];
var total_length = 0; var total_length = 0;
var weights = []; var weights = [];
@ -387,7 +403,8 @@ Rectangle
var total_cost = 0; var total_cost = 0;
var some_costs_known = false; var some_costs_known = false;
var names = []; var names = [];
if(base.printMaterialLengths) { if(base.printMaterialLengths)
{
for(var index = 0; index < base.printMaterialLengths.length; index++) for(var index = 0; index < base.printMaterialLengths.length; index++)
{ {
if(base.printMaterialLengths[index] > 0) if(base.printMaterialLengths[index] > 0)
@ -415,34 +432,28 @@ Rectangle
costs = ["0.00"]; costs = ["0.00"];
} }
var tooltip_html = "<b>%1</b><br/><table>".arg(catalog.i18nc("@label", "Cost specification")); var tooltip_html = "<b>%1</b><br/><table width=\"100%\">".arg(catalog.i18nc("@label", "Cost specification"));
for(var index = 0; index < lengths.length; index++) for(var index = 0; index < lengths.length; index++)
{ {
var item_strings = [ tooltip_html += formatRow([
"%1:".arg(names[index]), "%1:".arg(names[index]),
catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]), catalog.i18nc("@label m for meter", "%1m").arg(lengths[index]),
catalog.i18nc("@label g for grams", "%1g").arg(weights[index]), catalog.i18nc("@label g for grams", "%1g").arg(weights[index]),
"%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]), "%1&nbsp;%2".arg(UM.Preferences.getValue("cura/currency")).arg(costs[index]),
]; ]);
tooltip_html += "<tr>";
for(var item = 0; item < item_strings.length; item++) {
tooltip_html += "<td>%1&nbsp;&nbsp;</td>".arg(item_strings[item]);
}
} }
var item_strings = [ if(lengths.length > 1)
catalog.i18nc("@label", "Total:"), {
catalog.i18nc("@label m for meter", "%1m").arg(total_length.toFixed(2)), tooltip_html += formatRow([
catalog.i18nc("@label g for grams", "%1g").arg(Math.round(total_weight)), catalog.i18nc("@label", "Total:"),
"%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(total_cost.toFixed(2)), catalog.i18nc("@label m for meter", "%1m").arg(total_length.toFixed(2)),
]; catalog.i18nc("@label g for grams", "%1g").arg(Math.round(total_weight)),
tooltip_html += "<tr>"; "%1 %2".arg(UM.Preferences.getValue("cura/currency")).arg(total_cost.toFixed(2)),
for(var item = 0; item < item_strings.length; item++) { ]);
tooltip_html += "<td>%1&nbsp;&nbsp;</td>".arg(item_strings[item]);
} }
tooltip_html += "</tr></table>"; tooltip_html += "</table>";
tooltipText = tooltip_html; tooltipText = tooltip_html;
return tooltipText return tooltipText
} }