aas-http-client 0.2.3__py3-none-any.whl → 0.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of aas-http-client might be problematic. Click here for more details.
- aas_http_client/client.py +80 -19
- aas_http_client/demo/demo_process.py +34 -25
- aas_http_client/utilities/model_builder.py +37 -23
- aas_http_client/wrapper/sdk_wrapper.py +78 -22
- {aas_http_client-0.2.3.dist-info → aas_http_client-0.2.4.dist-info}/METADATA +1 -1
- aas_http_client-0.2.4.dist-info/RECORD +14 -0
- aas_http_client-0.2.3.dist-info/RECORD +0 -14
- {aas_http_client-0.2.3.dist-info → aas_http_client-0.2.4.dist-info}/WHEEL +0 -0
- {aas_http_client-0.2.3.dist-info → aas_http_client-0.2.4.dist-info}/licenses/LICENSE +0 -0
- {aas_http_client-0.2.3.dist-info → aas_http_client-0.2.4.dist-info}/top_level.txt +0 -0
aas_http_client/client.py
CHANGED
|
@@ -121,6 +121,8 @@ class AasHttpClient(BaseModel):
|
|
|
121
121
|
content = response.content.decode("utf-8")
|
|
122
122
|
return json.loads(content)
|
|
123
123
|
|
|
124
|
+
# region shells
|
|
125
|
+
|
|
124
126
|
def post_shells(self, aas_data: dict) -> dict | None:
|
|
125
127
|
"""Post an Asset Administration Shell (AAS) to the REST API.
|
|
126
128
|
|
|
@@ -311,11 +313,15 @@ class AasHttpClient(BaseModel):
|
|
|
311
313
|
|
|
312
314
|
return True
|
|
313
315
|
|
|
314
|
-
|
|
315
|
-
"""Post a submodel to the REST API.
|
|
316
|
+
# endregion
|
|
316
317
|
|
|
317
|
-
|
|
318
|
-
|
|
318
|
+
# region submodels
|
|
319
|
+
|
|
320
|
+
def post_submodels(self, submodel_data: dict) -> dict | None:
|
|
321
|
+
"""Create a new Submodel.
|
|
322
|
+
|
|
323
|
+
:param Submodel_data: Json data of the Submodel to post
|
|
324
|
+
:return: Submodel data or None if an error occurred
|
|
319
325
|
"""
|
|
320
326
|
url = f"{self.base_url}/submodels"
|
|
321
327
|
|
|
@@ -325,19 +331,19 @@ class AasHttpClient(BaseModel):
|
|
|
325
331
|
|
|
326
332
|
if response.status_code not in (STATUS_CODE_201, STATUS_CODE_202):
|
|
327
333
|
log_response_errors(response)
|
|
328
|
-
return
|
|
334
|
+
return None
|
|
329
335
|
|
|
330
336
|
except requests.exceptions.RequestException as e:
|
|
331
337
|
logger.error(f"Error call REST API: {e}")
|
|
332
|
-
return
|
|
338
|
+
return None
|
|
333
339
|
|
|
334
340
|
content = response.content.decode("utf-8")
|
|
335
341
|
return json.loads(content)
|
|
336
342
|
|
|
337
343
|
def put_submodels_by_id(self, identifier: str, submodel_data: dict) -> bool:
|
|
338
|
-
"""
|
|
344
|
+
"""Updates a existing Submodel.
|
|
339
345
|
|
|
340
|
-
:param identifier:
|
|
346
|
+
:param identifier: Encoded ID of the Submodel to update
|
|
341
347
|
:param submodel_data: Json data of the Submodel to update
|
|
342
348
|
:return: True if the update was successful, False otherwise
|
|
343
349
|
"""
|
|
@@ -359,9 +365,9 @@ class AasHttpClient(BaseModel):
|
|
|
359
365
|
return True
|
|
360
366
|
|
|
361
367
|
def get_submodels(self) -> list[dict] | None:
|
|
362
|
-
"""
|
|
368
|
+
"""Returns all Submodels
|
|
363
369
|
|
|
364
|
-
:return: Submodel
|
|
370
|
+
:return: List of Submodel data or None if an error occurred
|
|
365
371
|
"""
|
|
366
372
|
url = f"{self.base_url}/submodels"
|
|
367
373
|
|
|
@@ -381,10 +387,10 @@ class AasHttpClient(BaseModel):
|
|
|
381
387
|
return json.loads(content)
|
|
382
388
|
|
|
383
389
|
def get_submodels_by_id(self, submodel_id: str) -> dict | None:
|
|
384
|
-
"""
|
|
390
|
+
"""Returns a specific Submodel.
|
|
385
391
|
|
|
386
|
-
:param submodel_id: ID of the
|
|
387
|
-
:return: Submodel
|
|
392
|
+
:param submodel_id: Encoded ID of the Submodel to retrieve
|
|
393
|
+
:return: Submodel data or None if an error occurred
|
|
388
394
|
"""
|
|
389
395
|
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
390
396
|
url = f"{self.base_url}/submodels/{decoded_submodel_id}"
|
|
@@ -404,7 +410,12 @@ class AasHttpClient(BaseModel):
|
|
|
404
410
|
content = response.content.decode("utf-8")
|
|
405
411
|
return json.loads(content)
|
|
406
412
|
|
|
407
|
-
def patch_submodel_by_id(self, submodel_id: str, submodel_data: dict):
|
|
413
|
+
def patch_submodel_by_id(self, submodel_id: str, submodel_data: dict) -> bool:
|
|
414
|
+
"""Updates an existing Submodel
|
|
415
|
+
|
|
416
|
+
:param submodel_id: Encoded ID of the Submodel to delete
|
|
417
|
+
:return: True if the patch was successful, False otherwise
|
|
418
|
+
"""
|
|
408
419
|
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
409
420
|
url = f"{self.base_url}/submodels/{decoded_submodel_id}"
|
|
410
421
|
|
|
@@ -423,9 +434,9 @@ class AasHttpClient(BaseModel):
|
|
|
423
434
|
return True
|
|
424
435
|
|
|
425
436
|
def delete_submodels_by_id(self, submodel_id: str) -> bool:
|
|
426
|
-
"""
|
|
437
|
+
"""Deletes a existing Submodel.
|
|
427
438
|
|
|
428
|
-
:param submodel_id: ID of the
|
|
439
|
+
:param submodel_id: Encoded ID of the Submodel to delete
|
|
429
440
|
:return: True if the deletion was successful, False otherwise
|
|
430
441
|
"""
|
|
431
442
|
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
@@ -445,6 +456,57 @@ class AasHttpClient(BaseModel):
|
|
|
445
456
|
|
|
446
457
|
return True
|
|
447
458
|
|
|
459
|
+
def get_submodels_submodel_elements(self, submodel_id: str) -> list[dict] | None:
|
|
460
|
+
"""Returns all Submodel elements including their hierarchy.
|
|
461
|
+
|
|
462
|
+
:param submodel_id: Encoded ID of the Submodel to retrieve elements from
|
|
463
|
+
:return: List of Submodel element data or None if an error occurred
|
|
464
|
+
"""
|
|
465
|
+
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
466
|
+
url = f"{self.base_url}/submodels/{decoded_submodel_id}/submodel-elements"
|
|
467
|
+
|
|
468
|
+
try:
|
|
469
|
+
response = self._session.get(url, headers=HEADERS, timeout=self.time_out)
|
|
470
|
+
logger.debug(f"Call REST API url '{response.url}'")
|
|
471
|
+
|
|
472
|
+
if response.status_code != STATUS_CODE_200:
|
|
473
|
+
log_response_errors(response)
|
|
474
|
+
return None
|
|
475
|
+
|
|
476
|
+
except requests.exceptions.RequestException as e:
|
|
477
|
+
logger.error(f"Error call REST API: {e}")
|
|
478
|
+
return None
|
|
479
|
+
|
|
480
|
+
content = response.content.decode("utf-8")
|
|
481
|
+
return json.loads(content)
|
|
482
|
+
|
|
483
|
+
def post_submodels_submodel_elements(self, submodel_id: str, submodel_element_data: dict) -> dict | None:
|
|
484
|
+
"""Create a new Submodel element.
|
|
485
|
+
|
|
486
|
+
:param submodel_id: Encoded ID of the Submodel to create elements for
|
|
487
|
+
:return: Submodel element data or None if an error occurred
|
|
488
|
+
"""
|
|
489
|
+
decoded_submodel_id: str = decode_base_64(submodel_id)
|
|
490
|
+
url = f"{self.base_url}/submodels/{decoded_submodel_id}/submodel-elements"
|
|
491
|
+
|
|
492
|
+
try:
|
|
493
|
+
response = self._session.post(url, headers=HEADERS, json=submodel_element_data, timeout=self.time_out)
|
|
494
|
+
logger.debug(f"Call REST API url '{response.url}'")
|
|
495
|
+
|
|
496
|
+
if response.status_code != STATUS_CODE_201:
|
|
497
|
+
log_response_errors(response)
|
|
498
|
+
return None
|
|
499
|
+
|
|
500
|
+
except requests.exceptions.RequestException as e:
|
|
501
|
+
logger.error(f"Error call REST API: {e}")
|
|
502
|
+
return None
|
|
503
|
+
|
|
504
|
+
content = response.content.decode("utf-8")
|
|
505
|
+
return json.loads(content)
|
|
506
|
+
|
|
507
|
+
# endregion
|
|
508
|
+
|
|
509
|
+
# region client
|
|
448
510
|
|
|
449
511
|
def create_client_by_url(
|
|
450
512
|
base_url: str,
|
|
@@ -480,7 +542,6 @@ def create_client_by_url(
|
|
|
480
542
|
config_string = json.dumps(config_dict, indent=4)
|
|
481
543
|
return _create_client(config_string, password)
|
|
482
544
|
|
|
483
|
-
|
|
484
545
|
def create_client_by_config(config_file: Path, password: str = "") -> AasHttpClient | None:
|
|
485
546
|
"""Create a AAS HTTP client from the given parameters.
|
|
486
547
|
|
|
@@ -499,7 +560,6 @@ def create_client_by_config(config_file: Path, password: str = "") -> AasHttpCli
|
|
|
499
560
|
|
|
500
561
|
return _create_client(config_string, password)
|
|
501
562
|
|
|
502
|
-
|
|
503
563
|
def _create_client(config_string: str, password) -> AasHttpClient | None:
|
|
504
564
|
try:
|
|
505
565
|
connection_settings = AasHttpClient.model_validate_json(config_string)
|
|
@@ -525,7 +585,6 @@ def _create_client(config_string: str, password) -> AasHttpClient | None:
|
|
|
525
585
|
|
|
526
586
|
return client
|
|
527
587
|
|
|
528
|
-
|
|
529
588
|
def _connect_to_api(client: AasHttpClient) -> bool:
|
|
530
589
|
start_time = time.time()
|
|
531
590
|
logger.debug(f"Try to connect to REST API '{client.base_url}' for {client.connection_time_out} seconds")
|
|
@@ -544,3 +603,5 @@ def _connect_to_api(client: AasHttpClient) -> bool:
|
|
|
544
603
|
counter += 1
|
|
545
604
|
logger.warning(f"Retrying connection (attempt: {counter})")
|
|
546
605
|
time.sleep(1)
|
|
606
|
+
|
|
607
|
+
# endregion
|
|
@@ -7,41 +7,50 @@ import json
|
|
|
7
7
|
import basyx.aas.adapter.json
|
|
8
8
|
import basyx.aas.model
|
|
9
9
|
|
|
10
|
+
from basyx.aas import model
|
|
11
|
+
|
|
10
12
|
logger = logging.getLogger(__name__)
|
|
11
13
|
|
|
12
14
|
def start():
|
|
13
15
|
"""Start the demo process."""
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
# create a submodel element
|
|
17
|
+
sme_short_id: str = model_builder.create_unique_short_id("poc_sme")
|
|
18
|
+
sme = model_builder.create_base_submodel_element_Property(sme_short_id, model.datatypes.String, "Sample Value")
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
dotnet_sdk_wrapper.get_shells_by_id(aas_1.id)
|
|
20
|
+
# create a submodel
|
|
21
|
+
sm_short_id: str = model_builder.create_unique_short_id("poc_sm")
|
|
22
|
+
submodel = model_builder.create_base_submodel(sm_short_id)
|
|
23
|
+
# add submodel element to submodel
|
|
24
|
+
# submodel.submodel_element.add(sme)
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
# create an AAS
|
|
27
|
+
aas_short_id: str = model_builder.create_unique_short_id("poc_aas")
|
|
28
|
+
aas = model_builder.create_base_ass(aas_short_id)
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
# add submodel to AAS
|
|
31
|
+
model_builder.add_submodel_to_aas(aas, submodel)
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
java_sdk_wrapper.delete_shells_by_id(shell.id)
|
|
33
|
+
java_sdk_wrapper = _create_sdk_wrapper(Path("./aas_http_client/demo/java_server_config.json"))
|
|
34
|
+
# dotnet_sdk_wrapper = _create_sdk_wrapper(Path("./aas_http_client/demo/dotnet_server_config.json"))
|
|
34
35
|
|
|
35
|
-
java_sdk_wrapper.
|
|
36
|
+
for existing_shell in java_sdk_wrapper.get_shells():
|
|
37
|
+
logger.warning(f"Delete shell '{existing_shell.id}'")
|
|
38
|
+
java_sdk_wrapper.delete_shells_by_id(existing_shell.id)
|
|
36
39
|
|
|
40
|
+
for existing_submodel in java_sdk_wrapper.get_submodels():
|
|
41
|
+
logger.warning(f"Delete submodel '{existing_submodel.id}'")
|
|
42
|
+
java_sdk_wrapper.delete_submodels_by_id(existing_submodel.id)
|
|
37
43
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
client.post_shells(aas_dict)
|
|
41
|
-
|
|
42
|
-
shells = client.get_shells()
|
|
44
|
+
java_sdk_wrapper.post_shells(aas)
|
|
45
|
+
java_sdk_wrapper.post_submodels(submodel)
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
shell = java_sdk_wrapper.get_shells_by_id(aas.id)
|
|
48
|
+
submodel = java_sdk_wrapper.get_submodels_by_id(submodel.id)
|
|
49
|
+
|
|
50
|
+
java_sdk_wrapper.post_submodels_submodel_elements(submodel.id, sme)
|
|
51
|
+
|
|
52
|
+
submodel = java_sdk_wrapper.get_submodels_by_id(submodel.id)
|
|
53
|
+
|
|
45
54
|
|
|
46
55
|
def _create_shell() -> basyx.aas.model.AssetAdministrationShell:
|
|
47
56
|
# create an AAS
|
|
@@ -57,11 +66,11 @@ def _create_shell() -> basyx.aas.model.AssetAdministrationShell:
|
|
|
57
66
|
|
|
58
67
|
return aas
|
|
59
68
|
|
|
60
|
-
def _create_client() -> AasHttpClient:
|
|
69
|
+
def _create_client(config: Path) -> AasHttpClient:
|
|
61
70
|
"""Create client for java servers."""
|
|
62
71
|
|
|
63
72
|
try:
|
|
64
|
-
file =
|
|
73
|
+
file = config
|
|
65
74
|
client = create_client_by_config(file, password="")
|
|
66
75
|
except Exception as e:
|
|
67
76
|
logger.error(f"Failed to create client for {file}: {e}")
|
|
@@ -5,15 +5,8 @@ Provides some helper methods for easier work with basyx sdk data model
|
|
|
5
5
|
|
|
6
6
|
import uuid
|
|
7
7
|
|
|
8
|
-
from basyx.aas
|
|
9
|
-
|
|
10
|
-
AssetInformation,
|
|
11
|
-
AssetKind,
|
|
12
|
-
ModelReference,
|
|
13
|
-
MultiLanguageTextType,
|
|
14
|
-
Submodel,
|
|
15
|
-
)
|
|
16
|
-
|
|
8
|
+
from basyx.aas import model
|
|
9
|
+
from typing import Any
|
|
17
10
|
|
|
18
11
|
def create_unique_short_id(id_short: str) -> str:
|
|
19
12
|
"""Generate a unique identifier string by appending a UUID to the provided ID short.
|
|
@@ -23,8 +16,29 @@ def create_unique_short_id(id_short: str) -> str:
|
|
|
23
16
|
"""
|
|
24
17
|
return f"{id_short}_{str(uuid.uuid4()).replace('-', '_')}"
|
|
25
18
|
|
|
19
|
+
def create_base_submodel_element_Property(id_short: str, type: model.datatypes, value: Any, display_name: str = "", description: str = "") -> model.Property:
|
|
20
|
+
"""Create a basic Property Submodel Element.
|
|
21
|
+
"""
|
|
22
|
+
sme = model.Property(
|
|
23
|
+
id_short=id_short,
|
|
24
|
+
value_type=type,
|
|
25
|
+
value=value)
|
|
26
|
+
|
|
27
|
+
if not description:
|
|
28
|
+
description = f"This is the submodel element with ID short '{id_short}'"
|
|
29
|
+
|
|
30
|
+
description_text = {"en": f"{description}"}
|
|
31
|
+
sme.description = model.MultiLanguageTextType(description_text)
|
|
32
|
+
|
|
33
|
+
if not display_name:
|
|
34
|
+
display_name = "POC Submodel Element"
|
|
35
|
+
|
|
36
|
+
display_name_text = {"en": f"{display_name}"}
|
|
37
|
+
sme.display_name = model.MultiLanguageTextType(display_name_text)
|
|
38
|
+
|
|
39
|
+
return sme
|
|
26
40
|
|
|
27
|
-
def create_base_submodel(id_short: str, namespace: str = "basyx_python_aas_server", display_name: str = "", description: str = "") -> Submodel:
|
|
41
|
+
def create_base_submodel(id_short: str, namespace: str = "basyx_python_aas_server", display_name: str = "", description: str = "") -> model.Submodel:
|
|
28
42
|
"""Create a basic Submodel.
|
|
29
43
|
|
|
30
44
|
:param id_short: ID short of the Submodel
|
|
@@ -37,27 +51,27 @@ def create_base_submodel(id_short: str, namespace: str = "basyx_python_aas_serve
|
|
|
37
51
|
identifier = f"{namespace}/{id_short}"
|
|
38
52
|
else:
|
|
39
53
|
identifier = id_short
|
|
40
|
-
sm = Submodel(identifier)
|
|
54
|
+
sm = model.Submodel(identifier)
|
|
41
55
|
sm.id_short = id_short
|
|
42
56
|
|
|
43
57
|
if not description:
|
|
44
58
|
description = f"This is the submodel with ID short '{id_short}'"
|
|
45
59
|
|
|
46
60
|
description_text = {"en": f"{description}"}
|
|
47
|
-
sm.description = MultiLanguageTextType(description_text)
|
|
61
|
+
sm.description = model.MultiLanguageTextType(description_text)
|
|
48
62
|
|
|
49
63
|
if not display_name:
|
|
50
64
|
display_name = "POC AAS"
|
|
51
65
|
|
|
52
66
|
display_name_text = {"en": f"{display_name}"}
|
|
53
|
-
sm.display_name = MultiLanguageTextType(display_name_text)
|
|
67
|
+
sm.display_name = model.MultiLanguageTextType(display_name_text)
|
|
54
68
|
|
|
55
69
|
return sm
|
|
56
70
|
|
|
57
71
|
|
|
58
72
|
def create_base_ass(
|
|
59
73
|
id_short: str, namespace: str = "basyx_python_aas_server", display_name: str = "", description: str = ""
|
|
60
|
-
) -> AssetAdministrationShell:
|
|
74
|
+
) -> model.AssetAdministrationShell:
|
|
61
75
|
"""Create a basic AAS.
|
|
62
76
|
|
|
63
77
|
:param id_short: ID short of the AAS
|
|
@@ -68,35 +82,35 @@ def create_base_ass(
|
|
|
68
82
|
"""
|
|
69
83
|
asset_info = create_base_asset_information(id_short, namespace)
|
|
70
84
|
|
|
71
|
-
aas = AssetAdministrationShell(id_=asset_info.global_asset_id, asset_information=asset_info)
|
|
85
|
+
aas = model.AssetAdministrationShell(id_=asset_info.global_asset_id, asset_information=asset_info)
|
|
72
86
|
aas.id_short = id_short
|
|
73
87
|
|
|
74
88
|
if not description:
|
|
75
89
|
description = f"This is the asset administration shell with ID short '{id_short}'"
|
|
76
90
|
|
|
77
91
|
description_text = {"en": f"{description}"}
|
|
78
|
-
aas.description = MultiLanguageTextType(description_text)
|
|
92
|
+
aas.description = model.MultiLanguageTextType(description_text)
|
|
79
93
|
|
|
80
94
|
if not display_name:
|
|
81
95
|
display_name = "POC AAS"
|
|
82
96
|
|
|
83
97
|
display_name_text = {"en": f"{display_name}"}
|
|
84
|
-
aas.display_name = MultiLanguageTextType(display_name_text)
|
|
98
|
+
aas.display_name = model.MultiLanguageTextType(display_name_text)
|
|
85
99
|
|
|
86
100
|
return aas
|
|
87
101
|
|
|
88
102
|
|
|
89
|
-
def add_submodel_to_aas(aas: AssetAdministrationShell, submodel: Submodel) -> None:
|
|
103
|
+
def add_submodel_to_aas(aas: model.AssetAdministrationShell, submodel: model.Submodel) -> None:
|
|
90
104
|
"""Add a given Submodel correctly to a provided AssetAdministrationShell.
|
|
91
105
|
|
|
92
106
|
:param aas: provided AssetAdministrationShell to which the Submodel should be added
|
|
93
107
|
:param submodel: given Submodel to add
|
|
94
108
|
"""
|
|
95
109
|
# aas.submodel.add(submodel)
|
|
96
|
-
aas.submodel.add(ModelReference.from_referable(submodel))
|
|
110
|
+
aas.submodel.add(model.ModelReference.from_referable(submodel))
|
|
97
111
|
|
|
98
112
|
|
|
99
|
-
def create_base_asset_information(id_short: str, namespace: str = "basyx_python_aas_server") -> AssetInformation:
|
|
113
|
+
def create_base_asset_information(id_short: str, namespace: str = "basyx_python_aas_server") -> model.AssetInformation:
|
|
100
114
|
"""Return a basic AssetInformation instance.
|
|
101
115
|
|
|
102
116
|
:param id_short: short ID of the AssetInformation
|
|
@@ -107,13 +121,13 @@ def create_base_asset_information(id_short: str, namespace: str = "basyx_python_
|
|
|
107
121
|
identifier = f"{namespace}/{id_short}"
|
|
108
122
|
else:
|
|
109
123
|
identifier = id_short
|
|
110
|
-
return AssetInformation(AssetKind.INSTANCE, identifier)
|
|
124
|
+
return model.AssetInformation(model.AssetKind.INSTANCE, identifier)
|
|
111
125
|
|
|
112
126
|
|
|
113
|
-
def create_reference(id: str) -> ModelReference:
|
|
127
|
+
def create_reference(id: str) -> model.ModelReference:
|
|
114
128
|
"""Create a ModelReference.
|
|
115
129
|
|
|
116
130
|
:param id: ID of the Submodel to reference
|
|
117
131
|
:return: ModelReference instance
|
|
118
132
|
"""
|
|
119
|
-
return ModelReference.from_referable(Submodel(id))
|
|
133
|
+
return model.ModelReference.from_referable(model.Submodel(id))
|
|
@@ -7,24 +7,27 @@ from typing import Any
|
|
|
7
7
|
|
|
8
8
|
import basyx.aas.adapter.json
|
|
9
9
|
|
|
10
|
-
from basyx.aas
|
|
10
|
+
from basyx.aas import model
|
|
11
11
|
from aas_http_client.client import AasHttpClient, _create_client
|
|
12
12
|
logger = logging.getLogger(__name__)
|
|
13
13
|
|
|
14
14
|
class SdkWrapper():
|
|
15
15
|
"""Represents a wrapper for the BaSyx Python SDK to communicate with a REST API."""
|
|
16
|
-
_client: AasHttpClient = None
|
|
16
|
+
_client: AasHttpClient = None
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
# region shells
|
|
19
|
+
|
|
20
|
+
def post_shells(self, aas: model.AssetAdministrationShell) -> model.AssetAdministrationShell | None:
|
|
19
21
|
"""Post an Asset Administration Shell (AAS) to the REST API.
|
|
20
22
|
|
|
21
23
|
:param aas: Asset Administration Shell to post
|
|
22
24
|
:return: Response data as a dictionary or None if an error occurred
|
|
23
25
|
"""
|
|
24
26
|
aas_data = _to_dict(aas)
|
|
25
|
-
|
|
27
|
+
content: dict = self._client.post_shells(aas_data)
|
|
28
|
+
return _to_object(content)
|
|
26
29
|
|
|
27
|
-
def put_shells(self, identifier: str, aas: AssetAdministrationShell) -> bool:
|
|
30
|
+
def put_shells(self, identifier: str, aas: model.AssetAdministrationShell) -> bool:
|
|
28
31
|
"""Update an Asset Administration Shell (AAS) by its ID in the REST API.
|
|
29
32
|
|
|
30
33
|
:param identifier: Identifier of the AAS to update
|
|
@@ -34,7 +37,7 @@ class SdkWrapper():
|
|
|
34
37
|
aas_data = _to_dict(aas)
|
|
35
38
|
return self._client.put_shells(identifier, aas_data)
|
|
36
39
|
|
|
37
|
-
def put_shells_submodels_by_id(self, aas_id: str, submodel_id: str, submodel: Submodel) -> bool:
|
|
40
|
+
def put_shells_submodels_by_id(self, aas_id: str, submodel_id: str, submodel: model.Submodel) -> bool:
|
|
38
41
|
"""Update a submodel by its ID for a specific Asset Administration Shell (AAS).
|
|
39
42
|
|
|
40
43
|
:param aas_id: ID of the AAS to update the submodel for
|
|
@@ -44,7 +47,7 @@ class SdkWrapper():
|
|
|
44
47
|
sm_data = _to_dict(submodel)
|
|
45
48
|
return self._client.put_shells_submodels_by_id(aas_id, submodel_id, sm_data)
|
|
46
49
|
|
|
47
|
-
def get_shells(self) -> list[AssetAdministrationShell] | None:
|
|
50
|
+
def get_shells(self) -> list[model.AssetAdministrationShell] | None:
|
|
48
51
|
"""Get all Asset Administration Shells (AAS) from the REST API.
|
|
49
52
|
|
|
50
53
|
:return: AAS objects or None if an error occurred
|
|
@@ -59,7 +62,7 @@ class SdkWrapper():
|
|
|
59
62
|
logger.warning("No shells found on server.")
|
|
60
63
|
return []
|
|
61
64
|
|
|
62
|
-
aas_list: list[AssetAdministrationShell] = []
|
|
65
|
+
aas_list: list[model.AssetAdministrationShell] = []
|
|
63
66
|
|
|
64
67
|
for result in results:
|
|
65
68
|
if not isinstance(result, dict):
|
|
@@ -73,7 +76,7 @@ class SdkWrapper():
|
|
|
73
76
|
|
|
74
77
|
return aas_list
|
|
75
78
|
|
|
76
|
-
def get_shells_by_id(self, aas_id: str) -> AssetAdministrationShell | None:
|
|
79
|
+
def get_shells_by_id(self, aas_id: str) -> model.AssetAdministrationShell | None:
|
|
77
80
|
"""Get an Asset Administration Shell (AAS) by its ID from the REST API.
|
|
78
81
|
|
|
79
82
|
:param aas_id: ID of the AAS to retrieve
|
|
@@ -87,15 +90,15 @@ class SdkWrapper():
|
|
|
87
90
|
|
|
88
91
|
return _to_object(content)
|
|
89
92
|
|
|
90
|
-
def get_shells_reference_by_id(self, aas_id: str) -> Reference | None:
|
|
93
|
+
def get_shells_reference_by_id(self, aas_id: str) -> model.Reference | None:
|
|
91
94
|
#workaround because serialization not working
|
|
92
95
|
aas = self.get_shells_by_id(aas_id)
|
|
93
|
-
return ModelReference.from_referable(aas)
|
|
96
|
+
return model.ModelReference.from_referable(aas)
|
|
94
97
|
|
|
95
98
|
# content: dict = self._client.get_shells_reference_by_id(aas_id)
|
|
96
99
|
# return json.loads(content, cls=basyx.aas.adapter.json.AASFromJsonDecoder)
|
|
97
100
|
|
|
98
|
-
def get_shells_submodels_by_id(self, aas_id: str, submodel_id: str) -> Submodel | None:
|
|
101
|
+
def get_shells_submodels_by_id(self, aas_id: str, submodel_id: str) -> model.Submodel | None:
|
|
99
102
|
"""Get a submodel by its ID for a specific Asset Administration Shell (AAS).
|
|
100
103
|
|
|
101
104
|
:param aas_id: ID of the AAS to retrieve the submodel from
|
|
@@ -113,16 +116,21 @@ class SdkWrapper():
|
|
|
113
116
|
"""
|
|
114
117
|
return self._client.delete_shells_by_id(aas_id)
|
|
115
118
|
|
|
116
|
-
|
|
119
|
+
# endregion
|
|
120
|
+
|
|
121
|
+
# region submodels
|
|
122
|
+
|
|
123
|
+
def post_submodels(self, submodel: model.Submodel) -> model.Submodel | None:
|
|
117
124
|
"""Post a submodel to the REST API.
|
|
118
125
|
|
|
119
126
|
:param submodel: submodel data as a dictionary
|
|
120
127
|
:return: Response data as a dictionary or None if an error occurred
|
|
121
128
|
"""
|
|
122
129
|
sm_data = _to_dict(submodel)
|
|
123
|
-
|
|
130
|
+
content: dict = self._client.post_submodels(sm_data)
|
|
131
|
+
return _to_object(content)
|
|
124
132
|
|
|
125
|
-
def put_submodels_by_id(self, identifier: str, submodel: Submodel) -> bool:
|
|
133
|
+
def put_submodels_by_id(self, identifier: str, submodel: model.Submodel) -> bool:
|
|
126
134
|
"""Update a submodel by its ID in the REST API.
|
|
127
135
|
|
|
128
136
|
:param identifier: Identifier of the submodel to update
|
|
@@ -132,7 +140,7 @@ class SdkWrapper():
|
|
|
132
140
|
sm_data = _to_dict(submodel)
|
|
133
141
|
return self._client.put_submodels_by_id(identifier, sm_data)
|
|
134
142
|
|
|
135
|
-
def get_submodels(self) -> list[Submodel] | None:
|
|
143
|
+
def get_submodels(self) -> list[model.Submodel] | None:
|
|
136
144
|
"""Get all submodels from the REST API.
|
|
137
145
|
|
|
138
146
|
:return: Submodel objects or None if an error occurred
|
|
@@ -147,7 +155,7 @@ class SdkWrapper():
|
|
|
147
155
|
logger.warning("No submodels found on server.")
|
|
148
156
|
return []
|
|
149
157
|
|
|
150
|
-
submodels: list[Submodel] = []
|
|
158
|
+
submodels: list[model.Submodel] = []
|
|
151
159
|
|
|
152
160
|
for result in results:
|
|
153
161
|
if not isinstance(result, dict):
|
|
@@ -161,7 +169,7 @@ class SdkWrapper():
|
|
|
161
169
|
|
|
162
170
|
return submodels
|
|
163
171
|
|
|
164
|
-
def get_submodels_by_id(self, submodel_id: str) -> Submodel | None:
|
|
172
|
+
def get_submodels_by_id(self, submodel_id: str) -> model.Submodel | None:
|
|
165
173
|
"""Get a submodel by its ID from the REST API.
|
|
166
174
|
|
|
167
175
|
:param submodel_id: ID of the submodel to retrieve
|
|
@@ -175,7 +183,7 @@ class SdkWrapper():
|
|
|
175
183
|
|
|
176
184
|
return _to_object(content)
|
|
177
185
|
|
|
178
|
-
def patch_submodel_by_id(self, submodel_id: str, submodel: Submodel):
|
|
186
|
+
def patch_submodel_by_id(self, submodel_id: str, submodel: model.Submodel):
|
|
179
187
|
sm_data = _to_dict(submodel)
|
|
180
188
|
return self._client.patch_submodel_by_id(submodel_id, sm_data)
|
|
181
189
|
|
|
@@ -187,6 +195,52 @@ class SdkWrapper():
|
|
|
187
195
|
"""
|
|
188
196
|
return self._client.delete_submodels_by_id(submodel_id)
|
|
189
197
|
|
|
198
|
+
def get_submodels_submodel_elements(self, submodel_id: str, ) -> list[model.SubmodelElement] | None:
|
|
199
|
+
"""Returns all Submodel elements including their hierarchy.
|
|
200
|
+
!!! Serialization to model.SubmodelElement currently not possible
|
|
201
|
+
|
|
202
|
+
:param submodel_id: Encoded ID of the Submodel to retrieve elements from
|
|
203
|
+
:return: List of Submodel elements or None if an error occurred
|
|
204
|
+
"""
|
|
205
|
+
content = self._client.get_submodels_submodel_elements(submodel_id)
|
|
206
|
+
|
|
207
|
+
if not content:
|
|
208
|
+
return []
|
|
209
|
+
|
|
210
|
+
results: list = content.get("result", [])
|
|
211
|
+
if not results:
|
|
212
|
+
logger.warning("No submodels found on server.")
|
|
213
|
+
return []
|
|
214
|
+
|
|
215
|
+
submodel_elements: list[model.SubmodelElement] = []
|
|
216
|
+
|
|
217
|
+
for result in results:
|
|
218
|
+
if not isinstance(result, dict):
|
|
219
|
+
logger.error(f"Invalid submodel data: {result}")
|
|
220
|
+
return None
|
|
221
|
+
|
|
222
|
+
submodel_element = _to_object(result)
|
|
223
|
+
|
|
224
|
+
if submodel_element:
|
|
225
|
+
submodel_elements.append(submodel_element)
|
|
226
|
+
|
|
227
|
+
return submodel_elements
|
|
228
|
+
|
|
229
|
+
def post_submodels_submodel_elements(self, submodel_id: str, submodel_element: model.SubmodelElement) -> model.SubmodelElement | None:
|
|
230
|
+
"""Create a new submodel element.
|
|
231
|
+
!!! Serialization to model.SubmodelElements currently not possible
|
|
232
|
+
|
|
233
|
+
:param submodel_id: Encoded ID of the submodel to create elements for
|
|
234
|
+
:param submodel_element: Submodel element to create
|
|
235
|
+
:return: List of submodel element objects or None if an error occurred
|
|
236
|
+
"""
|
|
237
|
+
sme_data = _to_dict(submodel_element)
|
|
238
|
+
content: dict = self._client.post_submodels_submodel_elements(submodel_id, sme_data)
|
|
239
|
+
return _to_object(content)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# endregion
|
|
243
|
+
|
|
190
244
|
def _to_object(content: dict) -> Any | None:
|
|
191
245
|
try:
|
|
192
246
|
dict_string = json.dumps(content)
|
|
@@ -205,6 +259,8 @@ def _to_dict(object: Any) -> dict | None:
|
|
|
205
259
|
logger.error(f"In object: {object}")
|
|
206
260
|
return None
|
|
207
261
|
|
|
262
|
+
# region wrapper
|
|
263
|
+
|
|
208
264
|
def create_wrapper_by_url(
|
|
209
265
|
base_url: str,
|
|
210
266
|
username: str = "",
|
|
@@ -247,8 +303,6 @@ def create_wrapper_by_url(
|
|
|
247
303
|
wrapper._client = client
|
|
248
304
|
return wrapper
|
|
249
305
|
|
|
250
|
-
|
|
251
|
-
|
|
252
306
|
def create_wrapper_by_config(config_file: Path, password: str = "") -> SdkWrapper | None:
|
|
253
307
|
"""Create a wrapper for the BaSyx Python SDK from the given parameters.
|
|
254
308
|
|
|
@@ -271,4 +325,6 @@ def create_wrapper_by_config(config_file: Path, password: str = "") -> SdkWrappe
|
|
|
271
325
|
return None
|
|
272
326
|
|
|
273
327
|
wrapper._client = client
|
|
274
|
-
return wrapper
|
|
328
|
+
return wrapper
|
|
329
|
+
|
|
330
|
+
# endregion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aas-http-client
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Generic python HTTP client for communication with various types of AAS servers
|
|
5
5
|
Author-email: Daniel Klein <daniel.klein@em.ag>
|
|
6
6
|
License: # :em engineering methods AG Software License
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
aas_http_client/__init__.py,sha256=cAr1mQzWp0G0LKtkAOYzc9t95OY3jM3Aj4bKnxx0Dso,901
|
|
2
|
+
aas_http_client/client.py,sha256=8pgEd3xV8BDBhqQvYfdLGOVEOJI5-ZfzXhjRe5OZZ_0,22916
|
|
3
|
+
aas_http_client/core/encoder.py,sha256=FS7P0FPakzFsGz70eRFDHQZFA_2nlKLlWIxavtnFrPg,660
|
|
4
|
+
aas_http_client/core/version_check.py,sha256=721Zs3xSRrJTYZtAxkaUWg9LLKtpU7oFM62DzQHZdE4,705
|
|
5
|
+
aas_http_client/demo/demo_process.py,sha256=kW1f8D6cjlzRS2Ald_LYM_Qk7lc_XxEV53asjaJDhKw,3188
|
|
6
|
+
aas_http_client/demo/logging_handler.py,sha256=VJtZ4u3x_LhYZQtfNck7FuXhGFZm7gid0uDhvf9GjJ8,5596
|
|
7
|
+
aas_http_client/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
aas_http_client/utilities/model_builder.py,sha256=mL06SX208dMJHpiB-ol51JA9Bm3czoI8ELYTfismCq8,4633
|
|
9
|
+
aas_http_client/wrapper/sdk_wrapper.py,sha256=G0bqZB2AL4-E7FhQF4jDJtsRREq55knj1RmYNpLHxzI,12368
|
|
10
|
+
aas_http_client-0.2.4.dist-info/licenses/LICENSE,sha256=ayt4HY-Tjoe1Uvj47j6UdNq8mEufKcKFangurChIHxQ,5990
|
|
11
|
+
aas_http_client-0.2.4.dist-info/METADATA,sha256=D8d3xu5re1-uIXnlSfZUCjTptwwtBPbtf4kJ9AuGA4I,10301
|
|
12
|
+
aas_http_client-0.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
13
|
+
aas_http_client-0.2.4.dist-info/top_level.txt,sha256=vzvoz2vjeTLwpuz-Y-eEfoQ7T3byoaKshVlFMFH5NaM,16
|
|
14
|
+
aas_http_client-0.2.4.dist-info/RECORD,,
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
aas_http_client/__init__.py,sha256=cAr1mQzWp0G0LKtkAOYzc9t95OY3jM3Aj4bKnxx0Dso,901
|
|
2
|
-
aas_http_client/client.py,sha256=6d3g9VNhex1JrZwIXtBTopSTw3bsf5NZBSWG5mHYuQg,20705
|
|
3
|
-
aas_http_client/core/encoder.py,sha256=FS7P0FPakzFsGz70eRFDHQZFA_2nlKLlWIxavtnFrPg,660
|
|
4
|
-
aas_http_client/core/version_check.py,sha256=721Zs3xSRrJTYZtAxkaUWg9LLKtpU7oFM62DzQHZdE4,705
|
|
5
|
-
aas_http_client/demo/demo_process.py,sha256=QfneAU2KXHUt90jEsOEx1VA4xgXW7PHsLsVVXI5BOgg,2602
|
|
6
|
-
aas_http_client/demo/logging_handler.py,sha256=VJtZ4u3x_LhYZQtfNck7FuXhGFZm7gid0uDhvf9GjJ8,5596
|
|
7
|
-
aas_http_client/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
aas_http_client/utilities/model_builder.py,sha256=bL4hy3uHh1Y_uL6KmLIfo9ORiUqWNlyToJrAt8G1rpw,3877
|
|
9
|
-
aas_http_client/wrapper/sdk_wrapper.py,sha256=-0bKx5oP5jYosVAnuRlajMgJA1PJbOLLWm1j0fh1y_k,10334
|
|
10
|
-
aas_http_client-0.2.3.dist-info/licenses/LICENSE,sha256=ayt4HY-Tjoe1Uvj47j6UdNq8mEufKcKFangurChIHxQ,5990
|
|
11
|
-
aas_http_client-0.2.3.dist-info/METADATA,sha256=9sTQ4BxzU1ZOFMG2UVjAIb_sGWD1grxZPKt4-VSPzlk,10301
|
|
12
|
-
aas_http_client-0.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
13
|
-
aas_http_client-0.2.3.dist-info/top_level.txt,sha256=vzvoz2vjeTLwpuz-Y-eEfoQ7T3byoaKshVlFMFH5NaM,16
|
|
14
|
-
aas_http_client-0.2.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|