2
$\begingroup$

I've been using Klipper and Cura for a while now (somewhat new to 3D printing), and I notice whenever I import a new G-code file to Klipper, none of the Slicer settings from Cura display in the G-code files in Klipper. However, when I imported a G-code file from my friend (the PETG one) I noticed it showed up right away:

Screenshot of the File List from the web interface for klipper

I looked at the difference in the G-code formats, and I noticed that the file sliced with Prusa had the settings in the bottom of the file in the below (truncated) format:

;TYPE:Custom
; Filament-specific end gcode
; filament used [mm] = 5342.18
; filament used [cm3] = 12.85
; filament used [g] = 16.32
; filament cost = 0.45
; total filament used [g] = 16.32
; total filament cost = 0.45
; estimated printing time (normal mode) = 2h 49m 42s
; estimated printing time (silent mode) = 2h 50m 36s
; prusaslicer_config = begin
; avoid_crossing_perimeters = 0
; avoid_crossing_perimeters_max_detour = 0
; bed_custom_model =
; bed_custom_texture =
; bed_shape = 0x0,250x0,250x210,0x210
; bed_temperature = 90
; before_layer_gcode = ;BEFORE_LAYER_CHANGE\nG92 E0.0\n;[layer_z]\n\n
; between_objects_gcode =
; bottom_fill_pattern = monotonic
; bottom_solid_layers = 5
; bottom_solid_min_thickness = 0.5
; bridge_acceleration = 1000
; bridge_angle = 0
; bridge_fan_speed = 50
; bridge_flow_ratio = 1
; bridge_speed = 25
; cooling = 1
; cooling_tube_length = 5
; elefant_foot_compensation = 0.2
; external_perimeter_extrusion_width = 0.45
; external_perimeter_speed = 25
; external_perimeters_first = 0
; extra_loading_move = -2
; extra_perimeters = 0
; extrusion_multiplier = 1
; extrusion_width = 0.45
; fan_always_on = 1
; fan_below_layer_time = 20
; filament_colour = #FF8000
; filament_cooling_final_speed = 3.4
; filament_cooling_initial_speed = 2.2
; filament_cooling_moves = 4
; filament_cost = 27.82

Whereas the G-code generated by cura has them in the below format:

;End of Gcode
;SETTING_3 {"global_quality": "[general]\\nversion = 4\\nname = Filament_Sample-
;SETTING_3 PET-dev.1\\ndefinition = creality_ender3pro\\n\\n[metadata]\\ntype =
;SETTING_3 quality_changes\\nquality_type = standard\\nsetting_version = 22\\n\\
;SETTING_3 n[values]\\nadhesion_type = skirt\\nklipper_experimental_enable = Tru
;SETTING_3 e\\nklipper_ui_temp_support_enable = True\\nretraction_combing = nosk
;SETTING_3 in\\nsupport_enable = False\\nsupport_type = buildplate\\n\\n", "extr
;SETTING_3 uder_quality": ["[general]\\nversion = 4\\nname = Filament_Sample-PET
;SETTING_3 -dev.1\\ndefinition = creality_ender3pro\\n\\n[metadata]\\ntype = qua
;SETTING_3 lity_changes\\nquality_type = standard\\nintent_category = default\\n
;SETTING_3 position = 0\\nsetting_version = 22\\n\\n[values]\\nbrim_gap = 0.17\\
;SETTING_3 nbrim_line_count = 14\\ninfill_enable_travel_optimization = True\\nin
;SETTING_3 fill_sparse_density = 100\\ninset_direction = outside_in\\nironing_en
;SETTING_3 abled = True\\nironing_flow = 5.0\\nironing_inset = 0.2\\nironing_mon
;SETTING_3 otonic = True\\nironing_pattern = zigzag\\nmaterial_flow = 90.0\\nret
;SETTING_3 raction_amount = 3.0\\nretraction_hop = 1.0\\nretraction_hop_enabled
;SETTING_3 = True\\nretraction_hop_only_when_collides = True\\nroofing_layer_cou
;SETTING_3 nt = 1\\nroofing_line_width = 0.2\\nroofing_material_flow = 75.0\\nro
;SETTING_3 ofing_pattern = lines\\nskin_monotonic = True\\nskin_overlap = 4.0\\n
;SETTING_3 speed_print = 100.0\\nsupport_angle = 65.0\\nsupport_conical_enabled
;SETTING_3 = True\\nsupport_interface_density = 20\\nsupport_skip_some_zags = Tr
;SETTING_3 ue\\ntop_bottom_pattern_0 = lines\\ntop_layers = 1\\nwall_line_count
;SETTING_3 = 4\\nwall_overhang_angle = 55.0\\nwall_overhang_speed_factor = 80.0\
;SETTING_3 \n\\n"]}

Prusa has them in a more sensible format, whereas Cura stores them in INI format, stored as strings in a JSON object, which is then stored as a G-code comment (which seems ridiculously overcomplicated)

I already have a bash/jq function I use to parse those comments from the Cura sliced G-code and display it to me, but I'm trying to find a way to have it done automatically while the G-code file is getting generated. I have looked at some plugins for Cura, but I didn't see one that applied to this.

I know I could possibly modify the metadata.py (Moonraker) to have it parse for the Cura style G-code comments, or even write a Cura plugin, but it occurred to me that I can't be the first one to have this issue. And I didn't find anything for it upon Googling it.

The question: Does anyone have a simple workaround for this that doesn't require writing plugins or modifying existing Moonraker files?

And a bonus question: Why in the world would they store slicer settings nested in three different formats? Why?!

TL;DR: Cura stores the print config in the G-code comments, but Klipper/Moonraker can't parse them due to the format. Is there a simple way around this? (aside from writing a plugin or modifying Moonraker files)

P.S. I do see that some plugins seem related to this but I don't see one that formats and saves the settings to the G-code file. They either just extract them from the G-code, or require you to execute a script every time (or even launch a Node server..)

Update (Answer... Kinda)

So after looking into the Moonraker python, I can see that there actually is a Cura class that extends BaseSlicer class, and it's what handles the comment parsing:

class Cura(BaseSlicer):
    def check_identity(self, data: str) -> Optional[Dict[str, str]]:
        match = re.search(r"Cura_SteamEngine\s(.*)", data)
        if match:
            return {
                'slicer': "Cura",
                'slicer_version': match.group(1)
            }
        return None
        
    # .. Truncated some rows..

    def has_objects(self) -> bool:
        return self._check_has_objects(self.header_data, r"\n;MESH:")

    def parse_filament_weight_total(self) -> Optional[float]:
        return regex_find_float(r";Filament\sweight\s=\s.(%F).", self.header_data)

    def parse_filament_type(self) -> Optional[str]:
        return regex_find_string(r";Filament\stype\s=\s(%S)", self.header_data)

    def parse_filament_name(self) -> Optional[str]:
        return regex_find_string(r";Filament\sname\s=\s(%S)", self.header_data)

    # .. Truncated some rows..

    def parse_nozzle_diameter(self) -> Optional[float]:
        return regex_find_float(r";Nozzle\sdiameter\s=\s(%F)", self.header_data)

And if you look at the regex, it's looking for some config names like Filament weight, Filament name, Filament type, etc. But Cura stores it as just name, weight, and type, but puts it under a [metadata] section.

Also, the Cura-style metadata is all just concatenated into one string, which has a line return injected every 80 characters. This means that depending on the values, some of the names of the metadata items get truncated halfway through, and have another ;SETTING_3 injected as the prefix, which makes it somewhat of a nightmare to simply parse with RegEx.

I was trying to avoid having to modify any Moonraker code, but it looks like I'll just have to alter the Cura class to extract all lines that start with ;SETTING_3 , then concatenate > JSON Parse > INI Parse.

$\endgroup$
4
  • 1
    $\begingroup$ Please don't post text as an image; see Why are images of text, code and mathematical expressions discouraged?. $\endgroup$
    – agarza
    Dec 6, 2023 at 15:01
  • $\begingroup$ @agarza hm, ok. Updated. I thought about that but figured it was ok because I wasn't really posting the text to be parsed/read through. I just wanted to show the side by side differences between the two. And I did have the code in the draft and thought it just made it too cluttered/long. $\endgroup$
    – J H
    Dec 6, 2023 at 16:21
  • $\begingroup$ Does this answer your question? Is there a (common) way to embed used Slicer settings inside the G-code file? $\endgroup$
    – Bob Ortiz
    Dec 6, 2023 at 16:47
  • 2
    $\begingroup$ @BobOrtiz Not really. I actually found that there is a Class that should be able to do this, already in Moonraker. I just need to see why it doesn't work (I updated y original post) $\endgroup$
    – J H
    Dec 6, 2023 at 20:05

1 Answer 1

1
$\begingroup$

Not sure why I wasn't able to find this initially, but here's a list of replacement strings that can be used in the Start/End G-code settings of the machine/printer profile.

In my Machine profile settings, I inserted the below text at the top of the Start G-code section:

; Cura/Material/Profile settings
;Layer Height: {layer_height}
;MINZ: {layer_height_0}
;Print Speed: {speed_print}
;first_layer_bed_temp: {material_print_temperature_layer_0}
;Nozzle diameter = {machine_nozzle_size}
;Filament id = {material_id}
;Filament type = {material_type}
;Filament name = {material_name}
;Filament brand = {material_brand}
;Filament amount = {filament_amount}
;Filament weight = {filament_weight}
;Filament cost = {filament_cost}
;Jobname = {jobname}

; Ender 3 Custom Start G-code
; ... Rest of my start G-code was here

And now, when I generate a new G-code file, it has the below data in the file:

; Cura/Material/Profile settings
;Layer Height: 0.2
;MINZ: 0.2
;Print Speed: 30.0
;first_layer_bed_temp: 260.0
;Nozzle diameter = 0.4
;Filament id = generic_abs_175 #2
;Filament type = ABS
;Filament name = ASA
;Filament brand = iSANGHU
;Filament amount = [1.01]
;Filament weight = [3.013193642578125]
;Filament cost = [0.05423748556640625]
;Jobname = TN1-148_SHAFT_ADAPTOR

; Ender 3 Custom Start G-code

(Note: I had to save an ASA material as ABS because apparently, Cura thinks my printer profile isn't compatible with ASA, so it's saved as ABS. but that value is accurate to what's in the configs)

And it works fine in MoonRaker as well

Screenshot of the left-hand portion of MoonRaker's File List

Screenshot of the right-hand portion of MoonRaker's File List

Source: How to access material type (eg PLA, PETG etc) from Cura post-processing plugin?

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .