Jump to content

Issue retrieving a value in the extruder stack


V3DPrinting

Recommended Posts

Posted · Issue retrieving a value in the extruder stack

Dear community

 

I'm working on building a custom printer definition in Cura and I would like to comment my gcode header with the material brand used per extruder.

 

I use the ExtruderValue function which returns the value of a specific extruder for a specific key in my printer definition

 

                "used_material_brand":
                {
                    "comments": "V3DP setting",
                    "default_value": "",
                    "description": "Comment with the brand used.",
                    "enabled": false,
                    "label": "Used material brands",
                    "settable_per_extruder": true,
                    "type": "str",
                    "value": "str(extruderValue(0, 'material_brand'))"
                },
 

The issue is the function is returning 'None' though the material is defined for that extruder and the brand too.

 

The key 'material_brand' should exists as the replacement pattern {material_brand} is defined.

 

Any clue ?

 

I know the replacement pattern could be used directly in the gcode header, but I would like to use a function with a conditional value, my printer can have multiple extruders configurations, like an IDEX printer.

 

Thanks in advance for your valuable help

 

  • Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack

    You can't use functions when writing these things, just statements. I don't have the joy of having a multi-extruder printer so I don't know if you're accessing the value the correct way, but IIRC not every variable in the application stack has the same name as its replacement pattern.

     

    If it helps, with 5.6 (I think) or above you can use Python statements in your startup gcode, which should include using a conditional. It'd also be entirely possible to do it with a post-processing script (but that's getting into the "more hassle than it's worth, unless you're as crazy as I am" department).

  • Link to post
    Share on other sites

    Posted (edited) · Issue retrieving a value in the extruder stack

    @Slashee_the_Cow Thanks for the feedback.

    9 hours ago, Slashee_the_Cow said:

    You can't use functions when writing these things, just statements. I don't have the joy of having a multi-extruder printer so I don't know if you're accessing the value the correct way, but IIRC not every variable in the application stack has the same name as its replacement pattern.

     

    I am 100% sure of the statement, addressing the correct extruder, the only thing that is questionable is the key used. It might not be the right one. That's what I'm looking for

     

    For example str(extruderValue(0, 'material_type')).upper() returns properly the material type value, for example PLA.

     

    But with material_brand, it  returns 'None', though the replacement pattern returns the right value.

     

    9 hours ago, Slashee_the_Cow said:

    If it helps, with 5.6 (I think) or above you can use Python statements in your startup gcode, which should include using a conditional. It'd also be entirely possible to do it with a post-processing script (but that's getting into the "more hassle than it's worth, unless you're as crazy as I am" department).

     

    I know we already had that exchange together with @ahoeben a couple on month ago. This works fine.

    I agree the post processing script is far too complex for what it solves in the particular case.

    Edited by V3DPrinting
  • Link to post
    Share on other sites

    Posted (edited) · Issue retrieving a value in the extruder stack

    Digging into Cura's code, in ExtrudersModel.py:

    global_container_stack = Application.getInstance().getGlobalContainerStack()
    if global_container_stack:
    
    # get machine extruder count for verification
    machine_extruder_count = global_container_stack.getProperty("machine_extruder_count", "value")
    
    for extruder in Application.getInstance().getExtruderManager().getActiveExtruderStacks():
    position = extruder.getMetaDataEntry("position", default = "0")
    try:
        position = int(position)
    except ValueError:
        # Not a proper int.
        position = -1
    if position >= machine_extruder_count:
        continue
    
    default_color = self.defaultColors[position] if 0 <= position < len(self.defaultColors) else self.defaultColors[0]
    color = extruder.material.getMetaDataEntry("color_code", default = default_color) if extruder.material else default_color
    material_brand = extruder.material.getMetaDataEntry("brand", default = "generic")
    color_name = extruder.material.getMetaDataEntry("color_name")
    # construct an item with only the relevant information
    item = {
        "id": extruder.getId(),
        "name": extruder.getName(),
        "enabled": extruder.isEnabled,
        "color": color,
        "index": position,
        "definition": extruder.getBottom().getId(),
        "material": extruder.material.getName() if extruder.material else "",
        "variant": extruder.variant.getName() if extruder.variant else "",  # e.g. print core
        "stack": extruder,
        "material_brand": material_brand,
        "color_name": color_name,
        "material_type": extruder.material.getMetaDataEntry("material") if extruder.material else "",
        "material_name": extruder.material.getMetaDataEntry("name") if extruder.material else "",
    }
    items.append(item)
    extruders_changed = True

    That does seem to imply that material_brand inside the (item) should work. But in the code above you can see that it's based on the metadata entry "brand". That could be worth a try. Although it's inside the extruder.material not just extruder so maybe not. Also not all the replacement fields are covered, so again maybe not. But worth a try?

    Edited by Slashee_the_Cow
  • Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack

    Okay searching through the code some more here's the _buildReplacementTokens function, which seems more relevant:

    def _buildReplacementTokens(self, stack: ContainerStack) -> Dict[str, Any]:
        """Creates a dictionary of tokens to replace in g-code pieces.
    
        This indicates what should be replaced in the start and end g-codes.
        :param stack: The stack to get the settings from to replace the tokens with.
        :return: A dictionary of replacement tokens to the values they should be replaced with.
        """
    
        result = {}
        for key in stack.getAllKeys():
            result[key] = stack.getProperty(key, "value")
            Job.yieldThread()
    
        # Material identification in addition to non-human-readable GUID
        result["material_id"] = stack.material.getMetaDataEntry("base_file", "")
        result["material_type"] = stack.material.getMetaDataEntry("material", "")
        result["material_name"] = stack.material.getMetaDataEntry("name", "")
        result["material_brand"] = stack.material.getMetaDataEntry("brand", "")
    
        result["quality_name"] = stack.quality.getMetaDataEntry("name", "")
        result["quality_changes_name"] = stack.qualityChanges.getMetaDataEntry("name")
    
        # Renamed settings.
        result["print_bed_temperature"] = result["material_bed_temperature"]
        result["print_temperature"] = result["material_print_temperature"]
        result["travel_speed"] = result["speed_travel"]
    
        #Some extra settings.
        result["time"] = time.strftime("%H:%M:%S")
        result["date"] = time.strftime("%d-%m-%Y")
        result["day"] = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][int(time.strftime("%w"))]
        result["initial_extruder_nr"] = CuraApplication.getInstance().getExtruderManager().getInitialExtruderNr()
    
        return result

    That does explicitly set material_brand as a replacement token but note that the docstring at the start says it's to "replace in g-code pieces" so might not apply to a definition file.

  • Link to post
    Share on other sites

    Posted (edited) · Issue retrieving a value in the extruder stack

    Okay so I'm not sure if there's much further I can dig but material_type is mentioned a lot more times in the source code (just looking at the .py files) than material_brand.

     

    Here's a search for material_brand:

    Search "material_brand" (6 hits in 2 files of 966 searched)
      C:\Program Files\UltiMaker Cura 5.6.0\cura\Machines\Models\ExtrudersModel.py (5 hits)
    	Line 81:         self.addRoleName(self.MaterialBrandRole, "material_brand")
    	Line 189:             material_brand = extruder.material.getMetaDataEntry("brand", default = "generic")
    	Line 202:                 "material_brand": material_brand,
    	Line 202:                 "material_brand": material_brand,
    	Line 227:                     "material_brand": "",
      C:\Program Files\UltiMaker Cura 5.6.0\share\cura\plugins\CuraEngineBackend\StartSliceJob.py (1 hit)
    	Line 422:         result["material_brand"] = stack.material.getMetaDataEntry("brand", "")

     

    Here's a search for material_type:

    Search "material_type" (33 hits in 5 files of 966 searched)
      C:\Program Files\UltiMaker Cura 5.6.0\cura\Machines\MaterialNode.py (10 hits)
    	Line 33:         self.material_type = my_metadata["material"]
    	Line 86:                 my_material_type = self.material_type
    	Line 86:                 my_material_type = self.material_type
    	Line 95:                 all_material_base_files_right_brand = {material_metadata["base_file"] for material_metadata in container_registry.findInstanceContainersMetadata(type = "material", material = my_material_type, brand = self.brand)}
    	Line 106:                                                                                                  material=my_material_type)}
    	Line 164:         old_material_type = self.material_type
    	Line 164:         old_material_type = self.material_type
    	Line 165:         self.material_type = new_metadata["material"]
    	Line 168:         if self.base_file != old_base_file or self.material_type != old_material_type or self.guid != old_guid:  # List of quality profiles could've changed.
    	Line 168:         if self.base_file != old_base_file or self.material_type != old_material_type or self.guid != old_guid:  # List of quality profiles could've changed.
      C:\Program Files\UltiMaker Cura 5.6.0\cura\Machines\Models\ExtrudersModel.py (3 hits)
    	Line 83:         self.addRoleName(self.MaterialTypeRole, "material_type")
    	Line 204:                 "material_type": extruder.material.getMetaDataEntry("material") if extruder.material else "",
    	Line 229:                     "material_type": "",
      C:\Program Files\UltiMaker Cura 5.6.0\cura\Machines\Models\MaterialBrandsModel.py (17 hits)
    	Line 29:         self.addRoleName(Qt.ItemDataRole.UserRole + 2, "material_types")
    	Line 59:             material_type = container_node.getMetaDataEntry("material", "")
    	Line 60:             if material_type not in brand_group_dict[brand]:
    	Line 61:                 brand_group_dict[brand][material_type] = []
    	Line 66:                 brand_group_dict[brand][material_type].append(item)
    	Line 82:             material_type_item_list = []
    	Line 85:                 "material_types": MaterialTypesModel()
    	Line 88:             for material_type, material_list in material_dict.items():
    	Line 89:                 material_type_item = {
    	Line 90:                     "name": material_type,
    	Line 97:                 material_type_item["colors"].setItems(material_list)
    	Line 99:                 material_type_item_list.append(material_type_item)
    	Line 99:                 material_type_item_list.append(material_type_item)
    	Line 102:             material_type_item_list = sorted(material_type_item_list, key = lambda x: x["name"].upper())
    	Line 102:             material_type_item_list = sorted(material_type_item_list, key = lambda x: x["name"].upper())
    	Line 103:             brand_item["material_types"].setItems(material_type_item_list)
    	Line 103:             brand_item["material_types"].setItems(material_type_item_list)
      C:\Program Files\UltiMaker Cura 5.6.0\share\cura\plugins\CuraEngineBackend\StartSliceJob.py (2 hits)
    	Line 420:         result["material_type"] = stack.material.getMetaDataEntry("material", "")
    	Line 464:             # replacement values for the setting-keys. However, the values for `material_id`, `material_type`,
      C:\Program Files\UltiMaker Cura 5.6.0\share\cura\plugins\SimulationView\SimulationView.py (1 hit)
    	Line 57:     LAYER_VIEW_TYPE_MATERIAL_TYPE = 0

     

    Important Bit:

    Based on everything I've seen, my guess, if it's even possible to do it, which I'm not sure it is, is that you'd have to find a list of materials inside an extruder's stack, something like this, except, you know, finding the right name:

    str(extruderValue(0, materialValue(0, 'material_brand')))

     

    Not sure if there's much more digging can be done by someone as feeble as me.

    Edited by Slashee_the_Cow
    added header for important bit
  • Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack

    All settings have a replacement token, but not all replacement tokens represent a setting.

     

    `material_brand` is metadata of the used material in an extruder, not a setting of that extruder. So you cannot access `material_brand` with the extruderValue function.

    • Like 1
    Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack

    @Slashee_the_Cow Thanks for the search.

     

    1 hour ago, ahoeben said:

    All settings have a replacement token, but not all replacement tokens represent a setting.

     

    `material_brand` is metadata of the used material in an extruder, not a setting of that extruder. So you cannot access `material_brand` with the extruderValue function.

     

    @ahoeben Thanks for the clarification. So I need to evaluate the metadata

     

    material_brand = extruder.material.getMetaDataEntry("brand", default = "generic")
  • Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack
    4 hours ago, V3DPrinting said:

    So I need to evaluate the metadata

    Yes, but I don't think there's a way to do this from inside a printer definition.

  • Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack
    15 hours ago, ahoeben said:

    Yes, but I don't think there's a way to do this from inside a printer definition.

     

    @ahoeben Thanks for the piece of information.

     

    I think I need to create a function and include it into cura app and register it in CuraApplication.py, initializeSettingFunctions.

     

    I am not sure I will do it as it implies to tweak the app at each release.

     

    The replacement pattern in the start gcode is easier as it is not release dependent.

    But that may require a specific machine instance per extruders configuration. Which is against my initial goal to have only one machine instance whatever the extruders configuration is.

    Except if conditional statements are properly supported in the start gcode, which is not the case to my knowledge.

     

  • Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack

    Perhaps you could explain what you want to achieve in the first place. Why do you want to have a slice setting to reflect the brand of material selected?

     

    This can probably be handled with a plugin. Patching Cura is never the answer.

    • Like 1
    Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack
    3 hours ago, ahoeben said:

    Perhaps you could explain what you want to achieve in the first place. Why do you want to have a slice setting to reflect the brand of material selected?

     

    The idea is to be able to reprint without having to load the project. Opening the gcode would provide sufficient information to setup the printer and reprint.

     

    The reason why is that loading an old project file into Cura might alter the current configuration (profiles and materials) if you're not super cautious.

  • Link to post
    Share on other sites

    Posted (edited) · Issue retrieving a value in the extruder stack
    4 hours ago, V3DPrinting said:

    The replacement pattern in the start gcode is easier as it is not release dependent.

    But that may require a specific machine instance per extruders configuration.

    And can you expand on this? Why would that require a specific machine instance per extruder configuration?

     

    Do you want your users to look in the gcode or do you want your printer firmware to look up the material information and present it to the user?

    Edited by ahoeben
  • Link to post
    Share on other sites

    Posted (edited) · Issue retrieving a value in the extruder stack
    1 hour ago, ahoeben said:

    And can you expand on this? Why would that require a specific machine instance per extruder configuration?

     

    Because it's an IDEX printer, so it has 5 different modes therefore 5 different material configuration

     

     

    1 hour ago, ahoeben said:

    Do you want your users to look in the gcode or do you want your printer firmware to look up the material information and present it to the user?

     

    I just want my users to look at the gcode and retrieve the material information.

    I already have the material type, nozzle size and IDEX mode in my gcode header.

    Only the material brand is missing to be able to set up with no doubts the printer.

    Edited by V3DPrinting
  • Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack
    55 minutes ago, V3DPrinting said:

    Because it's an IDEX printer, so it has 5 different modes therefore 5 different material configuration

    I am sorry to be thick, but I don't understand what IDEX printing has to do with the brand of the material.

     

    What is the (potential) problem using the {material_brand} replacement pattern with IDEX printers?

  • Link to post
    Share on other sites

    Posted (edited) · Issue retrieving a value in the extruder stack
    On 2/17/2024 at 6:45 PM, ahoeben said:

    I am sorry to be thick, but I don't understand what IDEX printing has to do with the brand of the material.

     

    What is the (potential) problem using the {material_brand} replacement pattern with IDEX printers?

     

    To make it short :

    Replacement pattern cannot been made conditional in the start gcode.

     

    IDEX printers have 5 different modes : dual extrusion, single left extruder, single right extruder, duplication and miror.

     

    If you want to have the material configuration, given the start gcode is not conditional, you need to have 5 different start gcode based on the IDEX mode used.

    So 5 different printers defined in your Cura instance: IDEX dual, IDEX single left, IDEX single right, IDEX Duplication and IDEX miror.

     

    It's what I've got at the moment in order to have the configuration in the start goode.

    Additionally, when you switch from one mode to another, you need to change printer, and re parameter your whole project.

     

    That's why I have created functions with conditional statements so I can have only one start gcode (and only one printer defined in Cura). Therefore I don't need to rebuild an whole project when switching mode.

     

    The only issue I still have is for the material brand.

     

    I hope it helps clarify my issue and goal.

    Edited by V3DPrinting
  • Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack
    4 hours ago, V3DPrinting said:

    Replacement pattern cannot been made conditional in the start gcode.

    What happens when you try? I've been able to chain ternaries in startup gcode but that's been using number comparisons, not string comparisons. And have you tried just putting

    ; {material_brand}

    in the startup gcode just to see what output is to make sure you don't need to casefold() either it or your values?

    • Like 1
    Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack
    17 hours ago, Slashee_the_Cow said:

     

    ; {material_brand}

    in the startup gcode just to see what output is to make sure you don't need to casefold() either it or your values?

    the replacement pattern provides the exact brand name as defined in the material definition.

     

    Regarding the conditional replacement pattern in the code, I'll have another look to be sure, but when I've tried it was not successful.

    I'll keep you posted on that new try

  • Link to post
    Share on other sites

    Posted · Issue retrieving a value in the extruder stack

    @Slashee_the_Cow Sorry for the very late reply. I was very busy these weeks.

     

    I finally sorted out my issue with the material brand used, creating ternaries in my startup gcode.

    It was a syntax issue on my first attempts, a semi colon is necessary to separate the conditional statement from the reste of the code.

     

    Here's the beginning of my startup gcode, defined in the printer definition

     

    "value": "';Machine Model: {machine_name}\\n;Materials used: {used_material}\\n;Materials brand: '+ (\"T0 {material_brand,0}\" if print_mode == \"singleT0\" else (\"T1 {material_brand,1}\" if print_mode == \"singleT1\"  else (\"T0 {material_brand,0} T1 {material_brand,1}\"  if print_mode == \"dual\" else \"T0 {material_brand,0} T1 {material_brand,0}\"))) + '\\n;Extruders used: {used_nozzle_size} \\n;Print mode: {print_mode} ......

     

    I use some custom functions, defined in the printer definition in that startup gcode, but the material brand used ternary relies only on replacement patterns.

     

    Thanks again for your valuable help. !

     

     

  • Link to post
    Share on other sites

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now
    • Our picks

      • UltiMaker Cura 5.7 stable released
        Cura 5.7 is here and it brings a handy new workflow improvement when using Thingiverse and Cura together, as well as additional capabilities for Method series printers, and a powerful way of sharing print settings using new printer-agnostic project files! Read on to find out about all of these improvements and more. 
         
          • Like
        • 20 replies
      • S-Line Firmware 8.3.0 was released Nov. 20th on the "Latest" firmware branch.
        (Sorry, was out of office when this released)

        This update is for...
        All UltiMaker S series  
        New features
         
        Temperature status. During print preparation, the temperatures of the print cores and build plate will be shown on the display. This gives a better indication of the progress and remaining wait time. Save log files in paused state. It is now possible to save the printer's log files to USB if the currently active print job is paused. Previously, the Dump logs to USB option was only enabled if the printer was in idle state. Confirm print removal via Digital Factory. If the printer is connected to the Digital Factory, it is now possible to confirm the removal of a previous print job via the Digital Factory interface. This is useful in situations where the build plate is clear, but the operator forgot to select Confirm removal on the printer’s display. Visit this page for more information about this feature.
          • Like
        • 0 replies
    ×
    ×
    • Create New...