From 8800906df0ba2975399d8c8a4af968852d8b968b Mon Sep 17 00:00:00 2001 From: Moritz Sommer Date: Mon, 1 Sep 2025 09:19:53 +0200 Subject: [PATCH 1/2] sdk: Add tutorial for Submodel navigation Previously, we lacked a tutorial demonstrating how to navigate a Submodel's hierarchy using IdShorts and IdShortPaths. This adds a simple tutorial for Submodel navigation and updates the documentation to reference it. The end user is shown how to navigate SubmodelElements, such as simple Properties, Property Collections, Property Lists and Collection Lists. Fixes #351 --- sdk/README.md | 3 +- .../aas/examples/tutorial_navigate_aas.py | 140 ++++++++++++++++++ sdk/docs/source/tutorials/index.rst | 3 +- .../tutorials/tutorial_navigate_aas.rst | 7 + 4 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 sdk/basyx/aas/examples/tutorial_navigate_aas.py create mode 100644 sdk/docs/source/tutorials/tutorial_navigate_aas.rst diff --git a/sdk/README.md b/sdk/README.md index 5dfd2e9a..5c1457b3 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -124,10 +124,11 @@ write_aas_xml_file(file='Simple_Submodel.xml', data=data) For further examples and tutorials, check out the `basyx.aas.examples`-package. Here is a quick overview: * [`tutorial_create_simple_aas`](./basyx/aas/examples/tutorial_create_simple_aas.py): Create an Asset Administration Shell, including an Asset object and a Submodel +* [`tutorial_navigate_aas`](./basyx/aas/examples/tutorial_navigate_aas.py): Navigate Asset Administration Shell Submodels using IdShorts and IdShortPaths * [`tutorial_storage`](./basyx/aas/examples/tutorial_storage.py): Manage a larger number of Asset Administration Shells in an ObjectStore and resolve references * [`tutorial_serialization_deserialization`](./basyx/aas/examples/tutorial_serialization_deserialization.py): Use the JSON and XML serialization/deserialization for single objects or full standard-compliant files -* [`tutorial_aasx`](./basyx/aas/examples/tutorial_aasx.py): Export Asset Administration Shells with related objects and auxiliary files to AASX package files * [`tutorial_backend_couchdb`](./basyx/aas/examples/tutorial_backend_couchdb.py): Use the *Backends* interface (`update()/commit()` methods) to manage and retrieve AAS objects in a CouchDB document database +* [`tutorial_aasx`](./basyx/aas/examples/tutorial_aasx.py): Export Asset Administration Shells with related objects and auxiliary files to AASX package files ### Documentation diff --git a/sdk/basyx/aas/examples/tutorial_navigate_aas.py b/sdk/basyx/aas/examples/tutorial_navigate_aas.py new file mode 100644 index 00000000..089140d7 --- /dev/null +++ b/sdk/basyx/aas/examples/tutorial_navigate_aas.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# This work is licensed under a Creative Commons CCZero 1.0 Universal License. +# See http://creativecommons.org/publicdomain/zero/1.0/ for more information. +""" +Tutorial for navigating a Submodel's hierarchy using IdShorts and IdShortPaths. +""" + +from basyx.aas import model + +# In this tutorial, you will learn how to create a Submodel with different kinds of SubmodelElements and how to navigate +# through them using IdShorts and IdShortPaths. +# +# Step-by-Step Guide: +# Step 1: Create a Submodel with a Property, a Property Collection, a Property List and a Collection List +# Step 2: Navigate through the Submodel using IdShorts and IdShortPaths + + +######################################################################## +# Step 1: Create a Submodel with a navigable SubmodelElement hierarchy # +######################################################################## + +# Step 1.1: Create a Submodel +submodel = model.Submodel(id_="https://iat.rwth-aachen.de/Simple_Submodel") + +# Step 1.2: Add a single Property to the Submodel +my_property = model.Property( + id_short="MyProperty", + value_type=model.datatypes.String, + value="I am a simple Property" +) +submodel.submodel_element.add(my_property) + +# Step 1.3: Add a Property Collection to the Submodel +my_property_collection = model.SubmodelElementCollection( + id_short="MyPropertyCollection", + value={ + model.Property( + id_short="MyProperty0", + value_type=model.datatypes.String, + value="I am the first of two Properties within a Property Collection" + ), + model.Property( + id_short="MyProperty1", + value_type=model.datatypes.String, + value="I am the second of two Properties within a Property Collection" + ) + } +) +submodel.submodel_element.add(my_property_collection) + +# Step 1.4: Add a Property List to the Submodel +my_property_list = model.SubmodelElementList( + id_short="MyPropertyList", + type_value_list_element=model.Property, + value_type_list_element=model.datatypes.String, + order_relevant=True, + value=[ + model.Property( + id_short=None, + value_type=model.datatypes.String, + value="I am Property 0 within a Property List" + ), + model.Property( + id_short=None, + value_type=model.datatypes.String, + value="I am Property 1 within a Property List" + ) + ] +) +submodel.submodel_element.add(my_property_list) + +# Step 1.5: Add a Collection List to the Submodel +my_property_collection_0 = model.SubmodelElementCollection( + id_short=None, + value={model.Property( + id_short="MyProperty", + value_type=model.datatypes.String, + value="I am a simple Property within Property Collection 0" + )} +) +my_property_collection_1 = model.SubmodelElementCollection( + id_short=None, + value={model.Property( + id_short="MyProperty", + value_type=model.datatypes.String, + value="I am a simple Property within Property Collection 1" + )} +) +my_property_collection_2 = model.SubmodelElementCollection( + id_short=None, + value={model.Property( + id_short="MyProperty", + value_type=model.datatypes.String, + value="I am a simple Property within Property Collection 2" + )} +) +my_collection_list = model.SubmodelElementList( + id_short="MyCollectionList", + type_value_list_element=model.SubmodelElementCollection, + order_relevant=True, + value=[my_property_collection_0, my_property_collection_1, my_property_collection_2] +) +submodel.submodel_element.add(my_collection_list) + + +######################################################################### +# Step 2: Navigate through the Submodel using IdShorts and IdShortPaths # +######################################################################### + +# Step 2.1: Access a single Property via its IdShort +my_property = submodel.get_referable("MyProperty") +print(f"my_property: id_short = {my_property.id_short}, value = {my_property.value}\n") + +# Step 2.2.1: Access a Property within a Property Collection step by step via its IdShort +my_property_collection = submodel.get_referable("MyPropertyCollection") +my_property_collection_0 = my_property_collection.get_referable("MyProperty0") +print(f"my_property_collection_0: id_short = {my_property_collection_0}, value = {my_property_collection_0.value}") + +# Step 2.2.2: Access a Property within a Property Collection via its IdShortPath +my_property_collection_1 = submodel.get_referable(["MyPropertyCollection", "MyProperty1"]) +print(f"my_property_collection_1: id_short = {my_property_collection_1}, value = {my_property_collection_1.value}\n") + +# Step 2.3.1: Access a Property within a Property List step by step via its index +my_property_list = submodel.get_referable("MyPropertyList") +my_property_list_0 = my_property_list.get_referable("0") +print(f"my_property_list_0: id_short = {my_property_list_0}, value = {my_property_list_0.value}") + +# Step 2.3.2: Access a Property within a Property List via its IdShortPath +my_property_list_1 = submodel.get_referable(["MyPropertyList", "1"]) +print(f"my_property_list_1: id_short = {my_property_list_1}, value = {my_property_list_1.value}\n") + +# Step 2.4.1: Access a Property within a Collection List step by step via its index and IdShort +my_collection_list = submodel.get_referable("MyCollectionList") +my_collection_list_0 = my_collection_list.get_referable("0") +my_collection_list_0_0 = my_collection_list_0.get_referable("MyProperty") +print(f"my_collection_list_0_0: id_short = {my_collection_list_0_0}, value = {my_collection_list_0_0.value}") + +# Step 2.4.2: Access a Property within a Collection List via its IdShortPath +my_collection_list_2_0 = submodel.get_referable(["MyCollectionList", "2", "MyProperty"]) +print(f"my_collection_list_2_0: id_short = {my_collection_list_2_0}, value = {my_collection_list_2_0.value}") diff --git a/sdk/docs/source/tutorials/index.rst b/sdk/docs/source/tutorials/index.rst index ce2fe76a..dfb4149e 100644 --- a/sdk/docs/source/tutorials/index.rst +++ b/sdk/docs/source/tutorials/index.rst @@ -7,7 +7,8 @@ Tutorials for working with the Eclipse BaSyx Python SDK :caption: Contents: tutorial_create_simple_aas - tutorial_serialization_deserialization + tutorial_navigate_aas tutorial_storage + tutorial_serialization_deserialization tutorial_backend_couchdb tutorial_aasx diff --git a/sdk/docs/source/tutorials/tutorial_navigate_aas.rst b/sdk/docs/source/tutorials/tutorial_navigate_aas.rst new file mode 100644 index 00000000..57c6a935 --- /dev/null +++ b/sdk/docs/source/tutorials/tutorial_navigate_aas.rst @@ -0,0 +1,7 @@ +Tutorial: Navigate Submodels +============================ + +.. _tutorial_navigate_aas: + +.. literalinclude:: ../../../basyx/aas/examples/tutorial_navigate_aas.py + :language: python From 511cddb9fdf613ecadcf57f71db6f8450cd38510 Mon Sep 17 00:00:00 2001 From: Moritz Sommer Date: Mon, 1 Sep 2025 10:24:49 +0200 Subject: [PATCH 2/2] sdk/basyx/aas/examples/tutorial_navigate_aas.py: Fix mypy errors --- .../aas/examples/tutorial_navigate_aas.py | 68 ++++++++++++++----- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/sdk/basyx/aas/examples/tutorial_navigate_aas.py b/sdk/basyx/aas/examples/tutorial_navigate_aas.py index 089140d7..d9020648 100644 --- a/sdk/basyx/aas/examples/tutorial_navigate_aas.py +++ b/sdk/basyx/aas/examples/tutorial_navigate_aas.py @@ -6,6 +6,7 @@ """ from basyx.aas import model +from typing import cast # In this tutorial, you will learn how to create a Submodel with different kinds of SubmodelElements and how to navigate # through them using IdShorts and IdShortPaths. @@ -108,33 +109,66 @@ ######################################################################### # Step 2.1: Access a single Property via its IdShort -my_property = submodel.get_referable("MyProperty") +my_property = cast(model.Property, submodel.get_referable("MyProperty")) print(f"my_property: id_short = {my_property.id_short}, value = {my_property.value}\n") # Step 2.2.1: Access a Property within a Property Collection step by step via its IdShort -my_property_collection = submodel.get_referable("MyPropertyCollection") -my_property_collection_0 = my_property_collection.get_referable("MyProperty0") -print(f"my_property_collection_0: id_short = {my_property_collection_0}, value = {my_property_collection_0.value}") +my_property_collection = cast(model.SubmodelElementCollection, submodel.get_referable("MyPropertyCollection")) +my_property_collection_property_0 = cast(model.Property, my_property_collection.get_referable("MyProperty0")) +print( + f"my_property_collection_property_0: " + f"id_short = {my_property_collection_property_0}, " + f"value = {my_property_collection_property_0.value}" +) # Step 2.2.2: Access a Property within a Property Collection via its IdShortPath -my_property_collection_1 = submodel.get_referable(["MyPropertyCollection", "MyProperty1"]) -print(f"my_property_collection_1: id_short = {my_property_collection_1}, value = {my_property_collection_1.value}\n") +my_property_collection_property_1 = cast( + model.Property, + submodel.get_referable(["MyPropertyCollection", "MyProperty1"]) +) +print( + f"my_property_collection_property_1: " + f"id_short = {my_property_collection_property_1}, " + f"value = {my_property_collection_property_1.value}\n" +) # Step 2.3.1: Access a Property within a Property List step by step via its index -my_property_list = submodel.get_referable("MyPropertyList") -my_property_list_0 = my_property_list.get_referable("0") -print(f"my_property_list_0: id_short = {my_property_list_0}, value = {my_property_list_0.value}") +my_property_list = cast(model.SubmodelElementList, submodel.get_referable("MyPropertyList")) +my_property_list_property_0 = cast(model.Property, my_property_list.get_referable("0")) +print( + f"my_property_list_property_0: " + f"id_short = {my_property_list_property_0}, " + f"value = {my_property_list_property_0.value}" +) # Step 2.3.2: Access a Property within a Property List via its IdShortPath -my_property_list_1 = submodel.get_referable(["MyPropertyList", "1"]) -print(f"my_property_list_1: id_short = {my_property_list_1}, value = {my_property_list_1.value}\n") +my_property_list_property_1 = cast(model.Property, submodel.get_referable(["MyPropertyList", "1"])) +print( + f"my_property_list_property_1: " + f"id_short = {my_property_list_property_1}, " + f"value = {my_property_list_property_1.value}\n" +) # Step 2.4.1: Access a Property within a Collection List step by step via its index and IdShort -my_collection_list = submodel.get_referable("MyCollectionList") -my_collection_list_0 = my_collection_list.get_referable("0") -my_collection_list_0_0 = my_collection_list_0.get_referable("MyProperty") -print(f"my_collection_list_0_0: id_short = {my_collection_list_0_0}, value = {my_collection_list_0_0.value}") +my_collection_list = cast(model.SubmodelElementList, submodel.get_referable("MyCollectionList")) +my_collection_list_collection_0 = cast(model.SubmodelElementCollection, my_collection_list.get_referable("0")) +my_collection_list_collection_0_property_0 = cast( + model.Property, + my_collection_list_collection_0.get_referable("MyProperty") +) +print( + f"my_collection_list_collection_0_property_0: " + f"id_short = {my_collection_list_collection_0_property_0}, " + f"value = {my_collection_list_collection_0_property_0.value}" +) # Step 2.4.2: Access a Property within a Collection List via its IdShortPath -my_collection_list_2_0 = submodel.get_referable(["MyCollectionList", "2", "MyProperty"]) -print(f"my_collection_list_2_0: id_short = {my_collection_list_2_0}, value = {my_collection_list_2_0.value}") +my_collection_list_collection_2_property_0 = cast( + model.Property, + submodel.get_referable(["MyCollectionList", "2", "MyProperty"]) +) +print( + f"my_collection_list_collection_2_property_0: " + f"id_short = {my_collection_list_collection_2_property_0}, " + f"value = {my_collection_list_collection_2_property_0.value}" +)