UDTs - Bind Parameters to Properties Using Scripting

I’m trying to use an Ignition script to change the binding of a property using scripting.

I’m using this script:

a = system.tag.getConfiguration('[default]FV_102/FullStall/Ack')
x = (a[0]['opcItemPath'])
print('opcItemPath: ', x)
print('Type: ', type(x))

The result is this:

('opcItemPath: ', {bindType=parameter, binding={OPC_Item_Path}.{TagName}})
('Type: ', <type 'com.inductiveautomation.ignition.common.config.BoundValue'>)

My issue is that I do not know how to create / modify the BoundValue datatype. Setting the opcItemPath equal a string of the desired path does not work. I have to manually go back into the UDT and apply the change.

The information that I found on the BoundValue is this: http://files.inductiveautomation.com/sdk/javadoc/ignition80/8.0.0-beta/com/inductiveautomation/ignition/common/config/BoundValue.html

The system.tag.configure document doesn’t have an example on using parameters (it does for setting parameters). https://docs.inductiveautomation.com/display/DOC80/system.tag.configure

Is it possible to bind a parameter to a property via scripting?

There’s not any way to construct bindings in scripts, for any part of Ignition. You would have to instantiate an expression parser with a carefully constructed execution context, and none of the necessary pieces are exposed, not even in the SDK. It is theoretically possible, though. But totally unsupported.

The closest you can get would be to programmatically construct a file in tag export format and use system.tag.importTags() to pull it in.

Is this still the case ? I want to overwride an opcItemPath of a child in a UDT instance that uses parameters bindings.

I know its an old thread, but if you were still wondering, I found that (in 8.3) if you import the BoundValue type you can create a new BoundValue and assign it to a tag's opcItemPath property.

eg. if you want to bind a parameter named opcRootPath:

import com.inductiveautomation.ignition.common.config.BoundValue as BoundValue

rootpath = "[default]tagpath"
tag = system.tag.getConfiguration(path+"/member", False)[0]
bv = BoundValue('parameter', '{opcRootPath}/RestOfThePath')
tag['opcItemPath'] = bv
system.tag.configure(path, conv, 'o')

I just looked at this (and Ignition) for the first time in years. It turns out all that was needed was a .getValue() on the parameter. No need for messing with BoundValue.

Here's a script that dynamically goes through a specified path and automatically adds the nested name to the OPC_Item_Path custom parameter.
Going off the initial example, the OPC_Item_Path variable was FV_102.
Now the OPC_Item_Path for FV_102/FullStall will be FV_102.FullStall

edited to a much more optimized implementation using Gemini

def propagateParamsChildren(startPth):
    """
    Robust hybrid approach:
    1. Finds all top-level UDT instances directly under the starting path.
    2. Sequentially reads child configs inside error boundaries to prevent script crashes.
    3. Extracts raw primitive values to preserve explicit datatypes and prevent JSON parsing type-flips.
    4. Batches writes per folder to maintain great performance.
    """
    startPth = str(startPth).rstrip('/')
    topLevelUdts = []

# --- STEP 1: Find the Top-Level Master UDTs (Subfolder Aware) ---
    try:
        startConfig = system.tag.getConfiguration(startPth, False)
        if startConfig and str(startConfig[0].get('tagType', '')) == 'UdtInstance':
            topLevelUdts.append(startPth)
        else:
            # Grab EVERY UDT instance anywhere down the tree recursively
            results = system.tag.browse(startPth, {"tagType": "UdtInstance", "recursive": True}).getResults()
            allFoundPaths = [str(item.get('fullPath', '')) for item in results if item.get('fullPath')]
            
            # Sort paths shortest to longest so parents are evaluated before their own children
            allFoundPaths.sort(key=lambda x: len(x))
            
            # Filter the list so we only keep UDTs that don't have a parent UDT above them
            for path in allFoundPaths:
                is_child_udt = False
                for existing_master in topLevelUdts:
                    if path.startswith(existing_master + "/"):
                        is_child_udt = True
                        break
                if not is_child_udt:
                    topLevelUdts.append(path)
                    
    except Exception as e:
        print "Error finding top-level UDTs at '%s': %s" % (startPth, str(e))
        return

    if not topLevelUdts:
        print "No UDT instances found to process at: %s" % startPth
        return

    print "Found %d independent UDT trees to process." % len(topLevelUdts)


    # --- STEP 2: Process each UDT tree one by one ---
    for masterPath in topLevelUdts:
        print "Processing UDT Tree: %s" % masterPath
        
        try:
            # Safely fetch the Master UDT configuration
            masterConfig = system.tag.getConfiguration(masterPath, False)
            if not masterConfig:
                continue
            masterParams = masterConfig[0].get('parameters', {})
            if not masterParams:
                continue 

            # Find all nested child UDTs under this master tree
            childResults = system.tag.browse(masterPath, {"tagType": "UdtInstance", "recursive": True}).getResults()
            childPaths = [str(item.get('fullPath')) for item in childResults if item.get('fullPath')]

            if not childPaths:
                print "  No nested children found under this UDT."
                continue

            # Group writes by folder for this specific tree
            configsToWrite = {}

            # Process child configurations safely one-by-one to isolate path parsing errors
            for path in childPaths:
                try:
                    childConfigList = system.tag.getConfiguration(path, False)
                    if not childConfigList:
                        continue
                    config = childConfigList[0]
                except Exception as pathEx:
                    print "  Skipping child tag due to read path format error: %s" % path
                    continue

                node_name = config.get('name', '')
                childParams = config.get('parameters', {})
                modified = False

                for k, v in masterParams.items():
                    if k in childParams:
                        # FIX: Always extract the raw python/java primitive value out of the wrapper object
                        parent_val = v.getValue() if hasattr(v, 'getValue') else v
                        
                        if k == 'OPC_Item_Path':
                            childParams[k] = "%s.%s" % (parent_val, node_name)
                        else:
                            # Pass the clean, raw type (e.g. raw str, int, bool) without the Java object casing
                            childParams[k] = parent_val
                            
                        modified = True

                if modified:
                    write_config = {
                        "name": node_name,
                        "tagType": "UdtInstance",
                        "parameters": childParams
                    }
                    
                    parent_pth = path.rsplit('/', 1)[0]
                    if parent_pth not in configsToWrite:
                        configsToWrite[parent_pth] = []
                    configsToWrite[parent_pth].append(write_config)

            # Bulk write updates back out for this specific UDT tree
            for parent_folder, configs in configsToWrite.items():
                try:
                    system.tag.configure(parent_folder, configs, 'o')
                    print "  Successfully wrote batch of %d updates to %s" % (len(configs), parent_folder)
                except Exception as writeEx:
                    print "  Error writing batch to folder %s: %s" % (parent_folder, str(writeEx))

        except Exception as treeEx:
            print "  Error processing UDT tree '%s': %s" % (masterPath, str(treeEx))

    print "Parameter propagation complete."