MTPPy2.0 0.1.5__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.
Files changed (214) hide show
  1. examples/__init__.py +0 -0
  2. examples/minimal+pid.py +82 -0
  3. examples/minimal.py +32 -0
  4. examples/minimal_recipe.py +117 -0
  5. examples/pea_alarm_base.py +47 -0
  6. examples/pea_minimal.py +258 -0
  7. mtppy/__init__.py +1 -0
  8. mtppy/part1/__init__.py +4 -0
  9. mtppy/part1/empty_folder_test.py +7 -0
  10. mtppy/part3/__init__.py +4 -0
  11. mtppy/part3/data_assembly_set/__init__.py +4 -0
  12. mtppy/part3/data_assembly_set/active_elements/__init__.py +4 -0
  13. mtppy/part3/data_assembly_set/active_elements/active_element.py +22 -0
  14. mtppy/part3/data_assembly_set/active_elements/drives/__init__.py +4 -0
  15. mtppy/part3/data_assembly_set/active_elements/drives/ana_drv.py +446 -0
  16. mtppy/part3/data_assembly_set/active_elements/drives/ana_drv_test.py +567 -0
  17. mtppy/part3/data_assembly_set/active_elements/drives/bin_drv.py +365 -0
  18. mtppy/part3/data_assembly_set/active_elements/drives/bin_drv_test.py +503 -0
  19. mtppy/part3/data_assembly_set/active_elements/drives/mon_ana_drv.py +469 -0
  20. mtppy/part3/data_assembly_set/active_elements/drives/mon_ana_drv_test.py +418 -0
  21. mtppy/part3/data_assembly_set/active_elements/drives/mon_bin_drv.py +295 -0
  22. mtppy/part3/data_assembly_set/active_elements/drives/mon_bin_drv_test.py +265 -0
  23. mtppy/part3/data_assembly_set/active_elements/pid/__init__.py +4 -0
  24. mtppy/part3/data_assembly_set/active_elements/pid/pid_ctrl.py +333 -0
  25. mtppy/part3/data_assembly_set/active_elements/pid/pid_ctrl_test.py +156 -0
  26. mtppy/part3/data_assembly_set/active_elements/valves/__init__.py +4 -0
  27. mtppy/part3/data_assembly_set/active_elements/valves/ana_vlv.py +402 -0
  28. mtppy/part3/data_assembly_set/active_elements/valves/ana_vlv_test.py +732 -0
  29. mtppy/part3/data_assembly_set/active_elements/valves/bin_vlv.py +279 -0
  30. mtppy/part3/data_assembly_set/active_elements/valves/bin_vlv_test.py +585 -0
  31. mtppy/part3/data_assembly_set/active_elements/valves/mon_ana_vlv.py +402 -0
  32. mtppy/part3/data_assembly_set/active_elements/valves/mon_ana_vlv_test.py +270 -0
  33. mtppy/part3/data_assembly_set/active_elements/valves/mon_bin_vlv.py +286 -0
  34. mtppy/part3/data_assembly_set/active_elements/valves/mon_bin_vlv_test.py +224 -0
  35. mtppy/part3/data_assembly_set/base_functions/__init__.py +4 -0
  36. mtppy/part3/data_assembly_set/base_functions/operation_mode.py +252 -0
  37. mtppy/part3/data_assembly_set/base_functions/operation_mode_test.py +260 -0
  38. mtppy/part3/data_assembly_set/base_functions/oslevel.py +35 -0
  39. mtppy/part3/data_assembly_set/base_functions/source_mode.py +189 -0
  40. mtppy/part3/data_assembly_set/base_functions/source_mode_test.py +112 -0
  41. mtppy/part3/data_assembly_set/base_functions/wqc.py +75 -0
  42. mtppy/part3/data_assembly_set/base_functions/wqc_test.py +86 -0
  43. mtppy/part3/data_assembly_set/data_assembly.py +65 -0
  44. mtppy/part3/data_assembly_set/diagnostic_elements/__init__.py +4 -0
  45. mtppy/part3/data_assembly_set/diagnostic_elements/diagnostic_element.py +19 -0
  46. mtppy/part3/data_assembly_set/indicator_elements/__init__.py +4 -0
  47. mtppy/part3/data_assembly_set/indicator_elements/indicator_element.py +22 -0
  48. mtppy/part3/data_assembly_set/indicator_elements/views/__init__.py +4 -0
  49. mtppy/part3/data_assembly_set/indicator_elements/views/ana_view.py +68 -0
  50. mtppy/part3/data_assembly_set/indicator_elements/views/bin_view.py +73 -0
  51. mtppy/part3/data_assembly_set/indicator_elements/views/dint_view.py +76 -0
  52. mtppy/part3/data_assembly_set/indicator_elements/views/string_view.py +55 -0
  53. mtppy/part3/data_assembly_set/operation_elements/__init__.py +4 -0
  54. mtppy/part3/data_assembly_set/operation_elements/operation_element.py +19 -0
  55. mtppy/part3/data_assembly_set/pea_elements/__init__.py +4 -0
  56. mtppy/part3/data_assembly_set/pea_elements/pea_element.py +28 -0
  57. mtppy/part3/data_assembly_set/pea_elements/pea_information_label/__init__.py +4 -0
  58. mtppy/part3/data_assembly_set/pea_elements/pea_information_label/pea_information_label.py +231 -0
  59. mtppy/part3/data_assembly_set/pea_elements/web_server_url_info/__init__.py +4 -0
  60. mtppy/part3/data_assembly_set/pea_elements/web_server_url_info/web_server_url_info.py +42 -0
  61. mtppy/part3/definitions/__init__.py +4 -0
  62. mtppy/part3/definitions/mtp_access.py +15 -0
  63. mtppy/part4/__init__.py +4 -0
  64. mtppy/part4/automation_services/__init__.py +4 -0
  65. mtppy/part4/automation_services/base_functions/__init__.py +4 -0
  66. mtppy/part4/automation_services/base_functions/service_operation_mode.py +368 -0
  67. mtppy/part4/automation_services/base_functions/service_operation_mode_test.py +242 -0
  68. mtppy/part4/automation_services/base_functions/service_operator_interaction.py +62 -0
  69. mtppy/part4/automation_services/base_functions/service_source_mode.py +138 -0
  70. mtppy/part4/automation_services/base_functions/service_source_mode_test.py +179 -0
  71. mtppy/part4/automation_services/helpers/__init__.py +4 -0
  72. mtppy/part4/automation_services/helpers/command_en_control.py +330 -0
  73. mtppy/part4/automation_services/helpers/command_en_control_test.py +302 -0
  74. mtppy/part4/automation_services/helpers/state_machine.py +167 -0
  75. mtppy/part4/automation_services/helpers/state_machine_test.py +294 -0
  76. mtppy/part4/automation_services/helpers/thread_control.py +39 -0
  77. mtppy/part4/automation_services/helpers/thread_control_test.py +80 -0
  78. mtppy/part4/automation_services/procedure.py +111 -0
  79. mtppy/part4/automation_services/procedure_test.py +185 -0
  80. mtppy/part4/automation_services/service.py +463 -0
  81. mtppy/part4/automation_services/service_elements/__init__.py +4 -0
  82. mtppy/part4/automation_services/service_elements/parameter_elements/__init__.py +4 -0
  83. mtppy/part4/automation_services/service_elements/parameter_elements/ana_serv_param.py +108 -0
  84. mtppy/part4/automation_services/service_elements/parameter_elements/ana_serv_param_test.py +59 -0
  85. mtppy/part4/automation_services/service_elements/parameter_elements/bin_serv_param.py +70 -0
  86. mtppy/part4/automation_services/service_elements/parameter_elements/bin_serv_param_test.py +39 -0
  87. mtppy/part4/automation_services/service_elements/parameter_elements/common_serv_param.py +111 -0
  88. mtppy/part4/automation_services/service_elements/parameter_elements/dint_serv_param.py +77 -0
  89. mtppy/part4/automation_services/service_elements/parameter_elements/dint_serv_param_test.py +58 -0
  90. mtppy/part4/automation_services/service_elements/parameter_elements/parameter_element.py +175 -0
  91. mtppy/part4/automation_services/service_elements/parameter_elements/parameter_element_test.py +246 -0
  92. mtppy/part4/automation_services/service_elements/parameter_elements/string_serv_param.py +48 -0
  93. mtppy/part4/automation_services/service_elements/parameter_elements/string_serv_param_test.py +37 -0
  94. mtppy/part4/automation_services/service_elements/procedure_health_view.py +36 -0
  95. mtppy/part4/automation_services/service_elements/service_control.py +473 -0
  96. mtppy/part4/automation_services/service_elements/service_control_test.py +150 -0
  97. mtppy/part4/automation_services/service_elements/service_element.py +20 -0
  98. mtppy/part4/automation_services/service_test.py +407 -0
  99. mtppy/part4/definitions/__init__.py +4 -0
  100. mtppy/part4/definitions/command_codes.py +58 -0
  101. mtppy/part4/definitions/command_codes_test.py +44 -0
  102. mtppy/part4/definitions/state_codes.py +65 -0
  103. mtppy/part4/definitions/state_codes_test.py +44 -0
  104. mtppy/part4/process_values/__init__.py +4 -0
  105. mtppy/part4/process_values/base_functions/__init__.py +4 -0
  106. mtppy/part4/process_values/base_functions/vqc.py +48 -0
  107. mtppy/part4/process_values/input_elements/__init__.py +4 -0
  108. mtppy/part4/process_values/input_elements/ana_process_value_in.py +160 -0
  109. mtppy/part4/process_values/input_elements/bin_process_value_in.py +83 -0
  110. mtppy/part4/process_values/input_elements/dint_process_value_in.py +159 -0
  111. mtppy/part4/process_values/input_elements/input_element.py +40 -0
  112. mtppy/part4/process_values/input_elements/string_process_value_in.py +45 -0
  113. mtppy/part5/__init__.py +4 -0
  114. mtppy/part5/communication_object.py +99 -0
  115. mtppy/part5/communication_object_test.py +59 -0
  116. mtppy/part5/definitions/__init__.py +4 -0
  117. mtppy/part5/definitions/iec61131_data_types.py +31 -0
  118. mtppy/part5/definitions/iec61131_data_types_test.py +82 -0
  119. mtppy/part5/definitions/opcua_data_types.py +36 -0
  120. mtppy/part5/definitions/opcua_data_types_test.py +90 -0
  121. mtppy/part5/definitions/w3c_xml_data_types.py +177 -0
  122. mtppy/part5/definitions/w3c_xml_data_types_test.py +143 -0
  123. mtppy/part5/server_assembly_set/__init__.py +5 -0
  124. mtppy/part6/__init__.py +4 -0
  125. mtppy/part6/alarm_set/__init__.py +4 -0
  126. mtppy/part6/alarm_set/alarm.py +132 -0
  127. mtppy/part6/alarm_set/alarm_test.py +265 -0
  128. mtppy/pea/__init__.py +19 -0
  129. mtppy/pea/data_assembly_factory.py +124 -0
  130. mtppy/pea/data_assembly_factory_test.py +229 -0
  131. mtppy/pea/mtp_generator/__init__.py +4 -0
  132. mtppy/pea/mtp_generator/mtp_generator.py +1183 -0
  133. mtppy/pea/mtp_generator/mtp_generator_test.py +518 -0
  134. mtppy/pea/pea.py +139 -0
  135. mtppy/pea/pea_opcua_server/__init__.py +4 -0
  136. mtppy/pea/pea_opcua_server/marshalling.py +60 -0
  137. mtppy/pea/pea_opcua_server/opcua_options_provider/__init__.py +4 -0
  138. mtppy/pea/pea_opcua_server/opcua_options_provider/instances/basic_opcua_options_provider.py +50 -0
  139. mtppy/pea/pea_opcua_server/opcua_options_provider/opcua_options_provider.py +103 -0
  140. mtppy/pea/pea_opcua_server/pea_opcua_server.py +492 -0
  141. mtppy/pea/pea_opcua_server/subscription_list.py +55 -0
  142. mtppy/pea/pea_test.py +59 -0
  143. mtppy/pea/rmtp_pea.py +155 -0
  144. mtppy/pea/rmtp_pea_test.py +27 -0
  145. mtppy/pea/service_factory.py +178 -0
  146. mtppy/pea/service_factory_test.py +156 -0
  147. mtppy/pea/user_logic/__init__.py +4 -0
  148. mtppy/pea/user_logic/user_logic_pea.py +72 -0
  149. mtppy/pea/user_logic/user_logic_registry.py +106 -0
  150. mtppy/pea/user_logic/user_logic_registry_test.py +167 -0
  151. mtppy/pea/user_logic/user_logic_service.py +228 -0
  152. mtppy/pea/user_logic/user_logic_service_test.py +289 -0
  153. mtppy/utils/__init__.py +4 -0
  154. mtppy/utils/data_assembly_dict.py +61 -0
  155. mtppy/utils/data_assembly_dict_test.py +107 -0
  156. mtppy/utils/data_item.py +446 -0
  157. mtppy/utils/data_item_com_test.py +82 -0
  158. mtppy/utils/data_item_test.py +325 -0
  159. mtppy/utils/logging.py +23 -0
  160. mtppy/utils/logging_test.py +26 -0
  161. mtppy/utils/mtp_file_handling/__init__.py +4 -0
  162. mtppy/utils/mtp_file_handling/extract_manifest_from_mtp_file.py +22 -0
  163. mtppy/utils/mtp_file_handling/extract_mtp_file.py +22 -0
  164. mtppy/utils/mtp_file_handling/is_valid_mtp.py +22 -0
  165. mtppy/utils/mtp_file_handling/is_valid_path_for_manifest.py +15 -0
  166. mtppy/utils/mtp_file_handling/is_valid_path_to_manifest.py +17 -0
  167. mtppy/utils/mtp_file_handling/is_valid_path_to_mtp.py +17 -0
  168. mtppy/utils/mtp_file_handling/load_manifest_file.py +24 -0
  169. mtppy/utils/mtp_file_handling/mtp_reader/__init__.py +4 -0
  170. mtppy/utils/mtp_file_handling/mtp_reader/mtp_reader.py +103 -0
  171. mtppy/utils/mtp_file_handling/mtp_reader/mtp_reader_test.py +96 -0
  172. mtppy/utils/mtp_file_handling/mtp_reader/mtp_xml.py +226 -0
  173. mtppy/utils/mtp_file_handling/mtp_reader/mtp_xml_test.py +108 -0
  174. mtppy/utils/mtp_file_handling/mtp_writer/__init__.py +4 -0
  175. mtppy/utils/mtp_file_handling/mtp_writer/mtp_writer.py +77 -0
  176. mtppy/utils/mtp_file_handling/mtp_writer/ressources/get_content_types.py +10 -0
  177. mtppy/utils/mtp_file_handling/mtp_writer/ressources/get_rels.py +11 -0
  178. mtppy/utils/mtp_file_handling/mtp_writer/test_mtp_writer.py +25 -0
  179. mtppy/utils/mtp_file_handling/write_manifest_file.py +29 -0
  180. mtppy/utils/mtp_file_handling/write_manifest_file_test.py +22 -0
  181. mtppy/utils/mtp_file_handling/write_mtp_file.py +43 -0
  182. mtppy/utils/mtp_file_handling/write_mtp_file_test.py +22 -0
  183. mtppy/utils/testing.py +31 -0
  184. mtppy2_0-0.1.5.dist-info/METADATA +75 -0
  185. mtppy2_0-0.1.5.dist-info/RECORD +214 -0
  186. mtppy2_0-0.1.5.dist-info/WHEEL +5 -0
  187. mtppy2_0-0.1.5.dist-info/entry_points.txt +3 -0
  188. mtppy2_0-0.1.5.dist-info/licenses/LICENSE +21 -0
  189. mtppy2_0-0.1.5.dist-info/top_level.txt +4 -0
  190. tools/__init__.py +0 -0
  191. tools/create_bugreport.py +150 -0
  192. tools/inspect_mtp.py +110 -0
  193. utils/__init__.py +1 -0
  194. utils/file_handling/__init__.py +4 -0
  195. utils/file_handling/cleanup_folder.py +9 -0
  196. utils/file_handling/get_utc_foldername_with_ms.py +15 -0
  197. utils/file_handling/get_work_dir.py +9 -0
  198. utils/file_handling/is_valid_path_for_json.py +11 -0
  199. utils/file_handling/is_valid_path_to_json.py +17 -0
  200. utils/file_handling/load_json_file.py +18 -0
  201. utils/file_handling/read_file_from_file_archive.py +43 -0
  202. utils/file_handling/read_file_string.py +10 -0
  203. utils/file_handling/validate_json_data.py +28 -0
  204. utils/file_handling/write_json_file.py +23 -0
  205. utils/get_uuid.py +18 -0
  206. utils/get_uuid_test.py +17 -0
  207. utils/logging.py +100 -0
  208. utils/logging_test.py +67 -0
  209. utils/opcua/check_node.py +79 -0
  210. utils/resolve_unit/resolve_unit.py +11 -0
  211. utils/resolve_unit/unit_lib.py +2101 -0
  212. utils/resolve_unit/unit_lib_test.py +36 -0
  213. utils/type_conversion.py +236 -0
  214. utils/type_conversion_test.py +114 -0
@@ -0,0 +1,1183 @@
1
+ """Generate an MTP file from internal data structures."""
2
+
3
+ __copyright__ = (
4
+ "Copyright (c) 2026 Dresden University of Technology, Process-to-Order Group"
5
+ )
6
+ __license__ = "MIT"
7
+
8
+ from pathlib import Path
9
+
10
+ from opcua.ua import StringNodeId
11
+
12
+ from mtppy.utils.mtp_file_handling.mtp_writer.mtp_writer import MtpWriter
13
+ from mtppy.pea.pea import PEA
14
+ from mtppy.pea.pea_opcua_server.pea_opcua_server import PeaOPCUAServer
15
+ import xml.etree.ElementTree as ET
16
+
17
+ from mtppy.part3.data_assembly_set.data_assembly import DataAssembly
18
+ from mtppy.part4.automation_services.procedure import Procedure
19
+ from mtppy.part4.automation_services.service import Service
20
+ from mtppy.part6.alarm_set.alarm import Alarm
21
+ from mtppy.utils.data_item import DataItem
22
+ from utils.get_uuid import get_uuid
23
+
24
+
25
+ class MTPGenerator:
26
+ def __init__(self):
27
+ """
28
+ Represents an MTP generator.
29
+ """
30
+ self._template_path = None
31
+ self._tree = None
32
+ self._root = None
33
+
34
+ self._mtp_writer = MtpWriter()
35
+
36
+ # first layer: instance hierarchy MTP and instance hierarchy service
37
+ self._instance_hierarchy_module_type_package = None
38
+ self._instance_hierarchy_data_assemblies = None
39
+ self._instance_hierarchy_server_assemblies = None
40
+ self._instance_hierarchy_pictures = None
41
+ self._instance_hierarchy_process_values = None
42
+ self._instance_hierarchy_services = None
43
+ self._instance_hierarchy_texts = None
44
+ self._instance_hierarchy_alarms = None
45
+
46
+ self._server_assembly_reference = None
47
+ self._namespace_of_data_items = None
48
+ self._data_assembly_ref_ids: dict[int, str] = {}
49
+ self._alarm_trigger_ids: dict[int, str] = {}
50
+ self._serialized_data_items: set[int] = set()
51
+ self._alarm_group_elements: dict[int, ET.Element] = {}
52
+
53
+ def init(self):
54
+
55
+ # path of a manifest template containing general infos
56
+ base_dir = Path(__file__).parent
57
+ manifest_template_path = base_dir.joinpath("ressources/manifest_template.xml")
58
+ self._template_path = manifest_template_path
59
+
60
+ # empty prefix = Standard-Namespace
61
+ ET.register_namespace("", "http://www.dke.de/CAEX")
62
+ self._tree = ET.parse(self._template_path)
63
+ self._root = self._tree.getroot()
64
+
65
+ # first layer: instance hierarchy MTP and instance hierarchy service
66
+ self._instance_hierarchy_module_type_package = None
67
+ self._instance_hierarchy_data_assemblies = None
68
+ self._instance_hierarchy_server_assemblies = None
69
+ self._instance_hierarchy_pictures = None
70
+ self._instance_hierarchy_process_values = None
71
+ self._instance_hierarchy_services = None
72
+ self._instance_hierarchy_texts = None
73
+ self._instance_hierarchy_alarms = None
74
+
75
+ self._server_assembly_reference = None
76
+ self._namespace_of_data_items = None
77
+ self._data_assembly_ref_ids = {}
78
+ self._alarm_trigger_ids = {}
79
+ self._serialized_data_items = set()
80
+ self._alarm_group_elements = {}
81
+
82
+ self.__init_instance_hierarchies()
83
+
84
+ return True
85
+
86
+ def generate(
87
+ self,
88
+ pea: PEA,
89
+ source_document_information: None | dict = None,
90
+ out_path: str | None = None,
91
+ ):
92
+ self.init()
93
+
94
+ if source_document_information is not None:
95
+ self.__change_source_document_information(source_document_information)
96
+
97
+ self.__build_module_type_package_instance_hierarchy(
98
+ "0.0.1", "MTPPy2.0-PEA", pea.pea_information_label
99
+ )
100
+ opcua_server = pea.pea_opcua_server
101
+ self.__init_server_assemblies_instance_hierarchy(opcua_server)
102
+
103
+ for alarm in pea.alarms.values():
104
+ alarm.validate()
105
+ self._alarm_trigger_ids.setdefault(id(alarm.trigger), get_uuid())
106
+
107
+ for data_assembly in pea.data_assemblies.values():
108
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
109
+ data_assembly
110
+ )
111
+
112
+ for service in pea.service_set.values():
113
+ self.__add_service_to_instance_hierarchy_services(service)
114
+
115
+ for process_value_in in pea.process_value_ins.values():
116
+ process_value_in_ref = (
117
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
118
+ process_value_in
119
+ )
120
+ )
121
+ self.__add_process_value_in_to_instance_hierarchy_process_values(
122
+ process_value_in.tag_name, process_value_in_ref
123
+ )
124
+
125
+ for process_value_out in pea.process_value_outs.values():
126
+ process_value_out_ref = (
127
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
128
+ process_value_out
129
+ )
130
+ )
131
+ self.__add_process_value_out_to_instance_hierarchy_process_values(
132
+ process_value_out.tag_name, process_value_out_ref
133
+ )
134
+
135
+ for alarm in pea.alarms.values():
136
+ self.__add_alarm_to_instance_hierarchy_alarms(alarm)
137
+
138
+ # Export result
139
+ mtp_content_str = ET.tostring(self._root, encoding="utf-8")
140
+ self._mtp_writer.write_mtp(
141
+ mtp_content_str, out_path=out_path, mtp_name=f"MyPrettyMTP-{get_uuid()}"
142
+ )
143
+
144
+ def __init_instance_hierarchies(self):
145
+ self._instance_hierarchy_module_type_package = self.__init_instance_hierarchy(
146
+ "ModuleTypePackage"
147
+ )
148
+ self._instance_hierarchy_data_assemblies = self.__init_instance_hierarchy(
149
+ "DataAssemblies"
150
+ )
151
+ self._instance_hierarchy_server_assemblies = self.__init_instance_hierarchy(
152
+ "ServerAssemblies"
153
+ )
154
+ self._instance_hierarchy_pictures = self.__init_instance_hierarchy("Pictures")
155
+ self._instance_hierarchy_process_values = self.__init_instance_hierarchy(
156
+ "ProcessValues"
157
+ )
158
+ self._instance_hierarchy_services = self.__init_instance_hierarchy("Services")
159
+ self._instance_hierarchy_texts = self.__init_instance_hierarchy("Texts")
160
+ self._instance_hierarchy_alarms = self.__init_instance_hierarchy("Alarms")
161
+
162
+ def __init_instance_hierarchy(self, name: str):
163
+ instance_hierarchy = ET.SubElement(self._root, "InstanceHierarchy")
164
+ instance_hierarchy.set("Name", name)
165
+ instance_hierarchy.set("ID", get_uuid())
166
+ return instance_hierarchy
167
+
168
+ def __change_source_document_information(self, source_document_information: dict):
169
+ source_document_information_root = self._root.find("SourceDocumentInformation")
170
+ if source_document_information_root is not None:
171
+ for (
172
+ source_document_information_element
173
+ ) in source_document_information_root.findall("./"):
174
+ if source_document_information_element.tag in list(
175
+ source_document_information.keys()
176
+ ):
177
+ source_document_information_element.text = (
178
+ source_document_information[
179
+ source_document_information_element.tag
180
+ ]
181
+ )
182
+ else:
183
+ raise KeyError(
184
+ "Key of SourceDocumentInformation dict is not correct"
185
+ )
186
+
187
+ def __build_module_type_package_instance_hierarchy(
188
+ self, version: str, pea_name: str, pea_information_label: DataAssembly
189
+ ):
190
+ """Add internal element module type package to instance hierarchy mtp.
191
+
192
+ Args:
193
+ version: Version of mtp
194
+ pea_name: Name of pea
195
+ pea_information_label: PEA information label
196
+ """
197
+
198
+ # create InternalElement
199
+ module_type_package = ET.Element(
200
+ "InternalElement",
201
+ {
202
+ "Name": pea_name,
203
+ "ID": get_uuid(),
204
+ "RefBaseSystemUnitPath": "MTPSUCLib/ModuleTypePackage",
205
+ },
206
+ )
207
+ # add direct attributes to mtp internal element
208
+ mtp_version = ET.SubElement(module_type_package, "Attribute")
209
+ mtp_version.set("Name", "Version")
210
+ mtp_version.set("AttributeDataType", "xs:string")
211
+ mtp_version.set(
212
+ "RefAttributeType",
213
+ "MTPATLib/SemanticVersionAttributeType/ModuleTypePackageRevisionTyp",
214
+ )
215
+ mtp_version_value = ET.SubElement(mtp_version, "Value")
216
+ mtp_version_value.text = str(version)
217
+
218
+ mtp_device_revision = ET.SubElement(module_type_package, "Attribute")
219
+ mtp_device_revision.set("Name", "DeviceRevision")
220
+ mtp_device_revision.set("AttributeDataType", "xs:string")
221
+ mtp_device_revision.set(
222
+ "RefAttributeType",
223
+ "MTPATLib/SemanticVersionAttributeType/DeviceRevisionType",
224
+ )
225
+ mtp_device_revision_value = ET.SubElement(mtp_device_revision, "Value")
226
+ mtp_device_revision_value.text = str(version)
227
+
228
+ mtp_manufacturer_uri = ET.SubElement(module_type_package, "Attribute")
229
+ mtp_manufacturer_uri.set("Name", "ManufacturerUri")
230
+ mtp_manufacturer_uri.set("AttributeDataType", "xs:string")
231
+ mtp_manufacturer_uri_value = ET.SubElement(mtp_manufacturer_uri, "Value")
232
+ mtp_manufacturer_uri_value.text = "http://www.tu-dresden.de/P2O"
233
+
234
+ mtp_product_code = ET.SubElement(module_type_package, "Attribute")
235
+ mtp_product_code.set("Name", "ProductCode")
236
+ mtp_product_code.set("AttributeDataType", "xs:string")
237
+
238
+ mtp_pea_information = ET.SubElement(module_type_package, "Attribute")
239
+ mtp_pea_information.set("Name", "PeaInformation")
240
+ mtp_pea_information.set("AttributeDataType", "xs:string")
241
+ if pea_information_label is not None:
242
+ mtp_pea_information.set(
243
+ "RefAttributeType", "MTPATLib/IDReferenceType/IDLinkAttributeType"
244
+ )
245
+ ref_id = self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
246
+ pea_information_label
247
+ )
248
+ mtp_pea_information_value = ET.SubElement(mtp_pea_information, "Value")
249
+ mtp_pea_information_value.text = ref_id
250
+
251
+ mtp_web_server_url = ET.SubElement(module_type_package, "Attribute")
252
+ mtp_web_server_url.set("Name", "WebServerUrl")
253
+ mtp_web_server_url.set("AttributeDataType", "xs:string")
254
+
255
+ # Add external references to AspectSet
256
+ internal_element = ET.SubElement(module_type_package, "InternalElement")
257
+ internal_element.set("Name", "DataAssemblies")
258
+ internal_element.set("ID", get_uuid())
259
+ internal_element.set(
260
+ "RefBaseSystemUnitPath", "MTPDataAssemblySUCLib/DataAssemblySet"
261
+ )
262
+ external_interface = ET.SubElement(internal_element, "ExternalInterface")
263
+ external_interface.set("Name", "DataAssemblies")
264
+ external_interface.set("ID", get_uuid())
265
+ external_interface.set("RefBaseClassPath", "MTPICLib/AspectSetReference")
266
+ attribute = ET.SubElement(external_interface, "Attribute")
267
+ attribute.set("Name", "AspectRef")
268
+ attribute.set("AttributeDataType", "xs:string")
269
+ attribute.set(
270
+ "RefAttributeType", "MTPATLib/IDReferenceType/AspectIDAttributeType"
271
+ )
272
+ attribute_value = ET.SubElement(attribute, "Value")
273
+ attribute_value.text = self._instance_hierarchy_data_assemblies.attrib["ID"]
274
+ role_requirements = ET.SubElement(internal_element, "RoleRequirements")
275
+ role_requirements.set(
276
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
277
+ )
278
+
279
+ internal_element = ET.SubElement(module_type_package, "InternalElement")
280
+ internal_element.set("Name", "ServerAssemblies")
281
+ internal_element.set("ID", get_uuid())
282
+ internal_element.set(
283
+ "RefBaseSystemUnitPath", "MTPServerAssemblySUCLib/ServerAssemblySet"
284
+ )
285
+ external_interface = ET.SubElement(internal_element, "ExternalInterface")
286
+ external_interface.set("Name", "ServerAssemblies")
287
+ external_interface.set("ID", get_uuid())
288
+ external_interface.set("RefBaseClassPath", "MTPICLib/AspectSetReference")
289
+ attribute = ET.SubElement(external_interface, "Attribute")
290
+ attribute.set("Name", "AspectRef")
291
+ attribute.set("AttributeDataType", "xs:string")
292
+ attribute.set(
293
+ "RefAttributeType", "MTPATLib/IDReferenceType/AspectIDAttributeType"
294
+ )
295
+ attribute_value = ET.SubElement(attribute, "Value")
296
+ attribute_value.text = self._instance_hierarchy_server_assemblies.attrib["ID"]
297
+ role_requirements = ET.SubElement(internal_element, "RoleRequirements")
298
+ role_requirements.set(
299
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
300
+ )
301
+
302
+ internal_element = ET.SubElement(module_type_package, "InternalElement")
303
+ internal_element.set("Name", "HMI")
304
+ internal_element.set("ID", get_uuid())
305
+ internal_element.set("RefBaseSystemUnitPath", "MTPHMISUCLib/HMISet")
306
+ external_interface = ET.SubElement(internal_element, "ExternalInterface")
307
+ external_interface.set("Name", "HMI")
308
+ external_interface.set("ID", get_uuid())
309
+ external_interface.set("RefBaseClassPath", "MTPICLib/AspectSetReference")
310
+ attribute = ET.SubElement(external_interface, "Attribute")
311
+ attribute.set("Name", "AspectRef")
312
+ attribute.set("AttributeDataType", "xs:string")
313
+ attribute.set(
314
+ "RefAttributeType", "MTPATLib/IDReferenceType/AspectIDAttributeType"
315
+ )
316
+ attribute_value = ET.SubElement(attribute, "Value")
317
+ attribute_value.text = self._instance_hierarchy_pictures.attrib["ID"]
318
+ role_requirements = ET.SubElement(internal_element, "RoleRequirements")
319
+ role_requirements.set(
320
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
321
+ )
322
+
323
+ internal_element = ET.SubElement(module_type_package, "InternalElement")
324
+ internal_element.set("Name", "ProcessValues")
325
+ internal_element.set("ID", get_uuid())
326
+ internal_element.set(
327
+ "RefBaseSystemUnitPath", "MTPProcessValueSUCLib/ProcessValueSet"
328
+ )
329
+ external_interface = ET.SubElement(internal_element, "ExternalInterface")
330
+ external_interface.set("Name", "ProcessValues")
331
+ external_interface.set("ID", get_uuid())
332
+ external_interface.set("RefBaseClassPath", "MTPICLib/AspectSetReference")
333
+ attribute = ET.SubElement(external_interface, "Attribute")
334
+ attribute.set("Name", "AspectRef")
335
+ attribute.set("AttributeDataType", "xs:string")
336
+ attribute.set(
337
+ "RefAttributeType", "MTPATLib/IDReferenceType/AspectIDAttributeType"
338
+ )
339
+ attribute_value = ET.SubElement(attribute, "Value")
340
+ attribute_value.text = self._instance_hierarchy_process_values.attrib["ID"]
341
+ role_requirements = ET.SubElement(internal_element, "RoleRequirements")
342
+ role_requirements.set(
343
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
344
+ )
345
+
346
+ internal_element = ET.SubElement(module_type_package, "InternalElement")
347
+ internal_element.set("Name", "Services")
348
+ internal_element.set("ID", get_uuid())
349
+ internal_element.set("RefBaseSystemUnitPath", "MTPServiceSUCLib/ServiceSet")
350
+ external_interface = ET.SubElement(internal_element, "ExternalInterface")
351
+ external_interface.set("Name", "Services")
352
+ external_interface.set("ID", get_uuid())
353
+ external_interface.set("RefBaseClassPath", "MTPICLib/AspectSetReference")
354
+ attribute = ET.SubElement(external_interface, "Attribute")
355
+ attribute.set("Name", "AspectRef")
356
+ attribute.set("AttributeDataType", "xs:string")
357
+ attribute.set(
358
+ "RefAttributeType", "MTPATLib/IDReferenceType/AspectIDAttributeType"
359
+ )
360
+ attribute_value = ET.SubElement(attribute, "Value")
361
+ attribute_value.text = self._instance_hierarchy_services.attrib["ID"]
362
+ role_requirements = ET.SubElement(internal_element, "RoleRequirements")
363
+ role_requirements.set(
364
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
365
+ )
366
+
367
+ internal_element = ET.SubElement(module_type_package, "InternalElement")
368
+ internal_element.set("Name", "Texts")
369
+ internal_element.set("ID", get_uuid())
370
+ internal_element.set("RefBaseSystemUnitPath", "MTPTextSUCLib/TextSet")
371
+ external_interface = ET.SubElement(internal_element, "ExternalInterface")
372
+ external_interface.set("Name", "Texts")
373
+ external_interface.set("ID", get_uuid())
374
+ external_interface.set("RefBaseClassPath", "MTPICLib/AspectSetReference")
375
+ attribute = ET.SubElement(external_interface, "Attribute")
376
+ attribute.set("Name", "AspectRef")
377
+ attribute.set("AttributeDataType", "xs:string")
378
+ attribute.set(
379
+ "RefAttributeType", "MTPATLib/IDReferenceType/AspectIDAttributeType"
380
+ )
381
+ attribute_value = ET.SubElement(attribute, "Value")
382
+ attribute_value.text = self._instance_hierarchy_texts.attrib["ID"]
383
+ role_requirements = ET.SubElement(internal_element, "RoleRequirements")
384
+ role_requirements.set(
385
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
386
+ )
387
+
388
+ internal_element = ET.SubElement(module_type_package, "InternalElement")
389
+ internal_element.set("Name", "Alarms")
390
+ internal_element.set("ID", get_uuid())
391
+ internal_element.set("RefBaseSystemUnitPath", "MTPAlarmSUCLib/AlarmSet")
392
+ external_interface = ET.SubElement(internal_element, "ExternalInterface")
393
+ external_interface.set("Name", "Alarms")
394
+ external_interface.set("ID", get_uuid())
395
+ external_interface.set("RefBaseClassPath", "MTPICLib/AspectSetReference")
396
+ attribute = ET.SubElement(external_interface, "Attribute")
397
+ attribute.set("Name", "AspectRef")
398
+ attribute.set("AttributeDataType", "xs:string")
399
+ attribute.set(
400
+ "RefAttributeType", "MTPATLib/IDReferenceType/AspectIDAttributeType"
401
+ )
402
+ attribute_value = ET.SubElement(attribute, "Value")
403
+ attribute_value.text = self._instance_hierarchy_alarms.attrib["ID"]
404
+ role_requirements = ET.SubElement(internal_element, "RoleRequirements")
405
+ role_requirements.set(
406
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
407
+ )
408
+
409
+ role_requirements = ET.SubElement(module_type_package, "RoleRequirements")
410
+ role_requirements.set(
411
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
412
+ )
413
+ # Add to root MTP instance hierarchy
414
+ self._instance_hierarchy_module_type_package.append(module_type_package)
415
+
416
+ def __init_server_assemblies_instance_hierarchy(
417
+ self, pea_opcua_server: PeaOPCUAServer
418
+ ):
419
+
420
+ server_assembly_internal_element = ET.Element(
421
+ "InternalElement",
422
+ {
423
+ "Name": "MTPPy2.0-OPCUA-Server",
424
+ "ID": get_uuid(),
425
+ "RefBaseSystemUnitPath": "MTPServerAssemblySUCLib/ServerAssembly/OPCUAServer",
426
+ },
427
+ )
428
+
429
+ attribute = ET.SubElement(server_assembly_internal_element, "Attribute")
430
+ attribute.set("Name", "Endpoint")
431
+ attribute.set("AttributeDataType", "xs:string")
432
+ attribute_value = ET.SubElement(attribute, "Value")
433
+ attribute_value.text = pea_opcua_server.endpoint
434
+
435
+ self._namespace_of_data_items = (
436
+ pea_opcua_server.opcua_options_provider.get_default_namespace_uri()
437
+ )
438
+
439
+ attribute = ET.SubElement(server_assembly_internal_element, "Attribute")
440
+ attribute.set("Name", "MaxSessions")
441
+ attribute.set("AttributeDataType", "xs:unsignedInt")
442
+ # attribute_value = ET.SubElement(attribute, 'Value')
443
+ # attribute_value.text = str(pea_opcua_server.opcua_options_provider.get_max_sessions())
444
+
445
+ self._server_assembly_reference = server_assembly_internal_element
446
+ # Add to root Server Instance Hierarchy
447
+ self._instance_hierarchy_server_assemblies.append(
448
+ server_assembly_internal_element
449
+ )
450
+
451
+ def __add_data_assembly_to_instance_hierarchy_data_assemblies(
452
+ self, data_assembly: DataAssembly
453
+ ) -> str:
454
+
455
+ # create internal element
456
+ data_assembly_element = ET.Element(
457
+ "InternalElement",
458
+ {
459
+ "Name": data_assembly.tag_name,
460
+ "ID": get_uuid(),
461
+ "RefBaseSystemUnitPath": data_assembly.mtpObjectType,
462
+ },
463
+ )
464
+
465
+ if hasattr(data_assembly, "_data_items"):
466
+ for data_item in data_assembly._data_items.values():
467
+ # Add DataItem to DataAssembly
468
+ self.__add_data_item_to_data_assembly(data_assembly_element, data_item)
469
+
470
+ # AlarmSet.Base Trigger links require a CAEX ID on their DataItem Attribute.
471
+ for key in data_assembly:
472
+ data_item = data_assembly.get_item(key)
473
+ data_item_id = id(data_item)
474
+ if (
475
+ data_item_id in self._alarm_trigger_ids
476
+ and data_item_id not in self._serialized_data_items
477
+ ):
478
+ self.__add_data_item_to_data_assembly(data_assembly_element, data_item)
479
+
480
+ # Evaluate BaseFunctions
481
+ base_functions = [
482
+ "op_mode",
483
+ "src_mode",
484
+ "os_level",
485
+ "wqc",
486
+ "vqc",
487
+ "service_op_mode",
488
+ "service_src_mode",
489
+ "service_operator_interaction",
490
+ ]
491
+
492
+ for base_function_name in base_functions:
493
+ if not hasattr(data_assembly, base_function_name):
494
+ continue
495
+ base_function = eval(f"data_assembly.{base_function_name}")
496
+ for data_item in base_function._data_items.values():
497
+ # Add DataItem to DataAssembly
498
+ self.__add_data_item_to_data_assembly(data_assembly_element, data_item)
499
+
500
+ ref_id = get_uuid()
501
+ attribute = ET.SubElement(data_assembly_element, "Attribute")
502
+ attribute.set("Name", "RefID")
503
+ attribute.set("AttributeDataType", "xs:string")
504
+ attribute.set("RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType")
505
+ attribute_value = ET.SubElement(attribute, "Value")
506
+ attribute_value.text = ref_id
507
+
508
+ self._data_assembly_ref_ids.setdefault(id(data_assembly), ref_id)
509
+
510
+ self._instance_hierarchy_data_assemblies.append(data_assembly_element)
511
+
512
+ return ref_id
513
+
514
+ def __add_data_item_to_data_assembly(
515
+ self, parent_elem: ET.Element, data_item: DataItem
516
+ ):
517
+ """Add DataItems to the corresponding DataAssembly.
518
+
519
+ Args:
520
+ parent_elem: Parent to which the DataItems should be added
521
+ data_item: DataItem to be added
522
+ """
523
+ attr = ET.SubElement(parent_elem, "Attribute")
524
+ attr.set("Name", data_item.name)
525
+ attr.set("AttributeDataType", "xs:string")
526
+ trigger_id = self._alarm_trigger_ids.get(id(data_item))
527
+ if trigger_id is not None:
528
+ attr.set("ID", trigger_id)
529
+ self._serialized_data_items.add(id(data_item))
530
+
531
+ # value type data_item.w3c_xml_data_type
532
+
533
+ # DefaultValue is always present
534
+ attr_default_value = ET.SubElement(attr, "DefaultValue")
535
+ attr_default_value.text = str(data_item.get_value())
536
+
537
+ if data_item.comm_obj is None:
538
+ attr.set("RefAttributeType", "MTPATLib/StaticValueAttributeType")
539
+ attr_value = ET.SubElement(attr, "Value")
540
+ attr_value.text = str(data_item.get_value())
541
+ else:
542
+ attr.set("RefAttributeType", "MTPATLib/IDReferenceType/IDLinkAttributeType")
543
+ attr_value = ET.SubElement(attr, "Value")
544
+ attr_value.text = self.__add_item_to_opc_ua_server(data_item)
545
+
546
+ def __add_item_to_opc_ua_server(self, data_item: DataItem):
547
+ """Create an ExternalInterface at OPC UA server in ServerAssembly InstanceHierarchy.
548
+
549
+ Args:
550
+ data_item: Element for that an OPC UA node is to create for.
551
+
552
+ Returns:
553
+ The reference ID of the created item.
554
+ """
555
+ if data_item.comm_obj is None:
556
+ raise AttributeError(
557
+ "Adding Object as item to OPCUA server not possible - CommObj missing in DataItem"
558
+ )
559
+
560
+ data_item_node_identifier: StringNodeId = (
561
+ data_item.comm_obj._node_id.nodeid.Identifier
562
+ )
563
+ data_item_access = data_item.access
564
+ ref_id = get_uuid()
565
+
566
+ item = ET.Element("ExternalInterface")
567
+ item.set("Name", data_item_node_identifier)
568
+ item.set("ID", ref_id)
569
+ item.set("RefBaseClassPath", "MTPServerAssemblyICLib/DataItem/OPCUAItem")
570
+
571
+ # attribute: Identifier
572
+ attr_identifier = ET.SubElement(item, "Attribute")
573
+ attr_identifier.set("Name", "Identifier")
574
+ attr_identifier.set("AttributeDataType", "xs:string")
575
+ attr_identifier.set(
576
+ "RefAttributeType",
577
+ "MTPServerAssemblyATLib/OPCUABaseNodeIDType/OPCUAStringNodeIDType",
578
+ )
579
+ attr_identifier_value = ET.SubElement(attr_identifier, "Value")
580
+ attr_identifier_value.text = data_item_node_identifier
581
+
582
+ # attribute: Namespace
583
+ attr_ns = ET.SubElement(item, "Attribute")
584
+ attr_ns.set("Name", "Namespace")
585
+ attr_ns.set("AttributeDataType", "xs:string")
586
+ attr_ns_value = ET.SubElement(attr_ns, "Value")
587
+ attr_ns_value.text = self._namespace_of_data_items
588
+
589
+ # attribute: Access
590
+ # attr_ns = ET.SubElement(item, 'Attribute')
591
+ # attr_ns.set('Name', 'Access')
592
+ # attr_ns.set('AttributeDataType', 'xs:uint')
593
+ # attr_ns_value = ET.SubElement(attr_ns, 'Value')
594
+ # attr_ns_value.text = str(data_item_access.value)
595
+
596
+ self._server_assembly_reference.append(item)
597
+
598
+ return ref_id
599
+
600
+ def __add_service_to_instance_hierarchy_services(self, service: Service):
601
+ """Create a Service at Services InstanceHierarchy.
602
+
603
+ Args:
604
+ service: Service object
605
+
606
+ Returns:
607
+ str: The reference ID of the created service
608
+ """
609
+ ref_id = get_uuid()
610
+
611
+ service_element = ET.Element("InternalElement")
612
+ service_element.set("Name", service.name)
613
+ service_element.set("ID", ref_id)
614
+ service_element.set("RefBaseSystemUnitPath", "MTPServiceSUCLib/Service")
615
+
616
+ service_control_reference = (
617
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
618
+ service.service_control
619
+ )
620
+ )
621
+
622
+ # attribute: Reference to ServiceControl DataAssembly
623
+ service_control_ref_attr = ET.SubElement(service_element, "Attribute")
624
+ service_control_ref_attr.set("Name", "RefID")
625
+ service_control_ref_attr.set("AttributeDataType", "xs:string")
626
+ service_control_ref_attr.set(
627
+ "RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType"
628
+ )
629
+ service_control_ref_attr_value = ET.SubElement(
630
+ service_control_ref_attr, "Value"
631
+ )
632
+ service_control_ref_attr_value.text = service_control_reference
633
+
634
+ classification_attr = ET.SubElement(service_element, "Attribute")
635
+ classification_attr.set("Name", "Classification")
636
+ classification_attr.set(
637
+ "RefAttributeType", "AutomationMLBaseAttributeTypeLib/OrderedListType"
638
+ )
639
+ classification_attr_description = ET.SubElement(
640
+ classification_attr, "Description"
641
+ )
642
+ classification_attr_description.text = "Function Classification"
643
+
644
+ for configuration_parameter in service.configuration_parameters.values():
645
+ parameter_element = ET.Element("InternalElement")
646
+ parameter_element.set("Name", configuration_parameter.tag_name)
647
+ parameter_element.set("ID", get_uuid())
648
+ parameter_element.set(
649
+ "RefBaseSystemUnitPath",
650
+ "MTPServiceSUCLib/ServiceParameter/ConfigurationParameter",
651
+ )
652
+
653
+ classification_attr = ET.SubElement(parameter_element, "Attribute")
654
+ classification_attr.set("Name", "Classification")
655
+ classification_attr.set(
656
+ "RefAttributeType", "AutomationMLBaseAttributeTypeLib/OrderedListType"
657
+ )
658
+ classification_attr_description = ET.SubElement(
659
+ service_control_ref_attr, "Description"
660
+ )
661
+ classification_attr_description.text = "Function Classification"
662
+
663
+ parameter_reference = (
664
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
665
+ configuration_parameter
666
+ )
667
+ )
668
+
669
+ # attribute: Reference to Data Assembly
670
+ parameter_ref_attr = ET.SubElement(parameter_element, "Attribute")
671
+ parameter_ref_attr.set("Name", "RefID")
672
+ parameter_ref_attr.set("AttributeDataType", "xs:string")
673
+ parameter_ref_attr.set(
674
+ "RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType"
675
+ )
676
+ parameter_ref_attr_value = ET.SubElement(parameter_ref_attr, "Value")
677
+ parameter_ref_attr_value.text = parameter_reference
678
+
679
+ # attribute: RoleRequirements
680
+ parameter_role_req = ET.SubElement(parameter_element, "RoleRequirements")
681
+ parameter_role_req.set(
682
+ "RefBaseRoleClassPath",
683
+ "AutomationMLBaseRoleClassLib/AutomationMLBaseRole",
684
+ )
685
+
686
+ for procedure in service.procedures.values():
687
+ procedure_element = self.__create_procedure_element(procedure)
688
+ service_element.append(procedure_element)
689
+
690
+ # attribute: RoleRequirements
691
+ service_element_role_req = ET.SubElement(service_element, "RoleRequirements")
692
+ service_element_role_req.set(
693
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
694
+ )
695
+ self._instance_hierarchy_services.append(service_element_role_req)
696
+
697
+ return ref_id
698
+
699
+ def __create_procedure_element(self, procedure: Procedure) -> ET.Element:
700
+ """Create a Procedure InternalElement as XML Tree Element.
701
+
702
+ Args:
703
+ procedure: Procedure object
704
+
705
+ Returns:
706
+ the created Procedure InternalElement
707
+ """
708
+
709
+ procedure_element = ET.Element("InternalElement")
710
+ procedure_element.set("Name", procedure.name)
711
+ procedure_element.set("ID", get_uuid())
712
+ procedure_element.set(
713
+ "RefBaseSystemUnitPath", "MTPServiceSUCLib/Service/Procedure"
714
+ )
715
+
716
+ is_self_completing_attr = ET.SubElement(procedure_element, "Attribute")
717
+ is_self_completing_attr.set("Name", "IsSelfCompleting")
718
+ is_self_completing_attr.set("AttributeDataType", "xs:boolean")
719
+ is_self_completing_attr_value = ET.SubElement(is_self_completing_attr, "Value")
720
+ is_self_completing_attr_value.text = str(procedure.is_self_completing).lower()
721
+
722
+ id_attr = ET.SubElement(procedure_element, "Attribute")
723
+ id_attr.set("Name", "ProcedureID")
724
+ is_self_completing_attr.set("AttributeDataType", "xs:unsignedInt")
725
+ id_attr_value = ET.SubElement(id_attr, "Value")
726
+ id_attr_value.text = str(procedure.procedure_id)
727
+
728
+ procedure_da_reference = (
729
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
730
+ procedure.procedure_health_view
731
+ )
732
+ )
733
+
734
+ # attribute: Reference to DataAssembly
735
+ procedure_da_ref_attr = ET.SubElement(procedure_element, "Attribute")
736
+ procedure_da_ref_attr.set("Name", "RefID")
737
+ procedure_da_ref_attr.set("AttributeDataType", "xs:string")
738
+ procedure_da_ref_attr.set(
739
+ "RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType"
740
+ )
741
+ procedure_da_ref_attr_value = ET.SubElement(procedure_da_ref_attr, "Value")
742
+ procedure_da_ref_attr_value.text = procedure_da_reference
743
+
744
+ classification_attr = ET.SubElement(procedure_element, "Attribute")
745
+ classification_attr.set("Name", "Classification")
746
+ classification_attr.set(
747
+ "RefAttributeType", "AutomationMLBaseAttributeTypeLib/OrderedListType"
748
+ )
749
+ classification_attr_description = ET.SubElement(
750
+ classification_attr, "Description"
751
+ )
752
+ classification_attr_description.text = "Function Classification"
753
+
754
+ for process_value_out in procedure.process_value_outs.values():
755
+
756
+ data_assembly_ref = (
757
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
758
+ process_value_out
759
+ )
760
+ )
761
+ self.__add_process_value_out_to_instance_hierarchy_process_values(
762
+ process_value_out.tag_name, data_assembly_ref
763
+ )
764
+
765
+ pv_out = ET.Element("InternalElement")
766
+ pv_out.set("Name", process_value_out.tag_name)
767
+ pv_out.set("ID", get_uuid())
768
+ pv_out.set(
769
+ "RefBaseSystemUnitPath",
770
+ "MTPProcessValueSUCLib/ProcessValue/ProcessValueOut",
771
+ )
772
+
773
+ # attribute: Reference to Data Assembly
774
+ pv_out_ref_attr = ET.SubElement(pv_out, "Attribute")
775
+ pv_out_ref_attr.set("Name", "RefID")
776
+ pv_out_ref_attr.set("AttributeDataType", "xs:string")
777
+ pv_out_ref_attr.set(
778
+ "RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType"
779
+ )
780
+ pv_out_ref_attr_value = ET.SubElement(pv_out_ref_attr, "Value")
781
+ pv_out_ref_attr_value.text = data_assembly_ref
782
+
783
+ # attribute: RoleRequirements
784
+ pv_out_role_req = ET.SubElement(pv_out, "RoleRequirements")
785
+ pv_out_role_req.set(
786
+ "RefBaseRoleClassPath",
787
+ "AutomationMLBaseRoleClassLib/AutomationMLBaseRole",
788
+ )
789
+
790
+ procedure_element.append(pv_out)
791
+
792
+ for process_value_in in procedure.process_value_ins.values():
793
+
794
+ data_assembly_ref = (
795
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
796
+ process_value_in
797
+ )
798
+ )
799
+ self.__add_process_value_in_to_instance_hierarchy_process_values(
800
+ process_value_in.tag_name, data_assembly_ref
801
+ )
802
+
803
+ pv_in = ET.Element("InternalElement")
804
+ pv_in.set("Name", process_value_in.tag_name)
805
+ pv_in.set("ID", get_uuid())
806
+ pv_in.set(
807
+ "RefBaseSystemUnitPath",
808
+ "MTPProcessValueSUCLib/ProcessValue/ProcessValueIn",
809
+ )
810
+
811
+ # attribute: Reference to Data Assembly
812
+ pv_in_ref_attr = ET.SubElement(pv_in, "Attribute")
813
+ pv_in_ref_attr.set("Name", "RefID")
814
+ pv_in_ref_attr.set("AttributeDataType", "xs:string")
815
+ pv_in_ref_attr.set(
816
+ "RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType"
817
+ )
818
+ pv_in_ref_attr_value = ET.SubElement(pv_in_ref_attr, "Value")
819
+ pv_in_ref_attr_value.text = data_assembly_ref
820
+
821
+ # attribute: RoleRequirements
822
+ pv_in_role_req = ET.SubElement(pv_in, "RoleRequirements")
823
+ pv_in_role_req.set(
824
+ "RefBaseRoleClassPath",
825
+ "AutomationMLBaseRoleClassLib/AutomationMLBaseRole",
826
+ )
827
+
828
+ procedure_element.append(pv_in)
829
+
830
+ for procedure_parameter in procedure.procedure_parameters.values():
831
+
832
+ data_assembly_ref = (
833
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
834
+ procedure_parameter
835
+ )
836
+ )
837
+
838
+ procedure_parameter_element = ET.Element("InternalElement")
839
+ procedure_parameter_element.set("Name", procedure_parameter.tag_name)
840
+ procedure_parameter_element.set("ID", get_uuid())
841
+ procedure_parameter_element.set(
842
+ "RefBaseSystemUnitPath",
843
+ "MTPServiceSUCLib/ServiceParameter/ProcedureParameter",
844
+ )
845
+
846
+ # attribute: Reference to Data Assembly
847
+ procedure_parameter_element_ref_attr = ET.SubElement(
848
+ procedure_parameter_element, "Attribute"
849
+ )
850
+ procedure_parameter_element_ref_attr.set("Name", "RefID")
851
+ procedure_parameter_element_ref_attr.set("AttributeDataType", "xs:string")
852
+ procedure_parameter_element_ref_attr.set(
853
+ "RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType"
854
+ )
855
+ procedure_parameter_element_ref_attr_value = ET.SubElement(
856
+ procedure_parameter_element_ref_attr, "Value"
857
+ )
858
+ procedure_parameter_element_ref_attr_value.text = data_assembly_ref
859
+
860
+ # attribute: RoleRequirements
861
+ procedure_parameter_element_role_req = ET.SubElement(
862
+ procedure_parameter_element, "RoleRequirements"
863
+ )
864
+ procedure_parameter_element_role_req.set(
865
+ "RefBaseRoleClassPath",
866
+ "AutomationMLBaseRoleClassLib/AutomationMLBaseRole",
867
+ )
868
+
869
+ procedure_element.append(procedure_parameter_element)
870
+
871
+ for report_value in procedure.report_values.values():
872
+
873
+ data_assembly_ref = (
874
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
875
+ report_value
876
+ )
877
+ )
878
+
879
+ report_value_element = ET.Element("InternalElement")
880
+ report_value_element.set("Name", report_value.tag_name)
881
+ report_value_element.set("ID", get_uuid())
882
+ report_value_element.set(
883
+ "RefBaseSystemUnitPath", "MTPSUCLib/LinkedObject/ReportValue"
884
+ )
885
+
886
+ # attribute: Reference to Data Assembly
887
+ report_value_element_ref_attr = ET.SubElement(
888
+ report_value_element, "Attribute"
889
+ )
890
+ report_value_element_ref_attr.set("Name", "RefID")
891
+ report_value_element_ref_attr.set("AttributeDataType", "xs:string")
892
+ report_value_element_ref_attr.set(
893
+ "RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType"
894
+ )
895
+ report_value_element_ref_attr_value = ET.SubElement(
896
+ report_value_element_ref_attr, "Value"
897
+ )
898
+ report_value_element_ref_attr_value.text = data_assembly_ref
899
+
900
+ # attribute: RoleRequirements
901
+ report_value_element_role_req = ET.SubElement(
902
+ report_value_element, "RoleRequirements"
903
+ )
904
+ report_value_element_role_req.set(
905
+ "RefBaseRoleClassPath",
906
+ "AutomationMLBaseRoleClassLib/AutomationMLBaseRole",
907
+ )
908
+
909
+ procedure_element.append(report_value_element)
910
+
911
+ for required_equipment in procedure.required_equipment.values():
912
+
913
+ data_assembly_ref = (
914
+ self.__add_data_assembly_to_instance_hierarchy_data_assemblies(
915
+ required_equipment
916
+ )
917
+ )
918
+
919
+ required_equipment_element = ET.Element("InternalElement")
920
+ required_equipment_element.set("Name", required_equipment.tag_name)
921
+ required_equipment_element.set("ID", get_uuid())
922
+ required_equipment_element.set(
923
+ "RefBaseSystemUnitPath", "MTPSUCLib/LinkedObject/RequiredEquipment"
924
+ )
925
+
926
+ # attribute: Reference to Data Assembly
927
+ required_equipment_element_ref_attr = ET.SubElement(
928
+ required_equipment_element, "Attribute"
929
+ )
930
+ required_equipment_element_ref_attr.set("Name", "RefID")
931
+ required_equipment_element_ref_attr.set("AttributeDataType", "xs:string")
932
+ required_equipment_element_ref_attr.set(
933
+ "RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType"
934
+ )
935
+ required_equipment_element_ref_attr_value = ET.SubElement(
936
+ required_equipment_element_ref_attr, "Value"
937
+ )
938
+ required_equipment_element_ref_attr_value.text = data_assembly_ref
939
+
940
+ # attribute: RoleRequirements
941
+ required_equipment_element_role_req = ET.SubElement(
942
+ required_equipment_element, "RoleRequirements"
943
+ )
944
+ required_equipment_element_role_req.set(
945
+ "RefBaseRoleClassPath",
946
+ "AutomationMLBaseRoleClassLib/AutomationMLBaseRole",
947
+ )
948
+
949
+ procedure_element.append(required_equipment_element)
950
+
951
+ # attribute: RoleRequirements
952
+ procedure_role_req = ET.SubElement(procedure_element, "RoleRequirements")
953
+ procedure_role_req.set(
954
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
955
+ )
956
+
957
+ return procedure_element
958
+
959
+ def __add_process_value_in_to_instance_hierarchy_process_values(
960
+ self, name, data_assembly_reference
961
+ ):
962
+ """
963
+ Create an ProcessValueIn at ProcessValues InstanceHierarchy.
964
+
965
+ Args:
966
+ data_assembly_reference: ID Reference to DataAssembly object
967
+ """
968
+ pv_in = ET.Element("InternalElement")
969
+ pv_in.set("Name", name)
970
+ pv_in.set("ID", get_uuid())
971
+ pv_in.set(
972
+ "RefBaseSystemUnitPath", "MTPProcessValueSUCLib/ProcessValue/ProcessValueIn"
973
+ )
974
+
975
+ # attribute: Reference to Data Assembly
976
+ pv_in_ref_attr = ET.SubElement(pv_in, "Attribute")
977
+ pv_in_ref_attr.set("Name", "RefID")
978
+ pv_in_ref_attr.set("AttributeDataType", "xs:string")
979
+ pv_in_ref_attr.set(
980
+ "RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType"
981
+ )
982
+ pv_in_ref_attr_value = ET.SubElement(pv_in_ref_attr, "Value")
983
+ pv_in_ref_attr_value.text = data_assembly_reference
984
+
985
+ # attribute: RoleRequirements
986
+ pv_in_role_req = ET.SubElement(pv_in, "RoleRequirements")
987
+ pv_in_role_req.set(
988
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
989
+ )
990
+
991
+ self._instance_hierarchy_process_values.append(pv_in)
992
+
993
+ def __add_process_value_out_to_instance_hierarchy_process_values(
994
+ self, name, data_assembly_reference
995
+ ):
996
+ """Create an ProcessValueOut at ProcessValues InstanceHierarchy.
997
+
998
+ Args:
999
+ name: Name of the DataAssembly object
1000
+ data_assembly_reference: ID Reference to DataAssembly object
1001
+ """
1002
+
1003
+ pv_out = ET.Element("InternalElement")
1004
+ pv_out.set("Name", name)
1005
+ pv_out.set("ID", get_uuid())
1006
+ pv_out.set(
1007
+ "RefBaseSystemUnitPath",
1008
+ "MTPProcessValueSUCLib/ProcessValue/ProcessValueOut",
1009
+ )
1010
+
1011
+ # attribute: Reference to DataAssembly
1012
+ pv_in_ref_attr = ET.SubElement(pv_out, "Attribute")
1013
+ pv_in_ref_attr.set("Name", "RefID")
1014
+ pv_in_ref_attr.set("AttributeDataType", "xs:string")
1015
+ pv_in_ref_attr.set(
1016
+ "RefAttributeType", "MTPATLib/IDReferenceType/RefIDAttributeType"
1017
+ )
1018
+ pv_in_ref_attr_value = ET.SubElement(pv_in_ref_attr, "Value")
1019
+ pv_in_ref_attr_value.text = data_assembly_reference
1020
+
1021
+ # attribute: RoleRequirements
1022
+ pv_in_role_req = ET.SubElement(pv_out, "RoleRequirements")
1023
+ pv_in_role_req.set(
1024
+ "RefBaseRoleClassPath", "AutomationMLBaseRoleClassLib/AutomationMLBaseRole"
1025
+ )
1026
+
1027
+ self._instance_hierarchy_process_values.append(pv_out)
1028
+
1029
+ @staticmethod
1030
+ def __serialize_alarm_value(value: object) -> str:
1031
+ """Serialize scalar alarm values using XML-compatible spelling."""
1032
+ if type(value) is bool:
1033
+ return "true" if value else "false"
1034
+ return str(value)
1035
+
1036
+ @staticmethod
1037
+ def __add_role_requirements(parent: ET.Element) -> None:
1038
+ """Append the generic AutomationML role requirement."""
1039
+ role_requirements = ET.SubElement(parent, "RoleRequirements")
1040
+ role_requirements.set(
1041
+ "RefBaseRoleClassPath",
1042
+ "AutomationMLBaseRoleClassLib/AutomationMLBaseRole",
1043
+ )
1044
+
1045
+ @staticmethod
1046
+ def __add_alarm_attribute(
1047
+ parent: ET.Element,
1048
+ name: str,
1049
+ value: object,
1050
+ data_type: str | None = None,
1051
+ reference_type: str | None = None,
1052
+ ) -> ET.Element:
1053
+ """Append an alarm attribute and its scalar value."""
1054
+ attribute = ET.SubElement(parent, "Attribute")
1055
+ attribute.set("Name", name)
1056
+ if data_type is not None:
1057
+ attribute.set("AttributeDataType", data_type)
1058
+ if reference_type is not None:
1059
+ attribute.set("RefAttributeType", reference_type)
1060
+ attribute_value = ET.SubElement(attribute, "Value")
1061
+ attribute_value.text = MTPGenerator.__serialize_alarm_value(value)
1062
+ return attribute
1063
+
1064
+ def __add_alarm_to_instance_hierarchy_alarms(self, alarm: Alarm) -> None:
1065
+ """Add one AlarmSet.Base alarm and its references to the manifest."""
1066
+ assembly_key = id(alarm.data_assembly)
1067
+ data_assembly_ref_id = self._data_assembly_ref_ids.get(assembly_key)
1068
+ if data_assembly_ref_id is None:
1069
+ msg = f"Alarm {alarm.tag_name!r} must reference a registered DataAssembly"
1070
+ raise ValueError(msg)
1071
+ trigger_key = id(alarm.trigger)
1072
+ if trigger_key not in self._serialized_data_items:
1073
+ msg = f"Alarm {alarm.tag_name!r} trigger DataItem was not serialized"
1074
+ raise ValueError(msg)
1075
+ trigger_id = self._alarm_trigger_ids[trigger_key]
1076
+
1077
+ alarm_group = self._alarm_group_elements.get(assembly_key)
1078
+ if alarm_group is None:
1079
+ alarm_group = ET.Element(
1080
+ "InternalElement",
1081
+ {
1082
+ "Name": f"{alarm.data_assembly.tag_name}_AlarmGroup",
1083
+ "ID": get_uuid(),
1084
+ "RefBaseSystemUnitPath": "MTPAlarmSUCLib/AlarmGroup",
1085
+ },
1086
+ )
1087
+ self.__add_alarm_attribute(
1088
+ alarm_group,
1089
+ "RefID",
1090
+ data_assembly_ref_id,
1091
+ "xs:string",
1092
+ "MTPATLib/IDReferenceType/RefIDAttributeType",
1093
+ )
1094
+ self.__add_role_requirements(alarm_group)
1095
+ self._instance_hierarchy_alarms.append(alarm_group)
1096
+ self._alarm_group_elements[assembly_key] = alarm_group
1097
+
1098
+ message_id = self.__add_text_to_instance_hierarchy_texts(alarm)
1099
+ alarm_element = ET.Element(
1100
+ "InternalElement",
1101
+ {
1102
+ "Name": alarm.tag_name,
1103
+ "ID": get_uuid(),
1104
+ "RefBaseSystemUnitPath": "MTPAlarmSUCLib/Alarm",
1105
+ },
1106
+ )
1107
+ self.__add_alarm_attribute(
1108
+ alarm_element,
1109
+ "AckRequired",
1110
+ alarm.ack_required,
1111
+ "xs:boolean",
1112
+ )
1113
+ self.__add_alarm_attribute(
1114
+ alarm_element,
1115
+ "Severity",
1116
+ alarm.severity,
1117
+ "xs:short",
1118
+ )
1119
+ self.__add_alarm_attribute(
1120
+ alarm_element,
1121
+ "Trigger",
1122
+ trigger_id,
1123
+ "xs:string",
1124
+ "MTPATLib/IDReferenceType/IDLinkAttributeType",
1125
+ )
1126
+ self.__add_alarm_attribute(
1127
+ alarm_element,
1128
+ "TriggerValue",
1129
+ alarm.trigger_value,
1130
+ f"xs:{alarm.trigger.w3c_xml_data_type.string_value}",
1131
+ )
1132
+ classification = ET.SubElement(alarm_element, "Attribute")
1133
+ classification.set("Name", "Classification")
1134
+ classification.set(
1135
+ "RefAttributeType",
1136
+ "AutomationMLBaseAttributeTypeLib/OrderedListType",
1137
+ )
1138
+ ET.SubElement(classification, "Description").text = "Alarm Classification"
1139
+ self.__add_alarm_attribute(
1140
+ alarm_element,
1141
+ "MessageRef",
1142
+ message_id,
1143
+ "xs:string",
1144
+ "MTPTextATLib/TextRefAttributeType",
1145
+ )
1146
+ self.__add_role_requirements(alarm_element)
1147
+
1148
+ role_requirements_index = len(alarm_group) - 1
1149
+ alarm_group.insert(role_requirements_index, alarm_element)
1150
+
1151
+ def __add_text_to_instance_hierarchy_texts(self, alarm: Alarm) -> str:
1152
+ """Add an AlarmMessage and return its object ID."""
1153
+ message_id = get_uuid()
1154
+ message = ET.Element(
1155
+ "InternalElement",
1156
+ {
1157
+ "Name": f"{alarm.tag_name} message",
1158
+ "ID": message_id,
1159
+ "RefBaseSystemUnitPath": ("MTPTextSUCLib/TextDefinition/AlarmMessage"),
1160
+ },
1161
+ )
1162
+ alarm_text = ET.SubElement(
1163
+ message,
1164
+ "InternalElement",
1165
+ {
1166
+ "Name": f"{alarm.tag_name}.Text",
1167
+ "ID": get_uuid(),
1168
+ "RefBaseSystemUnitPath": (
1169
+ "MTPTextSUCLib/TextDefinition/AlarmMessage/AlarmText"
1170
+ ),
1171
+ },
1172
+ )
1173
+ self.__add_alarm_attribute(
1174
+ alarm_text,
1175
+ "Text",
1176
+ alarm.message,
1177
+ "xs:string",
1178
+ "MTPATLib/StaticValueAttributeType",
1179
+ )
1180
+ self.__add_role_requirements(alarm_text)
1181
+ self.__add_role_requirements(message)
1182
+ self._instance_hierarchy_texts.append(message)
1183
+ return message_id