Skip to content

Commit

Permalink
Merge pull request #174 from eclipse-basyx/improve/V30
Browse files Browse the repository at this point in the history
Implement v3.0 of the metamodel specification

For the detailed documentation of the changes, please refer to the [prior PRs](https://github.com/eclipse-basyx/basyx-python-sdk/pulls?page=4&q=is%3Apr+base%3Aimprove%2FV30)
  • Loading branch information
s-heppner committed Nov 25, 2023
2 parents 662ccf6 + 2db802b commit 2063c8a
Show file tree
Hide file tree
Showing 121 changed files with 29,485 additions and 13,997 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
# Coverage artifacts
/.coverage
/htmlcov/
/docs/build/

# customized config files
/test/test_config.ini
42 changes: 24 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@

(formerly known as PyI40AAS – Python Industry 4.0 Asset Administration Shell)

The Eclipse BaSyx Python project focuses on providing a Python implementation of the Asset Administration Shell (AAS) for Industry 4.0 Systems,
compliant with the meta model and interface specification provided in
[the document “Details of the Asset Administration Shell” (v2.0.1)](https://www.plattform-i40.de/IP/Redaktion/DE/Downloads/Publikation/Details_of_the_Asset_Administration_Shell_Part1_V2.html).
It currently adheres to version 2.0.1 of the specification.
An updated version with support for version 3.0RC01 is already in preparation and will be made available on an additional branch of this repository and in a future major release.
The Eclipse BaSyx Python project focuses on providing a Python implementation of the Asset Administration Shell (AAS)
for Industry 4.0 Systems.
These are the currently implemented specifications:

| Specification | Version |
|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| Part 1: Metamodel | [v3.0 (01001-3-0)](https://industrialdigitaltwin.org/content-hub/aasspecifications/idta_01001-3-0_metamodel) |
| Part 2: API | not implemented yet |
| Part 3a: Data Specification IEC 61360 | [v3.0 (01003-a-3-0)](https://industrialdigitaltwin.org/content-hub/aasspecifications/idta_01003-a-3-0_data_specification) |
| Part 5: Package File Format (AASX) | [v3.0 (01005-3-0)](https://industrialdigitaltwin.org/content-hub/aasspecifications/idta-01005-3-0_package_file_format_aasx) |

## Features

* Modelling of AASs as Python objects (according to DotAAS sec. 4)
* **except for**: Security extension of the metamodel (according to DotAAS sec. 5), *HasDataSpecification*
* Reading and writing of AASX package files (according to DotAAS sec. 6)
* (De-)serialization of AAS objects into/from JSON and XML (according to DotAAS sec. 7)
* Modelling of AASs as Python objects
* **except for**: *HasDataSpecification*
* Reading and writing of AASX package files
* (De-)serialization of AAS objects into/from JSON and XML
* Storing of AAS objects in CouchDB, Backend infrastructure for easy expansion
* Compliance checking of AAS XML and JSON files

Expand Down Expand Up @@ -53,9 +58,12 @@ Optional production usage dependencies:
* For using the Compliance Tool to validate JSON files against the JSON Schema: `jsonschema` and its
dependencies (MIT License, Apache License, PSF License)

Development/testing/example dependencies (see `requirements.txt`):
Development/testing/documentation/example dependencies (see `requirements.txt`):
* `jsonschema` and its dependencies (MIT License, Apache License, PSF License)
* `psutil` (BSD 3-clause License)
* `Sphinx` and its dependencies (multiple licenses)
* `sphinx-rtd-theme` and its dependencies
* `sphinx-argparse` (MIT License)

Dependencies for building the documentation:
* `Sphinx` and its dependencies (BSD 2-clause License, MIT License, Apache License)
Expand Down Expand Up @@ -89,19 +97,17 @@ Create a `Submodel`:
```python
from basyx.aas import model # Import all BaSyx Python SDK classes from the model package

identifier = model.Identifier('https://acplt.org/Simple_Submodel', model.IdentifierType.IRI)
submodel = model.Submodel(identification=identifier)
identifier = 'https://acplt.org/Simple_Submodel'
submodel = model.Submodel(identifier)
```

Create a `Property` and add it to the `Submodel`:
```python
# create a global reference to a semantic description of the property
semantic_reference = model.Reference(
# create an external reference to a semantic description of the property
semantic_reference = model.ExternalReference(
(model.Key(
type_=model.KeyElements.GLOBAL_REFERENCE,
local=False,
value='http://acplt.org/Properties/SimpleProperty',
id_type=model.KeyType.IRI
type_=model.KeyTypes.GLOBAL_REFERENCE,
value='http://acplt.org/Properties/SimpleProperty'
),)
)
property = model.Property(
Expand Down
147 changes: 82 additions & 65 deletions basyx/aas/adapter/_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,87 +12,104 @@

from basyx.aas import model

MODELING_KIND: Dict[model.ModelingKind, str] = {
model.ModelingKind.TEMPLATE: 'Template',
model.ModelingKind.INSTANCE: 'Instance'}
# XML Namespace definition
XML_NS_MAP = {"aas": "https://admin-shell.io/aas/3/0"}
XML_NS_AAS = "{" + XML_NS_MAP["aas"] + "}"

MODELLING_KIND: Dict[model.ModellingKind, str] = {
model.ModellingKind.TEMPLATE: 'Template',
model.ModellingKind.INSTANCE: 'Instance'}

ASSET_KIND: Dict[model.AssetKind, str] = {
model.AssetKind.TYPE: 'Type',
model.AssetKind.INSTANCE: 'Instance'}
model.AssetKind.INSTANCE: 'Instance',
model.AssetKind.NOT_APPLICABLE: 'NotApplicable'}

QUALIFIER_KIND: Dict[model.QualifierKind, str] = {
model.QualifierKind.CONCEPT_QUALIFIER: 'ConceptQualifier',
model.QualifierKind.TEMPLATE_QUALIFIER: 'TemplateQualifier',
model.QualifierKind.VALUE_QUALIFIER: 'ValueQualifier'}

DIRECTION: Dict[model.Direction, str] = {
model.Direction.INPUT: 'input',
model.Direction.OUTPUT: 'output'}

KEY_ELEMENTS: Dict[model.KeyElements, str] = {
model.KeyElements.ASSET: 'Asset',
model.KeyElements.ASSET_ADMINISTRATION_SHELL: 'AssetAdministrationShell',
model.KeyElements.CONCEPT_DESCRIPTION: 'ConceptDescription',
model.KeyElements.SUBMODEL: 'Submodel',
model.KeyElements.ANNOTATED_RELATIONSHIP_ELEMENT: 'AnnotatedRelationshipElement',
model.KeyElements.BASIC_EVENT: 'BasicEvent',
model.KeyElements.BLOB: 'Blob',
model.KeyElements.CAPABILITY: 'Capability',
model.KeyElements.CONCEPT_DICTIONARY: 'ConceptDictionary',
model.KeyElements.DATA_ELEMENT: 'DataElement',
model.KeyElements.ENTITY: 'Entity',
model.KeyElements.EVENT: 'Event',
model.KeyElements.FILE: 'File',
model.KeyElements.MULTI_LANGUAGE_PROPERTY: 'MultiLanguageProperty',
model.KeyElements.OPERATION: 'Operation',
model.KeyElements.PROPERTY: 'Property',
model.KeyElements.RANGE: 'Range',
model.KeyElements.REFERENCE_ELEMENT: 'ReferenceElement',
model.KeyElements.RELATIONSHIP_ELEMENT: 'RelationshipElement',
model.KeyElements.SUBMODEL_ELEMENT: 'SubmodelElement',
model.KeyElements.SUBMODEL_ELEMENT_COLLECTION: 'SubmodelElementCollection',
model.KeyElements.VIEW: 'View',
model.KeyElements.GLOBAL_REFERENCE: 'GlobalReference',
model.KeyElements.FRAGMENT_REFERENCE: 'FragmentReference'}
STATE_OF_EVENT: Dict[model.StateOfEvent, str] = {
model.StateOfEvent.ON: 'on',
model.StateOfEvent.OFF: 'off'}

KEY_TYPES: Dict[model.KeyType, str] = {
model.KeyType.CUSTOM: 'Custom',
model.KeyType.IRDI: 'IRDI',
model.KeyType.IRI: 'IRI',
model.KeyType.IDSHORT: 'IdShort',
model.KeyType.FRAGMENT_ID: 'FragmentId'}
REFERENCE_TYPES: Dict[Type[model.Reference], str] = {
model.ExternalReference: 'ExternalReference',
model.ModelReference: 'ModelReference'}

IDENTIFIER_TYPES: Dict[model.IdentifierType, str] = {
model.IdentifierType.CUSTOM: 'Custom',
model.IdentifierType.IRDI: 'IRDI',
model.IdentifierType.IRI: 'IRI'}
KEY_TYPES: Dict[model.KeyTypes, str] = {
model.KeyTypes.ASSET_ADMINISTRATION_SHELL: 'AssetAdministrationShell',
model.KeyTypes.CONCEPT_DESCRIPTION: 'ConceptDescription',
model.KeyTypes.SUBMODEL: 'Submodel',
model.KeyTypes.ANNOTATED_RELATIONSHIP_ELEMENT: 'AnnotatedRelationshipElement',
model.KeyTypes.BASIC_EVENT_ELEMENT: 'BasicEventElement',
model.KeyTypes.BLOB: 'Blob',
model.KeyTypes.CAPABILITY: 'Capability',
model.KeyTypes.DATA_ELEMENT: 'DataElement',
model.KeyTypes.ENTITY: 'Entity',
model.KeyTypes.EVENT_ELEMENT: 'EventElement',
model.KeyTypes.FILE: 'File',
model.KeyTypes.MULTI_LANGUAGE_PROPERTY: 'MultiLanguageProperty',
model.KeyTypes.OPERATION: 'Operation',
model.KeyTypes.PROPERTY: 'Property',
model.KeyTypes.RANGE: 'Range',
model.KeyTypes.REFERENCE_ELEMENT: 'ReferenceElement',
model.KeyTypes.RELATIONSHIP_ELEMENT: 'RelationshipElement',
model.KeyTypes.SUBMODEL_ELEMENT: 'SubmodelElement',
model.KeyTypes.SUBMODEL_ELEMENT_COLLECTION: 'SubmodelElementCollection',
model.KeyTypes.SUBMODEL_ELEMENT_LIST: 'SubmodelElementList',
model.KeyTypes.GLOBAL_REFERENCE: 'GlobalReference',
model.KeyTypes.FRAGMENT_REFERENCE: 'FragmentReference'}

ENTITY_TYPES: Dict[model.EntityType, str] = {
model.EntityType.CO_MANAGED_ENTITY: 'CoManagedEntity',
model.EntityType.SELF_MANAGED_ENTITY: 'SelfManagedEntity'}

IEC61360_DATA_TYPES: Dict[model.concept.IEC61360DataType, str] = {
model.concept.IEC61360DataType.DATE: 'DATE',
model.concept.IEC61360DataType.STRING: 'STRING',
model.concept.IEC61360DataType.STRING_TRANSLATABLE: 'STRING_TRANSLATABLE',
model.concept.IEC61360DataType.REAL_MEASURE: 'REAL_MEASURE',
model.concept.IEC61360DataType.REAL_COUNT: 'REAL_COUNT',
model.concept.IEC61360DataType.REAL_CURRENCY: 'REAL_CURRENCY',
model.concept.IEC61360DataType.BOOLEAN: 'BOOLEAN',
model.concept.IEC61360DataType.URL: 'URL',
model.concept.IEC61360DataType.RATIONAL: 'RATIONAL',
model.concept.IEC61360DataType.RATIONAL_MEASURE: 'RATIONAL_MEASURE',
model.concept.IEC61360DataType.TIME: 'TIME',
model.concept.IEC61360DataType.TIMESTAMP: 'TIMESTAMP',
IEC61360_DATA_TYPES: Dict[model.base.DataTypeIEC61360, str] = {
model.base.DataTypeIEC61360.DATE: 'DATE',
model.base.DataTypeIEC61360.STRING: 'STRING',
model.base.DataTypeIEC61360.STRING_TRANSLATABLE: 'STRING_TRANSLATABLE',
model.base.DataTypeIEC61360.INTEGER_MEASURE: 'INTEGER_MEASURE',
model.base.DataTypeIEC61360.INTEGER_COUNT: 'INTEGER_COUNT',
model.base.DataTypeIEC61360.INTEGER_CURRENCY: 'INTEGER_CURRENCY',
model.base.DataTypeIEC61360.REAL_MEASURE: 'REAL_MEASURE',
model.base.DataTypeIEC61360.REAL_COUNT: 'REAL_COUNT',
model.base.DataTypeIEC61360.REAL_CURRENCY: 'REAL_CURRENCY',
model.base.DataTypeIEC61360.BOOLEAN: 'BOOLEAN',
model.base.DataTypeIEC61360.IRI: 'IRI',
model.base.DataTypeIEC61360.IRDI: 'IRDI',
model.base.DataTypeIEC61360.RATIONAL: 'RATIONAL',
model.base.DataTypeIEC61360.RATIONAL_MEASURE: 'RATIONAL_MEASURE',
model.base.DataTypeIEC61360.TIME: 'TIME',
model.base.DataTypeIEC61360.TIMESTAMP: 'TIMESTAMP',
model.base.DataTypeIEC61360.HTML: 'HTML',
model.base.DataTypeIEC61360.BLOB: 'BLOB',
model.base.DataTypeIEC61360.FILE: 'FILE',
}

IEC61360_LEVEL_TYPES: Dict[model.concept.IEC61360LevelType, str] = {
model.concept.IEC61360LevelType.MIN: 'Min',
model.concept.IEC61360LevelType.MAX: 'Max',
model.concept.IEC61360LevelType.NOM: 'Nom',
model.concept.IEC61360LevelType.TYP: 'Typ',
IEC61360_LEVEL_TYPES: Dict[model.base.IEC61360LevelType, str] = {
model.base.IEC61360LevelType.MIN: 'min',
model.base.IEC61360LevelType.NOM: 'nom',
model.base.IEC61360LevelType.TYP: 'typ',
model.base.IEC61360LevelType.MAX: 'max',
}

MODELING_KIND_INVERSE: Dict[str, model.ModelingKind] = {v: k for k, v in MODELING_KIND.items()}
MODELLING_KIND_INVERSE: Dict[str, model.ModellingKind] = {v: k for k, v in MODELLING_KIND.items()}
ASSET_KIND_INVERSE: Dict[str, model.AssetKind] = {v: k for k, v in ASSET_KIND.items()}
KEY_ELEMENTS_INVERSE: Dict[str, model.KeyElements] = {v: k for k, v in KEY_ELEMENTS.items()}
KEY_TYPES_INVERSE: Dict[str, model.KeyType] = {v: k for k, v in KEY_TYPES.items()}
IDENTIFIER_TYPES_INVERSE: Dict[str, model.IdentifierType] = {v: k for k, v in IDENTIFIER_TYPES.items()}
QUALIFIER_KIND_INVERSE: Dict[str, model.QualifierKind] = {v: k for k, v in QUALIFIER_KIND.items()}
DIRECTION_INVERSE: Dict[str, model.Direction] = {v: k for k, v in DIRECTION.items()}
STATE_OF_EVENT_INVERSE: Dict[str, model.StateOfEvent] = {v: k for k, v in STATE_OF_EVENT.items()}
REFERENCE_TYPES_INVERSE: Dict[str, Type[model.Reference]] = {v: k for k, v in REFERENCE_TYPES.items()}
KEY_TYPES_INVERSE: Dict[str, model.KeyTypes] = {v: k for k, v in KEY_TYPES.items()}
ENTITY_TYPES_INVERSE: Dict[str, model.EntityType] = {v: k for k, v in ENTITY_TYPES.items()}
IEC61360_DATA_TYPES_INVERSE: Dict[str, model.concept.IEC61360DataType] = {v: k for k, v in IEC61360_DATA_TYPES.items()}
IEC61360_LEVEL_TYPES_INVERSE: Dict[str, model.concept.IEC61360LevelType] = \
IEC61360_DATA_TYPES_INVERSE: Dict[str, model.base.DataTypeIEC61360] = {v: k for k, v in IEC61360_DATA_TYPES.items()}
IEC61360_LEVEL_TYPES_INVERSE: Dict[str, model.base.IEC61360LevelType] = \
{v: k for k, v in IEC61360_LEVEL_TYPES.items()}

KEY_ELEMENTS_CLASSES_INVERSE: Dict[model.KeyElements, Type[model.Referable]] = \
{v: k for k, v in model.KEY_ELEMENTS_CLASSES.items()}
KEY_TYPES_CLASSES_INVERSE: Dict[model.KeyTypes, Type[model.Referable]] = \
{v: k for k, v in model.KEY_TYPES_CLASSES.items()}
Loading

0 comments on commit 2063c8a

Please sign in to comment.