Read family parameter and write to shared parameter

fitting has Angle family parameter, also have Angle shared parameter, how to read Angle family parameter value and write to Angle shared parameter via coding (Dynamo/Python)?

in fact, i tried traditional way by modifying fitting family, but loading family back to project will screw up all existing fitting which is not desired, even though i only added shared parameter to family and linked to family parameter.

can’t you just…
add new shared parameter to family
add formula to new parameter =existing parameter
reload to project without overriding parameter values

no dynamo or coding required

?

well, maybe project file is not in good health (that’s why 2 Angle parameters existed), reload won’t work well even without overriding parameter values

There’s a node for that… Parameter.IsShared

Building on @Mike.Buttery’s graph: the split works, but the write step is where nodes get stuck, since SetParameterByName grabs whichever “Angle” it finds first, and that may not be the shared one. A Python node can do the same IsShared split and the write in one pass across every fitting:

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument
name = IN[0] if IN[0] else "Angle"

fittings = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_PipeFitting).WhereElementIsNotElementType().ToElements()

done, skipped = [], []
TransactionManager.Instance.EnsureInTransaction(doc)
for f in fittings:
    params = list(f.GetParameters(name))
    src = next((p for p in params if not p.IsShared and p.HasValue), None)
    dst = next((p for p in params if p.IsShared and not p.IsReadOnly), None)
    if src and dst:
        if src.StorageType == StorageType.Double and dst.StorageType == StorageType.Double:
            dst.Set(src.AsDouble())
        else:
            dst.Set(src.AsValueString())
        done.append(f)
    else:
        skipped.append(f)
TransactionManager.Instance.TransactionTaskDone()

OUT = done, skipped

If the shared Angle is an Angle-type parameter, AsDouble copies over as-is, since both are stored in radians internally. Swap in OST_DuctFitting if these are duct fittings. Anything in the skipped list is either missing the shared parameter (check that it’s bound to the category) or has it as a type parameter. Plug a String node with Angle into IN[0] before running.

It doesn’t get ‘stuck’, you just need to use the right parameter nodes
And if you want to update every item a Categories → All Elements of Category is all you need.

Onto the python, many ways to bake the cake, a few thoughts below

# Safe way to set a parameter in Pythonnet3 (3.11)
def set_param_value(builtin, shared):
    if builtin.StorageType == shared.StorageType and not shared.IsReadOnly:
        match builtin.StorageType:
            case StorageType.Integer:
                return shared.Set(builtin.AsInteger())
            case StorageType.Double:
                return shared.Set(builtin.AsDouble())
            case StorageType.String:
                return shared.Set(builtin.AsString())
            case StorageType.ElementId:
                return shared.Set(builtin.AsElementId())
    return False

# if IN[0] is none, param_name will be "Thickness" in this example
param_name = IN[0] or "Thickness"

# Use a ParameterFilterRuleFactory to only get elements with the shared parameter by name
# My preference is to use Class over category, however some classes like FamilyInstance
# can result in a large collection (so use class and category filters)
bic = BuiltInCategory.OST_Roofs

pfrf = ParameterFilterRuleFactory.CreateSharedParameterApplicableRule(param_name)
epf = ElementParameterFilter(pfrf)

elems = (
    FilteredElementCollector(doc)
    .OfCategory(bic)
    .WherePasses(epf)
    .WhereElementIsNotElementType()
)

# You can sort by True/False (True=1, False=0)
params = elem.GetParameters(param_name)
if len(params) == 2:
    builtin, shared = sorted(params, key=lambda param: param.IsShared)
    param_set.append(set_param_value(builtin, shared))