How to get the System Type instance parameter as string with Python code?

How to get the System Type instance parameter as string with Python code?

I tried this code but no luck yet

import clr

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference("RevitAPI")
import Autodesk
from Autodesk.Revit.DB import *

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

def getSystem(elem):
	try:
		system = elem.MEPSystem.GetTypeId()
		return doc.GetElement(system)
	except:
		try:
			connectors = elem.ConnectorManager.Connectors
		except:
			connectors = elem.MEPModel.ConnectorManager.Connectors
		
		if connectors.Size < 2:
			for conn in connectors:
				connector = conn
				break
			systypeId = connector.MEPSystem.GetTypeId()
			return doc.GetElement(systypeId)
		else:
			systems = []
			ids = set()
			for conn in connectors:
				try:
					if conn.MEPSystem.Id not in ids:
						ids.add(conn.MEPSystem.Id)
						systypeId = conn.MEPSystem.GetTypeId()
						systems.append(doc.GetElement(systypeId))
				except:
					pass
			return systems

def GetName(item):
	unwrapped = UnwrapElement(item)
	if not unwrapped: return None
	elif unwrapped.GetType().ToString() in ("Autodesk.Revit.DB.BuiltInParameter", "Autodesk.Revit.DB.BuiltInParameterGroup", "Autodesk.Revit.DB.DisplayUnitType", "Autodesk.Revit.DB.ParameterType", "Autodesk.Revit.DB.UnitSymbolType", "Autodesk.Revit.DB.UnitType"): return LabelUtils.GetLabelFor(unwrapped)
	elif unwrapped.GetType().ToString() in ("Autodesk.Revit.DB.Parameter", "Autodesk.Revit.DB.FamilyParameter"): return unwrapped.Definition.Name
	elif hasattr(unwrapped, "Name"): return unwrapped.Name
	elif hasattr(item, "Name"): return item.Name
	else: return None

# Process the input elements
elements = IN[0]
listout = []

# Check if the input is a list or a list of sublists
if not all(isinstance(el, list) for el in elements):
	elements = [elements] # Wrap in a list if it's a flat list

# Iterate through each sublist
for sublist in elements:
	sublist_out = []
	for el in sublist:
		el_unwrapped = UnwrapElement(el)
		try:
			system = getSystem(el_unwrapped)
			if isinstance(system, list) and len(system) == 1:
				sublist_out.append(system[0])
			else:
				sublist_out.append(system)
		except:
			sublist_out.append(None)
	listout.append(sublist_out)

# If there is only one sublist, return it flattened
if len(listout) == 1:
	systems_out = listout[0]
else:
	systems_out = listout

# Convert systems to names using the GetName function
if all(isinstance(item, list) for item in systems_out):
	OUT = [[GetName(x) for x in sublist if x] for sublist in systems_out]
else:
	OUT = [GetName(x) for x in systems_out if x]

1 Like

Have you tried using the MepOver Package get paramater value as string?

1 Like

Assuming you mean the name of the system type, you basically have two options:

  1. Get the parameter value directly as a user readable string with param.AsValueString(). This is typically the easiest and the most direct option.
  2. Get the actual System Type ElementId from the parameter and then get the name of that element. This is just extra steps but may fit your code better since you’re not getting the system from the element parameters.

I’ll also add that is should be way easier and more consistent to get the System Type from the element parameters, even if you have to parse multiple types. Otherwise the goal should be to get the System Type element and then get the name. Again, that makes your method consistent so you won’t have to deal with multiple conditions for how to get the name from the object. Right now you seem to be overcomplicating it.

1 Like

I mean the builtin parameter System Type that is available on categories of Ducts, Pipes and accessories, fittings. I tried many options and I only get a list of nulls results, also I can get the system type like an element in separate script and then other node for getting the elements name and it appears but if I combined both scripts the result is only null. please can you share this code example?

It’s the same thing, but if you get it as the parameter element you can return the name directly.

Can you show a simplified version of this? Like I show in my previous reply, once you have the system type element it’s just a matter of getting the type name.

You could also work top down from a BuiltInParameter like this

pipes = (
    FilteredElementCollector(doc)
    .OfClass(Pipe)
    .WhereElementIsNotElementType()
    .ToElements()
)

# ForgeTypeId from BuiltInParameter
sc = ParameterUtils.GetParameterTypeId(BuiltInParameter.RBS_SYSTEM_CLASSIFICATION_PARAM)

# Helper function
pv = lambda p, v: p.GetParameter(v).AsValueString()

OUT = [pv(p, sc) for p in pipes]

the thinkg is the builting parameter name is different for each element type of MEP for the same Revit parameter name or equivalent? I am trying the package node of MEPOVER it worked in revit 2020 but not in Revit 2022 it seems the method to call changed in API.

I resolved it like this, considering input is a list of sublists of elements:

import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
version = int(app.VersionNumber)

elements_sublists = [UnwrapElement(sublist) for sublist in IN[0]]

# Hardcoding the names list directly in the script
names = ["System Type", "Service Type", "Fabrication Service"]

formatOptions = FormatOptions()
formatOptions.UseDefault = False
if version < 2021:
    formatOptions.UnitSymbol = UnitSymbolType.UST_NONE

def getParameterValue(e, names):
    for name in names:
        params = e.GetParameters(name)
        if params:
            p = params[0]  # Assume one parameter with the given name
            if p:
                if p.StorageType == StorageType.String:
                    return p.AsString()
                elif p.StorageType == StorageType.ElementId:
                    return p.AsValueString()
                elif p.StorageType == StorageType.Integer:
                    return p.AsValueString()
                else:
                    if version < 2021:
                        formatOptions.DisplayUnits = p.DisplayUnitType
                    else:
                        formatOptions.SetUnitTypeId(p.GetUnitTypeId())
                    return p.AsValueString(formatOptions)
    return None

output = []

for sublist in elements_sublists:
    sublist_output = []
    for e in sublist:
        value = getParameterValue(e, names)
        sublist_output.append(value)
    output.append(sublist_output)
                
OUT = output

Glad you got it sorted out, but, personally, I still think this would be easier just getting the parameter directly. That’s essentially what you’re doing in the getParameterValue function already, you’ve just added a little complexity and redundancy (you don’t need all those checks if you’re getting one specific parameter).

2 Likes