更新打印时间计算方式,优化打印页面布局
This commit is contained in:
parent
99833457be
commit
d258964289
@ -16,29 +16,39 @@ class Panel(ScreenPanel):
|
||||
def __init__(self, screen, title):
|
||||
title = title or _("Job Status")
|
||||
super().__init__(screen, title)
|
||||
self.thumb_dialog = None
|
||||
self.grid = Gtk.Grid(column_homogeneous=True)
|
||||
self.pos_z = 0.0
|
||||
self.extrusion = 100
|
||||
self.speed_factor = 1.0
|
||||
self.speed = 100
|
||||
self.req_speed = 0
|
||||
self.f_layer_h = self.layer_h = 1
|
||||
self.oheight = 0.0
|
||||
self.current_extruder = None
|
||||
self.fila_section = pi * ((1.75 / 2) ** 2)
|
||||
self.filename_label = self.filename = self.prev_pos = self.prev_gpos = None
|
||||
self.filename_label = None
|
||||
self.filename = None
|
||||
self.prev_pos = None
|
||||
self.prev_gpos = None
|
||||
self.can_close = False
|
||||
self.flow_timeout = self.animation_timeout = None
|
||||
self.flow_timeout = None
|
||||
self.animation_timeout = None
|
||||
self.file_metadata = self.fans = {}
|
||||
self.state = "standby"
|
||||
self.timeleft_type = "auto"
|
||||
self.progress = self.zoffset = self.flowrate = self.vel = 0.0
|
||||
self.progress = 0.0
|
||||
self.zoffset = 0.0
|
||||
self.flowrate = 0.0
|
||||
self.vel = 0.0
|
||||
self.flowstore = []
|
||||
self.mm = _("mm")
|
||||
self.mms = _("mm/s")
|
||||
self.mms2 = _("mm/s²")
|
||||
self.mms3 = _("mm³/s")
|
||||
self.status_grid = self.move_grid = self.time_grid = self.extrusion_grid = None
|
||||
self.status_grid = None
|
||||
self.move_grid = None
|
||||
self.time_grid = None
|
||||
self.extrusion_grid = None
|
||||
|
||||
data = ['pos_x', 'pos_y', 'pos_z', 'time_left', 'duration', 'slicer_time', 'file_time',
|
||||
'filament_time', 'est_time', 'speed_factor', 'req_speed', 'max_accel', 'extrude_factor', 'zoffset',
|
||||
@ -82,14 +92,14 @@ class Panel(ScreenPanel):
|
||||
|
||||
self.labels['file'] = Gtk.Label(label="Filename", hexpand=True)
|
||||
self.labels['file'].get_style_context().add_class("printing-filename")
|
||||
self.labels['lcdmessage'] = Gtk.Label()
|
||||
self.labels['lcdmessage'] = Gtk.Label(no_show_all=True)
|
||||
self.labels['lcdmessage'].get_style_context().add_class("printing-status")
|
||||
|
||||
for label in self.labels:
|
||||
self.labels[label].set_halign(Gtk.Align.START)
|
||||
self.labels[label].set_ellipsize(Pango.EllipsizeMode.END)
|
||||
|
||||
fi_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
|
||||
fi_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10, valign=Gtk.Align.CENTER)
|
||||
fi_box.add(self.labels['file'])
|
||||
fi_box.add(self.labels['lcdmessage'])
|
||||
self.grid.attach(fi_box, 1, 0, 3, 1)
|
||||
@ -332,11 +342,16 @@ class Panel(ScreenPanel):
|
||||
def activate(self):
|
||||
if self.flow_timeout is None:
|
||||
self.flow_timeout = GLib.timeout_add_seconds(2, self.update_flow)
|
||||
if self.animation_timeout is None:
|
||||
self.animation_timeout = GLib.timeout_add(500, self.animate_label)
|
||||
|
||||
def deactivate(self):
|
||||
if self.flow_timeout is not None:
|
||||
GLib.source_remove(self.flow_timeout)
|
||||
self.flow_timeout = None
|
||||
if self.animation_timeout is not None:
|
||||
GLib.source_remove(self.animation_timeout)
|
||||
self.animation_timeout = None
|
||||
|
||||
def create_buttons(self):
|
||||
|
||||
@ -365,22 +380,21 @@ class Panel(ScreenPanel):
|
||||
def save_offset(self, widget, device):
|
||||
sign = "+" if self.zoffset > 0 else "-"
|
||||
label = Gtk.Label(hexpand=True, vexpand=True, wrap=True)
|
||||
saved_z_offset = None
|
||||
msg = f"Apply {sign}{abs(self.zoffset)} offset to {device}?"
|
||||
if device == "probe":
|
||||
probe = self._printer.get_probe()
|
||||
saved_z_offset = probe['z_offset'] if probe else "?"
|
||||
label.set_label(_("Apply %s%.3f offset to Probe?") % (sign, abs(self.zoffset))
|
||||
+ "\n\n"
|
||||
+ _("Saved offset: %s") % saved_z_offset)
|
||||
msg = _("Apply %s%.3f offset to Probe?") % (sign, abs(self.zoffset))
|
||||
if probe := self._printer.get_probe():
|
||||
saved_z_offset = probe['z_offset']
|
||||
elif device == "endstop":
|
||||
saved_z_offset = None
|
||||
msg = _("Apply %s%.3f offset to Endstop?") % (sign, abs(self.zoffset))
|
||||
if 'stepper_z' in self._printer.get_config_section_list():
|
||||
saved_z_offset = self._printer.get_config_section('stepper_z')['position_endstop']
|
||||
elif 'stepper_a' in self._printer.get_config_section_list():
|
||||
saved_z_offset = self._printer.get_config_section('stepper_a')['position_endstop']
|
||||
if saved_z_offset:
|
||||
msg += "\n\n" + _("Saved offset: %s") % saved_z_offset
|
||||
label.set_label(msg)
|
||||
if saved_z_offset:
|
||||
msg += "\n\n" + _("Saved offset: %s") % saved_z_offset
|
||||
label.set_label(msg)
|
||||
buttons = [
|
||||
{"name": _("Apply"), "response": Gtk.ResponseType.APPLY, "style": 'dialog-default'},
|
||||
{"name": _("Cancel"), "response": Gtk.ResponseType.CANCEL, "style": 'dialog-error'}
|
||||
@ -459,6 +473,7 @@ class Panel(ScreenPanel):
|
||||
logging.info("reseting progress")
|
||||
self._printer.data["virtual_sdcard"]["progress"] = 0
|
||||
self.update_progress(0.0)
|
||||
self.set_state("printing")
|
||||
|
||||
def process_update(self, action, data):
|
||||
if action == "notify_gcode_response":
|
||||
@ -470,7 +485,7 @@ class Panel(ScreenPanel):
|
||||
self.set_state("printing")
|
||||
return
|
||||
elif action == "notify_metadata_update" and data['filename'] == self.filename:
|
||||
self.update_file_metadata(response=True)
|
||||
self.get_file_metadata(response=True)
|
||||
elif action != "notify_status_update":
|
||||
return
|
||||
|
||||
@ -486,9 +501,11 @@ class Panel(ScreenPanel):
|
||||
self.buttons['heater'][x].set_label(temp_state)
|
||||
|
||||
if "display_status" in data and "message" in data["display_status"]:
|
||||
self.labels['lcdmessage'].set_label(
|
||||
f"{data['display_status']['message'] if data['display_status']['message'] is not None else ''}"
|
||||
)
|
||||
if data['display_status']['message']:
|
||||
self.labels['lcdmessage'].set_label(f"{data['display_status']['message']}")
|
||||
self.labels['lcdmessage'].show()
|
||||
else:
|
||||
self.labels['lcdmessage'].hide()
|
||||
|
||||
if 'toolhead' in data:
|
||||
if 'extruder' in data['toolhead'] and data['toolhead']['extruder'] != self.current_extruder:
|
||||
@ -505,7 +522,10 @@ class Panel(ScreenPanel):
|
||||
if 'gcode_move' in data:
|
||||
if 'gcode_position' in data['gcode_move']:
|
||||
self.pos_z = round(float(data['gcode_move']['gcode_position'][2]), 2)
|
||||
self.buttons['z'].set_label(f"Z: {self.pos_z:6.2f}{f'/{self.oheight}' if self.oheight > 0 else ''}")
|
||||
self.buttons['z'].set_label(
|
||||
f"Z: {self.pos_z:6.2f}{f'/{self.oheight}' if self.oheight > 0 else ''} "
|
||||
f"{f'{self.mm}' if self._screen.width > 500 else ''}"
|
||||
)
|
||||
if 'extrude_factor' in data['gcode_move']:
|
||||
self.extrusion = round(float(data['gcode_move']['extrude_factor']) * 100)
|
||||
self.labels['extrude_factor'].set_label(f"{self.extrusion:3}%")
|
||||
@ -573,11 +593,8 @@ class Panel(ScreenPanel):
|
||||
f"{data['print_stats']['info']['current_layer']} / "
|
||||
f"{self.labels['total_layers'].get_text()}"
|
||||
)
|
||||
elif "layer_height" in self.file_metadata and "object_height" in self.file_metadata:
|
||||
self.labels['layer'].set_label(
|
||||
f"{1 + round((self.pos_z - self.f_layer_h) / self.layer_h)} / "
|
||||
f"{self.labels['total_layers'].get_text()}"
|
||||
)
|
||||
if 'total_duration' in data["print_stats"]:
|
||||
self.labels["duration"].set_label(self.format_time(data["print_stats"]["total_duration"]))
|
||||
if self.state in ["printing", "paused"]:
|
||||
self.update_time_left()
|
||||
|
||||
@ -591,59 +608,50 @@ class Panel(ScreenPanel):
|
||||
return True
|
||||
|
||||
def update_time_left(self):
|
||||
total_duration = float(self._printer.get_stat('print_stats', 'total_duration'))
|
||||
print_duration = float(self._printer.get_stat('print_stats', 'print_duration'))
|
||||
fila_used = float(self._printer.get_stat('print_stats', 'filament_used'))
|
||||
if "gcode_start_byte" in self.file_metadata:
|
||||
progress = (max(self._printer.get_stat('virtual_sdcard', 'file_position') -
|
||||
self.file_metadata['gcode_start_byte'], 0) / (self.file_metadata['gcode_end_byte'] -
|
||||
self.file_metadata['gcode_start_byte']))
|
||||
else:
|
||||
progress = self._printer.get_stat('virtual_sdcard', 'progress')
|
||||
self.labels["duration"].set_label(self.format_time(total_duration))
|
||||
progress = (
|
||||
max(self._printer.get_stat('virtual_sdcard', 'file_position') - self.file_metadata['gcode_start_byte'], 0)
|
||||
/ (self.file_metadata['gcode_end_byte'] - self.file_metadata['gcode_start_byte'])
|
||||
) if "gcode_start_byte" in self.file_metadata else self._printer.get_stat('virtual_sdcard', 'progress')
|
||||
|
||||
elapsed_label = f"{self.labels['elapsed'].get_text()} {self.labels['duration'].get_text()}"
|
||||
self.buttons['elapsed'].set_label(elapsed_label)
|
||||
find_widget(self.buttons['elapsed'], Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END)
|
||||
estimated = slicer_time = filament_time = file_time = 0
|
||||
timeleft_type = self._config.get_config()['main'].get('print_estimate_method', 'auto')
|
||||
|
||||
if 'estimated_time' in self.file_metadata and self.file_metadata['estimated_time'] > 1:
|
||||
spdcomp = sqrt(self.speed_factor)
|
||||
slicer_time = ((self.file_metadata['estimated_time']) / spdcomp)
|
||||
self.labels["slicer_time"].set_label(self.format_time(slicer_time))
|
||||
if print_duration < 1:
|
||||
last_time = self.file_metadata['last_time'] if "last_time" in self.file_metadata else 0
|
||||
slicer_time = self.file_metadata['estimated_time'] if 'estimated_time' in self.file_metadata else 0
|
||||
print_duration = float(self._printer.get_stat('print_stats', 'print_duration'))
|
||||
if print_duration < 1: # No-extrusion
|
||||
if last_time:
|
||||
print_duration = last_time * progress
|
||||
elif slicer_time:
|
||||
print_duration = slicer_time * progress
|
||||
elif print_duration < 1: # No-extrusion
|
||||
print_duration = total_duration
|
||||
else:
|
||||
print_duration = float(self._printer.get_stat('print_stats', 'total_duration'))
|
||||
|
||||
fila_used = float(self._printer.get_stat('print_stats', 'filament_used'))
|
||||
if 'filament_total' in self.file_metadata and self.file_metadata['filament_total'] >= fila_used > 0:
|
||||
filament_time = (print_duration / (fila_used / self.file_metadata['filament_total']))
|
||||
self.labels["filament_time"].set_label(self.format_time(filament_time))
|
||||
else:
|
||||
filament_time = 0
|
||||
if progress > 0:
|
||||
file_time = (print_duration / progress)
|
||||
self.labels["file_time"].set_label(self.format_time(file_time))
|
||||
else:
|
||||
file_time = 0
|
||||
|
||||
estimated = 0
|
||||
timeleft_type = self._config.get_config()['main'].get('print_estimate_method', 'auto')
|
||||
if timeleft_type == "file":
|
||||
estimated = file_time
|
||||
elif timeleft_type == "filament":
|
||||
estimated = filament_time
|
||||
elif timeleft_type == "slicer":
|
||||
estimated = slicer_time
|
||||
elif estimated < 1: # Auto
|
||||
if print_duration < slicer_time > 1:
|
||||
if progress < 0.15:
|
||||
# At the begining file and filament are innacurate
|
||||
estimated = slicer_time
|
||||
elif filament_time > 1 and file_time > 1:
|
||||
# Weighted arithmetic mean (Slicer is the most accurate)
|
||||
estimated = (slicer_time * 3 + filament_time + file_time) / 5
|
||||
elif file_time > 1:
|
||||
# Weighted arithmetic mean (Slicer is the most accurate)
|
||||
estimated = (slicer_time * 2 + file_time) / 3
|
||||
elif print_duration < filament_time > 1 and file_time > 1:
|
||||
estimated = (filament_time + file_time) / 2
|
||||
elif file_time > 1:
|
||||
estimated = file_time
|
||||
else:
|
||||
estimated = self.estimate_time(
|
||||
progress, print_duration, file_time, filament_time, slicer_time, last_time
|
||||
)
|
||||
if estimated > 1:
|
||||
progress = min(max(print_duration / estimated, 0), 1)
|
||||
self.labels["est_time"].set_label(self.format_time(estimated))
|
||||
@ -653,6 +661,31 @@ class Panel(ScreenPanel):
|
||||
find_widget(self.buttons['left'], Gtk.Label).set_ellipsize(Pango.EllipsizeMode.END)
|
||||
self.update_progress(progress)
|
||||
|
||||
def estimate_time(self, progress, print_duration, file_time, filament_time, slicer_time, last_time):
|
||||
estimate_above = 0.3
|
||||
slicer_time /= sqrt(self.speed_factor)
|
||||
if progress <= estimate_above:
|
||||
return last_time or slicer_time or filament_time or file_time
|
||||
objects = self._printer.get_stat("exclude_object", "objects")
|
||||
excluded_objects = self._printer.get_stat("exclude_object", "excluded_objects")
|
||||
exclude_compensation = 3 * (len(excluded_objects) / len(objects)) if len(objects) > 0 else 0
|
||||
weight_last = 4.0 - exclude_compensation if print_duration < last_time else 0
|
||||
weight_slicer = 1.0 + estimate_above - progress - exclude_compensation if print_duration < slicer_time else 0
|
||||
weight_filament = min(progress - estimate_above, 0.33) if print_duration < filament_time else 0
|
||||
weight_file = progress - estimate_above
|
||||
total_weight = weight_last + weight_slicer + weight_filament + weight_file
|
||||
if total_weight == 0:
|
||||
return 0
|
||||
return (
|
||||
(
|
||||
last_time * weight_last
|
||||
+ slicer_time * weight_slicer
|
||||
+ filament_time * weight_filament
|
||||
+ file_time * weight_file
|
||||
)
|
||||
/ total_weight
|
||||
)
|
||||
|
||||
def update_progress(self, progress: float):
|
||||
self.progress = progress
|
||||
self.labels['progress_text'].set_label(f"{trunc(progress * 100)}%")
|
||||
@ -684,6 +717,8 @@ class Panel(ScreenPanel):
|
||||
if self.state != state:
|
||||
logging.debug(f"Changing job_status state from '{self.state}' to '{state}'")
|
||||
self.state = state
|
||||
if self.thumb_dialog:
|
||||
self.close_dialog(self.thumb_dialog)
|
||||
self.show_buttons_for_state()
|
||||
|
||||
def _add_timeout(self, timeout):
|
||||
@ -746,13 +781,11 @@ class Panel(ScreenPanel):
|
||||
if width <= 1 or height <= 1:
|
||||
width = max_width
|
||||
height = max_height
|
||||
self.labels['thumbnail'].set_hexpand(False)
|
||||
pixbuf = self.get_file_image(self.filename, width, height)
|
||||
if pixbuf is None:
|
||||
logging.debug("no pixbuf")
|
||||
return
|
||||
image = find_widget(self.labels['thumbnail'], Gtk.Image)
|
||||
if image:
|
||||
if image := find_widget(self.labels['thumbnail'], Gtk.Image):
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
|
||||
def show_fullscreen_thumbnail(self, widget):
|
||||
@ -761,17 +794,16 @@ class Panel(ScreenPanel):
|
||||
return
|
||||
image = Gtk.Image.new_from_pixbuf(pixbuf)
|
||||
image.set_vexpand(True)
|
||||
self._gtk.Dialog(self.filename, None, image, self.close_fullscreen_thumbnail)
|
||||
self.thumb_dialog = self._gtk.Dialog(self.filename, None, image, self.close_dialog)
|
||||
|
||||
def close_fullscreen_thumbnail(self, dialog, response_id):
|
||||
def close_dialog(self, dialog=None, response_id=None):
|
||||
self._gtk.remove_dialog(dialog)
|
||||
self.thumb_dialog = None
|
||||
|
||||
def update_filename(self, filename):
|
||||
if not filename:
|
||||
if not filename or filename == self.filename:
|
||||
return
|
||||
if self.animation_timeout is not None:
|
||||
GLib.source_remove(self.animation_timeout)
|
||||
self.animation_timeout = None
|
||||
|
||||
self.filename = filename
|
||||
logging.debug(f"Updating filename to {filename}")
|
||||
self.labels["file"].set_label(os.path.splitext(self.filename)[0])
|
||||
@ -779,18 +811,10 @@ class Panel(ScreenPanel):
|
||||
"complete": self.labels['file'].get_label(),
|
||||
"current": self.labels['file'].get_label(),
|
||||
}
|
||||
ellipsized = self.labels['file'].get_layout().is_ellipsized()
|
||||
if ellipsized:
|
||||
self.animation_timeout = GLib.timeout_add(500, self.animate_label)
|
||||
else:
|
||||
self.animation_timeout = None
|
||||
self.update_file_metadata()
|
||||
self.get_file_metadata()
|
||||
|
||||
def animate_label(self):
|
||||
if not self.filename_label or not self.animation_timeout:
|
||||
return False
|
||||
ellipsized = self.labels['file'].get_layout().is_ellipsized()
|
||||
if ellipsized:
|
||||
if ellipsized := self.labels['file'].get_layout().is_ellipsized():
|
||||
self.filename_label['current'] = self.filename_label['current'][1:]
|
||||
self.labels['file'].set_label(self.filename_label['current'] + " " * 6)
|
||||
else:
|
||||
@ -798,27 +822,29 @@ class Panel(ScreenPanel):
|
||||
self.labels['file'].set_label(self.filename_label['complete'])
|
||||
return True
|
||||
|
||||
def update_file_metadata(self, response=False):
|
||||
def get_file_metadata(self, response=False):
|
||||
if self._files.file_metadata_exists(self.filename):
|
||||
self.file_metadata = self._files.get_file_info(self.filename)
|
||||
logging.info(f"Update Metadata. File: {self.filename} Size: {self.file_metadata['size']}")
|
||||
if "estimated_time" in self.file_metadata and self.timeleft_type == "slicer":
|
||||
self.labels["est_time"].set_label(self.format_time(self.file_metadata['estimated_time']))
|
||||
if "object_height" in self.file_metadata:
|
||||
self.oheight = float(self.file_metadata['object_height'])
|
||||
self.labels['height'].set_label(f"{self.oheight} {self.mm}")
|
||||
if "layer_height" in self.file_metadata:
|
||||
self.layer_h = float(self.file_metadata['layer_height'])
|
||||
if "first_layer_height" in self.file_metadata:
|
||||
self.f_layer_h = float(self.file_metadata['first_layer_height'])
|
||||
else:
|
||||
self.f_layer_h = self.layer_h
|
||||
self.labels['total_layers'].set_label(f"{((self.oheight - self.f_layer_h) / self.layer_h) + 1:.0f}")
|
||||
if "filament_total" in self.file_metadata:
|
||||
self.labels['filament_total'].set_label(f"{float(self.file_metadata['filament_total']) / 1000:.1f} m")
|
||||
self._update_file_metadata()
|
||||
elif not response:
|
||||
logging.debug("Cannot find file metadata. Listening for updated metadata")
|
||||
self._files.request_metadata(self.filename)
|
||||
else:
|
||||
logging.debug("Cannot load file metadata")
|
||||
self.show_file_thumbnail()
|
||||
|
||||
def _update_file_metadata(self):
|
||||
self.file_metadata = self._files.get_file_info(self.filename)
|
||||
logging.info(f"Update Metadata. File: {self.filename} Size: {self.file_metadata['size']}")
|
||||
if "estimated_time" in self.file_metadata:
|
||||
if self.timeleft_type == "slicer":
|
||||
self.labels["est_time"].set_label(self.format_time(self.file_metadata['estimated_time']))
|
||||
self.labels["slicer_time"].set_label(self.format_time(self.file_metadata['estimated_time']))
|
||||
if "object_height" in self.file_metadata:
|
||||
self.oheight = float(self.file_metadata['object_height'])
|
||||
self.labels['height'].set_label(f"{self.oheight:.2f} {self.mm}")
|
||||
if "filament_total" in self.file_metadata:
|
||||
self.labels['filament_total'].set_label(f"{float(self.file_metadata['filament_total']) / 1000:.1f} m")
|
||||
if "job_id" in self.file_metadata and self.file_metadata['job_id']:
|
||||
history = self._screen.apiclient.send_request(f"server/history/job?uid={self.file_metadata['job_id']}")
|
||||
if history and history['job']['status'] == "completed" and history['job']['print_duration']:
|
||||
self.file_metadata["last_time"] = history['job']['print_duration']
|
||||
|
Loading…
x
Reference in New Issue
Block a user