STEP (ISO 10303) CAD models → Asset Administration Shell (AAS) digital twin packages (.aasx).
CAx-IF AS1 (AP214): AASX Package Explorer on the left,
STP2AAS HTML viewer on the right. Converted with --assembly-structure hierarchical --view.
pythonocc-core is not pip-installable, so the runtime is a conda env. Running
setup.bat builds that env inside this folder at .\env (installing
Miniforge via winget first if conda is missing). Code + environment then live
together in one folder; the .bat launchers call .\env\python.exe directly with
PYTHONPATH=src, so nothing is hardcoded and no conda activate is needed.
setup.bat :: one-time; builds .\env from environment.yml
run_gui.bat :: launch the desktop GUI (pick a file, convert, view)
run.bat input.stp -o out\model.aasx :: CLI
view.bat out\model.aasx --open :: build + open the 3D viewer
Moving to another PC: copy the folder and run setup.bat once (it rebuilds .\env;
needs internet). .\env is git-ignored and not committed.
run_gui.bat (or python scripts/gui.py) opens a window to choose an input
STEP/AP242 file, convert it to .aasx, and open the interactive 3D viewer — the
same pipeline as the CLI, no commands needed.
STP2X3D-style flags (--input/--output; short -i/-o). --output is optional
and defaults to <input>.aasx beside the input. Bare positional forms also work.
run.bat --input <file> [--output <file.aasx>] [options]
python -m step2aas -i <file> [-o <file.aasx>] [options]
Inputs:
- Part 21 STEP (
.stp/.step) — AP203 / AP214 / AP242, single part or assembly. - AP242 Domain Model XML (
.stpx/.xml) — CAx-IF/MBx-IF Assembly Structure BOM, both all-in-one and nested (multi-file sub-assembly) layouts. Referenced external STEP part files are resolved relative to the XML.
Options:
-
--assembly-structure {hierarchical,flat,single,lean-hierarchical,lean-flat}— AAS composition (defaulthierarchical):hierarchical— one AAS per unique part and per unique sub-assembly; each assembly's 02011 BOM lists its direct children (ArcheType=OneDown) and identifies their assets through each Node'sglobalAssetId.flat— one assembly AAS (root) + one AAS per unique part; the root BOM nests the whole tree (ArcheType=Full), nested sub-assemblies appear as co-managed BOM nodes.single— one AAS for the whole model (all parts as Model3D entries + a co-managedFullBOM tree); experimental comparison baseline.lean-hierarchical— AAS only for the root and for every design used more than once. Same answers ashierarchical(every repeated design is one asset), fewer AAS.lean-flat— AAS only for the root and for every part used more than once. Same answers asflat(every part use is listed separately in a BOM), fewer AAS. In both lean modes, a part without its own AAS keeps its STEP file as an extra Model3D entry of the AAS whose BOM lists it.
The root
globalAssetIdis identical across modes (same physical asset), while root AAS/submodel ids differ per mode — outputs of several modes for the same file can be loaded into one repository side by side. Part AAS are shared between hierarchical/flat. See Choosing a packaging option below. -
--link-only— do not embed the original whole-model file (DigitalFile holds its path). Split per-part STEP files are still embedded. -
--include-partial-nameplate— emit the intentionally-incomplete 02006 Nameplate (default: omit, per policy D7). -
--view— also build the HTML 3D viewer next to the.aasx. -
--open— open that viewer in a browser (implies--view). -
--no-3d— with--view, build the viewer without 3D geometry (structure only; faster). -
--derive-lightweight— reserved (future work §6a; raises NotImplementedError). -
-v/--verbose— verbose logging (shows gap/fallback decisions).
Examples:
python -m step2aas --input tests/as1/as1_root.stp -o out/as1.aasx --view
python -m step2aas assembly.stp -o out/assembly.aasx --view
python -m step2aas Torque_Convertor_Assy.stpx -o out/converter.aasx --open
STEP stores a sub-assembly once and records each place where it is used; the AAS only knows assets and BOM entries. For a component that occurs more than once, a package can answer two different questions:
- Is it the same design? (spare parts, catalogues, suppliers, engineering changes) — only if the design has its own AAS.
- Which use is it? (assembly records, torques, positions, plant or robot models) — only if the use is listed separately in a BOM.
The two conflict only inside repeated sub-assemblies: if a repeated sub-assembly has its own AAS, the parts inside it are listed once for all its uses. Repeated parts and designs used once never cause the conflict.
| Option | Repeated designs shown as one design | Every part use listed separately | AAS count |
|---|---|---|---|
hierarchical |
yes | no, inside repeated sub-assemblies | most |
lean-hierarchical |
yes | no, inside repeated sub-assemblies | fewer |
flat |
parts only | yes | medium |
lean-flat |
parts only | yes | fewer |
single |
no | yes | one |
Rule of thumb: data per use → lean-flat (or flat); one asset per reused design
→ lean-hierarchical; every sub-assembly as a deliverable → hierarchical. If the
model has no repeated sub-assembly, every option lists all uses separately.
- Default hierarchical composition: one AAS per unique part and per unique
sub-assembly. Each assembly's 02011 BOM (
ArcheType=OneDown) identifies its direct child assets throughglobalAssetId.--assembly-structure flatrestores a single root assembly AAS plus part AAS (nested sub-assemblies as co-managed BOM nodes).--assembly-structure singlepacks the whole model into one AAS. - Repeated parts collapse to a single AAS referenced by multiple BOM Nodes (design decision D2).
- Positions of every part use (no IDTA template element exists for them) are
stored in a
PlacementSceneJSON file referenced from the assembly's 3D-model submodel: one record per use with the asset id, a 4x4 transform in millimetres, the path of child indices from that assembly, and the deepest BOM Node on that path (bom,node,below). Uses inside a shared sub-assembly BOM are told apart by their path (mapping D8). - The original STEP is embedded per part as an AASX supplementary file; a 512² preview PNG is rendered offscreen (solid-colour placeholder fallback on headless GL failure, D6).
The AAS is being adopted as the exchange format for industrial digital twins, for example in the Catena-X data space (CX-0002 Digital Twins in Catena-X) and for the EU Digital Product Passport, starting with the battery passport (IDTA). Design data for these twins already exists in CAD; STP2AAS turns it into a package instead of re-entering it.
The converter emits design-time Type AAS, not a live factory twin. That is the join point, not a dead end:
- A line / plant AAS could use an explicit production-assignment reference to identify the product type a station is building.
- An instance AAS can keep live data and use
derivedFromto reference the type AAS;assetTypecan identify its type asset. Consumers and discovery services must implement lookup; type and instance are distinct assets. - Suppliers could publish part AAS for OEM BOM lookup after shared catalogue identities and discovery have been established.
See docs/mapping-draft.md §0.1 and §9 for downstream scenarios.
scripts/demo_basyx.py is a minimal upload/print demo.
Review status (2026-09-07): optional SameAs relationships are omitted; HasPart
uses Entity model references and self-managed Nodes use globalAssetId for asset
lookup. XML v2 includes resolved dependency content and relative-path namespaces
in identity. This intentionally changes prior XML IDs; P21 identity is unchanged.
See docs/identity-policy.md for migration and coverage.
Each package includes a custom ConversionProvenance JSON record (source hashes,
tool versions, mode, extraction coverage). Assembly volume/area is omitted when
any descendant lacks that property. The root mapping/*.yaml remains canonical
and is copied into the wheel during the build.
scripts/validate_package.py package.aasx --xsd path/to/AAS.xsd --output report.json
checks XML with a supplied official schema and independently inspects selected
references, entity kinds, lists, and embedded files. It does not certify every
IDTA template constraint.
Render an .aasx to a self-contained HTML viewer — AAS structure tree + BOM +
TechnicalData + preview thumbnails on one side, and an interactive WebGL 3D
viewport (geometry tessellated from the embedded STEP with pythonocc) on the
other. No server, no third-party JS; open the .html in any browser.
view.bat out\suspension.aasx --open # build + open (click a part to load its 3D)
view.bat out\part.aasx --no-3d # structure only (faster)
python -m step2aas.viewer out\x.aasx # equivalent module form
The scripts below need only the generated packages (the reader shares no code with the converter):
scripts/reconstruct_aasx.py— package-only reader: rebuilds the assembly from BOMs and placement scenes, counts shared designs and separately listed uses.scripts/evaluate_compositions.py,scripts/evaluate_lean.py— compare the packages of all options with the predictions from the product graph.scripts/aascore_verify.py— independent constraint check with aas-core3.1.scripts/fusion_namematch.py,scripts/fusion_crosscheck.py— compare package values with the native Fusion 360 records.scripts/case_stats.py,scripts/size_law.py,scripts/paper_stats.py— case-study records, package-size prediction, and summary numbers.scripts/ocp_compat/— a thinOCC.*layer over the OCP bindings, so the converter also runs where pythonocc-core is unavailable.
pytest -x -q
Roundtrip tests convert an in-memory IR (and optional fixtures), reload the .aasx
with basyx, and assert submodels, semanticIds, and BOM cardinality. Drop STEP/AP242
datasets under tests/ (gitignored) to exercise real-world models; AP242 tests skip
when none are present. Coverage/size/time CSV: python scripts/evaluate.py --synthetic.
The public CAx-IF AS1 sample used in the screenshot is tests/as1/as1_root.stp.
- AS1 is a public AP214 sample (CAx-IF). A copy lives at
tests/as1/as1_root.stp. - Fusion 360 Gallery assembly STEP files are not redistributed here (dataset
license is non-commercial research). To reproduce the corpus sweep locally, place
the Gallery archives on disk and run
scripts/download_fusion.py,scripts/extract_fusion.py, andscripts/run_fusion_experiment.py. - Conversion outputs (
.aasx, HTML viewers, CSVs) stay underout/and are gitignored.
docs/mapping-draft.md— STEP ↔ IDTA submodel mapping specification (authoritative)docs/identity-policy.md— identifier scheme and XML v2 migrationdocs/verification-log.md— semanticId verification status + extraction/AP242 validation
Soonjo Kwon — School of Mechanical Engineering, Pusan National University, Busan, Republic of Korea (soonjo.kwon@pusan.ac.kr).
Released under the MIT License (LICENSE).
