<< All versions
Skill v1.0.0
currentAutomated scan100/100datadrivenconstruction/ddc_skills_for_ai_agents_in_construction/excel-to-rvt
──Details
PublishedSeptember 29, 2026 at 06:35 AM
Content Hashsha256:4f941dca0adcbe11...
Git SHA
──Files
Files (1 file, 12.1 KB)
SKILL.md12.1 KBactive
SKILL.md · 418 lines · 12.1 KB
version: "1.0.0" name: "excel-to-rvt" description: "Import Excel data into RVT projects. Update element parameters, create schedules, and sync external data sources." homepage: "https://datadrivenconstruction.io" metadata: {"openclaw": {"emoji": "📄", "os": ["win32"], "homepage": "https://datadrivenconstruction.io", "requires": {"bins": ["python3"]}}}
Excel to RVT Import
Note: RVT is the file format. Examples may reference Autodesk® Revit® APIs. Autodesk and Revit are registered trademarks of Autodesk, Inc.
Business Case
Problem Statement
External data (costs, specifications, classifications) lives in Excel but needs to update Revit:
- Cost estimates need to link to model elements
- Classification codes need assignment
- Custom parameters need population
- Manual entry is slow and error-prone
Solution
Automated import of Excel data into Revit using the DDC ImportExcelToRevit tool and Dynamo workflows.
Business Value
- Automation - Batch update thousands of parameters
- Accuracy - Eliminate manual data entry errors
- Sync - Keep external data in sync with model
- Flexibility - Update any writable parameter
Technical Implementation
Methods
- ImportExcelToRevit CLI - Direct command-line update
- Dynamo Script - Visual programming approach
- Revit API - Full programmatic control
ImportExcelToRevit CLI
bash
ImportExcelToRevit.exe <model.rvt> <data.xlsx> [options]
| Option | Description | |
|---|---|---|
-sheet | Excel sheet name | |
-idcol | Element ID column | |
-mapping | Parameter mapping file |
Python Implementation
python
import subprocessimport pandas as pdfrom pathlib import Pathfrom typing import Dict, Any, List, Optional, Tuplefrom dataclasses import dataclassimport json@dataclassclass ImportResult:"""Result of Excel import to Revit."""elements_processed: intelements_updated: intelements_failed: intparameters_updated: interrors: List[str]class ExcelToRevitImporter:"""Import Excel data into Revit models."""def __init__(self, tool_path: str = "ImportExcelToRevit.exe"):self.tool_path = Path(tool_path)def import_data(self, revit_file: str,excel_file: str,sheet_name: str = "Elements",id_column: str = "ElementId",parameter_mapping: Dict[str, str] = None) -> ImportResult:"""Import Excel data into Revit."""# Build commandcmd = [str(self.tool_path),revit_file,excel_file,"-sheet", sheet_name,"-idcol", id_column]# Add mapping file if providedif parameter_mapping:mapping_file = self._create_mapping_file(parameter_mapping)cmd.extend(["-mapping", mapping_file])# Executeresult = subprocess.run(cmd, capture_output=True, text=True)# Parse result (format depends on tool)return self._parse_result(result)def _create_mapping_file(self, mapping: Dict[str, str]) -> str:"""Create temporary mapping file."""mapping_path = Path("temp_mapping.json")with open(mapping_path, 'w') as f:json.dump(mapping, f)return str(mapping_path)def _parse_result(self, result: subprocess.CompletedProcess) -> ImportResult:"""Parse CLI result."""# This is placeholder - actual parsing depends on tool outputif result.returncode == 0:return ImportResult(elements_processed=0,elements_updated=0,elements_failed=0,parameters_updated=0,errors=[])else:return ImportResult(elements_processed=0,elements_updated=0,elements_failed=0,parameters_updated=0,errors=[result.stderr])class DynamoScriptGenerator:"""Generate Dynamo scripts for Revit data import."""def generate_parameter_update_script(self,mappings: Dict[str, str],excel_path: str,output_path: str) -> str:"""Generate Dynamo Python script for parameter updates."""mappings_json = json.dumps(mappings)script = f'''# Dynamo Python Script - Excel to Revit Parameter Update# Generated by DDCimport clrimport syssys.path.append(r'C:\\Program Files (x86)\\IronPython 2.7\\Lib')clr.AddReference('RevitAPI')clr.AddReference('RevitServices')clr.AddReference('Microsoft.Office.Interop.Excel')from RevitServices.Persistence import DocumentManagerfrom RevitServices.Transactions import TransactionManagerfrom Autodesk.Revit.DB import *import Microsoft.Office.Interop.Excel as Excel# Configurationexcel_path = r'{excel_path}'mappings = {mappings_json}# Open Excelexcel_app = Excel.ApplicationClass()excel_app.Visible = Falseworkbook = excel_app.Workbooks.Open(excel_path)worksheet = workbook.Worksheets[1]# Get Revit documentdoc = DocumentManager.Instance.CurrentDBDocument# Read Excel dataused_range = worksheet.UsedRangerows = used_range.Rows.Countcols = used_range.Columns.Count# Find column indicesheaders = {{}}for col in range(1, cols + 1):header = str(worksheet.Cells[1, col].Value2 or '')headers[header] = col# Process rowsTransactionManager.Instance.EnsureInTransaction(doc)updated_count = 0error_count = 0for row in range(2, rows + 1):try:# Get element IDelement_id_col = headers.get('ElementId', 1)element_id = int(worksheet.Cells[row, element_id_col].Value2 or 0)element = doc.GetElement(ElementId(element_id))if not element:continue# Update mapped parametersfor excel_col, revit_param in mappings.items():if excel_col in headers:col_idx = headers[excel_col]value = worksheet.Cells[row, col_idx].Value2if value is not None:param = element.LookupParameter(revit_param)if param and not param.IsReadOnly:if param.StorageType == StorageType.Double:param.Set(float(value))elif param.StorageType == StorageType.Integer:param.Set(int(value))elif param.StorageType == StorageType.String:param.Set(str(value))updated_count += 1except Exception as e:error_count += 1TransactionManager.Instance.TransactionTaskDone()# Cleanupworkbook.Close(False)excel_app.Quit()OUT = f"Updated: {{updated_count}}, Errors: {{error_count}}"'''with open(output_path, 'w') as f:f.write(script)return output_pathdef generate_schedule_creator(self,schedule_name: str,category: str,fields: List[str],output_path: str) -> str:"""Generate script to create Revit schedule from Excel structure."""fields_json = json.dumps(fields)script = f'''# Dynamo Python Script - Create Schedule# Generated by DDCimport clrclr.AddReference('RevitAPI')clr.AddReference('RevitServices')from RevitServices.Persistence import DocumentManagerfrom RevitServices.Transactions import TransactionManagerfrom Autodesk.Revit.DB import *doc = DocumentManager.Instance.CurrentDBDocumentfields = {fields_json}# Get categorycategory = Category.GetCategory(doc, BuiltInCategory.OST_{category})TransactionManager.Instance.EnsureInTransaction(doc)# Create scheduleschedule = ViewSchedule.CreateSchedule(doc, category.Id)schedule.Name = "{schedule_name}"# Add fieldsdefinition = schedule.Definitionfor field_name in fields:# Find schedulable fieldfor sf in definition.GetSchedulableFields():if sf.GetName(doc) == field_name:definition.AddField(sf)breakTransactionManager.Instance.TransactionTaskDone()OUT = schedule'''with open(output_path, 'w') as f:f.write(script)return output_pathclass ExcelDataValidator:"""Validate Excel data before Revit import."""def __init__(self, revit_elements: pd.DataFrame):"""Initialize with exported Revit elements."""self.revit_data = revit_elementsself.valid_ids = set(revit_elements['ElementId'].astype(str).tolist())def validate_import_data(self, import_df: pd.DataFrame,id_column: str = 'ElementId') -> Dict[str, Any]:"""Validate import data against Revit export."""results = {'valid': True,'total_rows': len(import_df),'matching_ids': 0,'missing_ids': [],'invalid_ids': [],'warnings': []}import_ids = import_df[id_column].astype(str).tolist()for import_id in import_ids:if import_id in self.valid_ids:results['matching_ids'] += 1else:results['invalid_ids'].append(import_id)if results['invalid_ids']:results['valid'] = Falseresults['warnings'].append(f"{len(results['invalid_ids'])} element IDs not found in Revit model")results['match_rate'] = round(results['matching_ids'] / results['total_rows'] * 100, 1) if results['total_rows'] > 0 else 0return resultsdef check_parameter_types(self, import_df: pd.DataFrame,type_definitions: Dict[str, str]) -> List[str]:"""Check if values match expected parameter types."""errors = []for column, expected_type in type_definitions.items():if column not in import_df.columns:continuefor idx, value in import_df[column].items():if pd.isna(value):continueif expected_type == 'number':try:float(value)except ValueError:errors.append(f"Row {idx}: '{column}' should be number, got '{value}'")elif expected_type == 'integer':try:int(value)except ValueError:errors.append(f"Row {idx}: '{column}' should be integer, got '{value}'")return errors
Quick Start
python
# Generate Dynamo scriptgenerator = DynamoScriptGenerator()mappings = {'OmniClass_Code': 'OmniClass Number','Unit_Cost': 'Cost','Material_Type': 'Material'}generator.generate_parameter_update_script(mappings=mappings,excel_path="enriched_data.xlsx",output_path="update_revit.py")
Validation
python
# Validate before importvalidator = ExcelDataValidator(revit_export_df)validation = validator.validate_import_data(import_df)if validation['valid']:print(f"Ready to import. Match rate: {validation['match_rate']}%")else:print(f"Issues found: {validation['warnings']}")
Complete Workflow
python
# 1. Export from Revit# RvtExporter.exe model.rvt complete# 2. Load and validaterevit_df = pd.read_excel("model.xlsx")validator = ExcelDataValidator(revit_df)# 3. Prepare import dataimport_df = pd.read_excel("enriched_data.xlsx")validation = validator.validate_import_data(import_df)# 4. Generate update scriptif validation['valid']:generator = DynamoScriptGenerator()generator.generate_parameter_update_script(mappings={'Classification': 'OmniClass Number'},excel_path="enriched_data.xlsx",output_path="apply_updates.py")print("Run apply_updates.py in Dynamo to update Revit")
Resources
- GitHub: DDC Update Revit from Excel
- Dynamo: https://dynamobim.org/