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,418 @@
1
+ """Test Suite for MonAnaDrv."""
2
+
3
+ __copyright__ = (
4
+ "Copyright (c) 2026 Dresden University of Technology, Process-to-Order Group"
5
+ )
6
+ __license__ = "MIT"
7
+ import pytest
8
+ import time
9
+
10
+ from mtppy.utils.testing import data_object_set_modes
11
+ from mtppy.part3.data_assembly_set.active_elements.drives.mon_ana_drv import MonAnaDrv
12
+
13
+
14
+ def init_mon_ana_drv(
15
+ init_op_mode="off",
16
+ init_src_mode="int",
17
+ rev_fbk_calc=True,
18
+ fwd_fbk_calc=True,
19
+ rpm_fbk_calc=True,
20
+ safe_pos=1,
21
+ fwd_en=True,
22
+ rev_en=True,
23
+ perm_en=False,
24
+ intl_en=False,
25
+ prot_en=False,
26
+ mon_en=True,
27
+ mon_safe_pos=1,
28
+ mon_dyn_ti=0.5,
29
+ mon_stat_ti=0.5,
30
+ rmp_ah_en=True,
31
+ rmp_al_en=True,
32
+ rpm_ah_lim=900,
33
+ rpm_al_lim=50,
34
+ ):
35
+ instance = MonAnaDrv(
36
+ "tag",
37
+ tag_description="",
38
+ rpm_min=-10,
39
+ rpm_max=1000,
40
+ rpm_scl_min=0,
41
+ rpm_scl_max=1000,
42
+ rev_fbk_calc=rev_fbk_calc,
43
+ fwd_fbk_calc=fwd_fbk_calc,
44
+ rpm_fbk_calc=rpm_fbk_calc,
45
+ safe_pos=safe_pos,
46
+ fwd_en=fwd_en,
47
+ rev_en=rev_en,
48
+ perm_en=perm_en,
49
+ intl_en=intl_en,
50
+ prot_en=prot_en,
51
+ mon_en=mon_en,
52
+ mon_safe_pos=mon_safe_pos,
53
+ mon_dyn_ti=mon_dyn_ti,
54
+ mon_stat_ti=mon_stat_ti,
55
+ rpm_ah_en=rmp_ah_en,
56
+ rpm_al_en=rmp_al_en,
57
+ rpm_ah_lim=rpm_ah_lim,
58
+ rpm_al_lim=rpm_al_lim,
59
+ )
60
+ data_object_set_modes(instance, init_op_mode, init_src_mode)
61
+ return instance
62
+
63
+
64
+ test_scenario_no_control_signals = [
65
+ ("off", "int", "set_fwd_op"),
66
+ ("off", "man", "set_fwd_op"),
67
+ ("aut", "int", "set_fwd_op"),
68
+ ("aut", "man", "set_fwd_op"),
69
+ ("off", "int", "set_fwd_aut"),
70
+ ("off", "man", "set_fwd_aut"),
71
+ ("op", "int", "set_fwd_aut"),
72
+ ("op", "man", "set_fwd_aut"),
73
+ ("off", "int", "set_rev_op"),
74
+ ("off", "man", "set_rev_op"),
75
+ ("aut", "int", "set_rev_op"),
76
+ ("aut", "man", "set_rev_op"),
77
+ ("off", "int", "set_rev_aut"),
78
+ ("off", "man", "set_rev_aut"),
79
+ ("op", "int", "set_rev_aut"),
80
+ ("op", "man", "set_rev_aut"),
81
+ ]
82
+
83
+
84
+ @pytest.mark.parametrize(
85
+ "op_mode, src_mode, set_command", test_scenario_no_control_signals
86
+ )
87
+ def test_static_error(op_mode, src_mode, set_command):
88
+ for command in [True, False]:
89
+ mon_ana_drv = init_mon_ana_drv(
90
+ init_op_mode=op_mode,
91
+ init_src_mode=src_mode,
92
+ rmp_ah_en=False,
93
+ rmp_al_en=False,
94
+ )
95
+
96
+ mon_ana_drv.start_monitor()
97
+ try:
98
+ eval(f"mon_ana_drv.{set_command}({command})")
99
+ print(f"Scenario: mode {op_mode} {src_mode}, {set_command}")
100
+
101
+ # FwdFbk becomes to True without any control signals
102
+ mon_ana_drv["FwdFbk"] = True
103
+ time.sleep(0.6)
104
+
105
+ assert mon_ana_drv["MonStatErr"] == True
106
+ assert mon_ana_drv["SafePosAct"] == True
107
+ assert mon_ana_drv["FwdFbk"] == True # safe position is clockwise rotation
108
+
109
+ # FwdFbk becomes to True without any control signals
110
+ mon_ana_drv["FwdFbk"] = False
111
+ time.sleep(0.6)
112
+
113
+ assert mon_ana_drv["MonStatErr"] == True
114
+ assert mon_ana_drv["SafePosAct"] == True
115
+ assert mon_ana_drv["FwdFbk"] == True # safe position is clockwise rotation
116
+ finally:
117
+ mon_ana_drv.set_stop_monitor()
118
+ mon_ana_drv.monitor_static_thread.join()
119
+ mon_ana_drv.monitor_dynamic_thread.join()
120
+ mon_ana_drv.monitor_rpm_error_thread.join()
121
+
122
+
123
+ @pytest.mark.parametrize(
124
+ "op_mode, src_mode, set_command", test_scenario_no_control_signals
125
+ )
126
+ def test_static_error_within_monitor_time(op_mode, src_mode, set_command):
127
+ """If the required state is set on the interface before the time has expired (wait tme < 0.5s in this test),
128
+ there is no error"""
129
+
130
+ for command in [True, False]:
131
+ mon_ana_drv = init_mon_ana_drv(
132
+ init_op_mode=op_mode,
133
+ init_src_mode=src_mode,
134
+ rmp_ah_en=False,
135
+ rmp_al_en=False,
136
+ )
137
+
138
+ mon_ana_drv.start_monitor()
139
+ try:
140
+ eval(f"mon_ana_drv.{set_command}({command})")
141
+ print(f"Scenario: mode {op_mode} {src_mode}, {set_command}")
142
+
143
+ # mimic an error situation: FwdFbk changes to True without any change in control signal
144
+ mon_ana_drv["FwdFbk"] = True
145
+ time.sleep(0.3) # monitor time has not expired (0.5s)
146
+
147
+ assert mon_ana_drv["MonStatErr"] == False
148
+ assert mon_ana_drv["MonDynErr"] == False
149
+ finally:
150
+ mon_ana_drv.set_stop_monitor()
151
+ mon_ana_drv.monitor_static_thread.join()
152
+ mon_ana_drv.monitor_dynamic_thread.join()
153
+ mon_ana_drv.monitor_rpm_error_thread.join()
154
+
155
+
156
+ test_scenario_control_signals_fwd = [
157
+ ("op", "int", "set_fwd_op", "set_stop_op"),
158
+ ("op", "man", "set_fwd_op", "set_stop_op"),
159
+ ("aut", "int", "set_fwd_aut", "set_stop_aut"),
160
+ ("aut", "man", "set_fwd_aut", "set_stop_aut"),
161
+ ]
162
+
163
+
164
+ @pytest.mark.parametrize(
165
+ "op_mode, src_mode, fwd_command, stop_command", test_scenario_control_signals_fwd
166
+ )
167
+ def test_dynamic_error_fwd_stop(op_mode, src_mode, fwd_command, stop_command):
168
+ mon_ana_drv = init_mon_ana_drv(
169
+ init_op_mode=op_mode, init_src_mode=src_mode, rmp_ah_en=False, rmp_al_en=False
170
+ )
171
+
172
+ mon_ana_drv.start_monitor()
173
+ try:
174
+ eval(f"mon_ana_drv.{fwd_command}(True)")
175
+ print(f"Scenario: mode {op_mode} {src_mode}, {fwd_command}")
176
+
177
+ # FwdFbk does not change to True after control signal has changed to clockwise rotation
178
+ mon_ana_drv["FwdFbk"] = False
179
+ time.sleep(0.6)
180
+
181
+ assert mon_ana_drv["MonDynErr"] == True
182
+ assert mon_ana_drv["MonStatErr"] == False
183
+ assert mon_ana_drv["SafePosAct"] == True
184
+ assert mon_ana_drv["FwdFbk"] == True # safe position is clockwise rotation
185
+
186
+ eval(f"mon_ana_drv.{stop_command}(True)")
187
+ print(f"Scenario: mode {op_mode} {src_mode}, {stop_command}")
188
+
189
+ # FwdFbk does not change to False after control signal has changed to stop
190
+ mon_ana_drv["FwdFbk"] = True
191
+ time.sleep(0.6)
192
+
193
+ assert mon_ana_drv["MonDynErr"] == True
194
+ assert mon_ana_drv["MonStatErr"] == False
195
+ assert mon_ana_drv["SafePosAct"] == True
196
+ assert mon_ana_drv["FwdFbk"] == True # safe position is clockwise rotation
197
+ finally:
198
+ mon_ana_drv.set_stop_monitor()
199
+ mon_ana_drv.monitor_static_thread.join()
200
+ mon_ana_drv.monitor_dynamic_thread.join()
201
+ mon_ana_drv.monitor_rpm_error_thread.join()
202
+
203
+
204
+ test_scenario_control_signals_rev = [
205
+ ("op", "int", "set_rev_op", "set_stop_op"),
206
+ ("op", "man", "set_rev_op", "set_stop_op"),
207
+ ("aut", "int", "set_rev_aut", "set_stop_aut"),
208
+ ("aut", "man", "set_rev_aut", "set_stop_aut"),
209
+ ]
210
+
211
+
212
+ @pytest.mark.parametrize(
213
+ "op_mode, src_mode, rev_command, stop_command", test_scenario_control_signals_rev
214
+ )
215
+ def test_dynamic_error_rev_stop(op_mode, src_mode, rev_command, stop_command):
216
+ mon_ana_drv = init_mon_ana_drv(
217
+ init_op_mode=op_mode, init_src_mode=src_mode, rmp_ah_en=False, rmp_al_en=False
218
+ )
219
+
220
+ mon_ana_drv.start_monitor()
221
+ try:
222
+ eval(f"mon_ana_drv.{rev_command}(True)")
223
+ print(f"Scenario: mode {op_mode} {src_mode}, {rev_command}")
224
+
225
+ # RevFbk does not change to True after control signal has changed to anti-clockwise rotation
226
+ mon_ana_drv["RevFbk"] = False
227
+ time.sleep(0.6)
228
+ assert mon_ana_drv["MonDynErr"] == True
229
+ assert mon_ana_drv["MonStatErr"] == False
230
+ assert mon_ana_drv["SafePosAct"] == True
231
+ assert mon_ana_drv["FwdFbk"] == True # safe position is clockwise rotation
232
+
233
+ eval(f"mon_ana_drv.{stop_command}(True)")
234
+ print(f"Scenario: mode {op_mode} {src_mode}, {stop_command}")
235
+
236
+ # FwdFbk does not change to False after control signal has changed to stop
237
+ mon_ana_drv["FwdFbk"] = True
238
+ time.sleep(0.6)
239
+
240
+ assert mon_ana_drv["MonDynErr"] == True
241
+ assert mon_ana_drv["MonStatErr"] == False
242
+ assert mon_ana_drv["SafePosAct"] == True
243
+ assert mon_ana_drv["FwdFbk"] == True # safe position is clockwise rotation
244
+
245
+ finally:
246
+ mon_ana_drv.set_stop_monitor()
247
+ mon_ana_drv.monitor_static_thread.join()
248
+ mon_ana_drv.monitor_dynamic_thread.join()
249
+ mon_ana_drv.monitor_rpm_error_thread.join()
250
+
251
+
252
+ test_scenario_control_signals_reset = [
253
+ ("op", "int", "set_reset_op"),
254
+ ("op", "man", "set_reset_op"),
255
+ ("aut", "int", "set_reset_aut"),
256
+ ("aut", "man", "set_reset_aut"),
257
+ ]
258
+
259
+
260
+ @pytest.mark.parametrize(
261
+ "op_mode, src_mode, set_command", test_scenario_control_signals_reset
262
+ )
263
+ def test_dynamic_error_reset(op_mode, src_mode, set_command):
264
+ mon_ana_drv = init_mon_ana_drv(
265
+ init_op_mode=op_mode, init_src_mode=src_mode, rmp_ah_en=False, rmp_al_en=False
266
+ )
267
+
268
+ mon_ana_drv.start_monitor()
269
+ try:
270
+ # set valve to open
271
+ if op_mode == "op":
272
+ mon_ana_drv.set_fwd_op(True)
273
+ elif op_mode == "aut":
274
+ mon_ana_drv.set_fwd_aut(True)
275
+ time.sleep(0.6)
276
+
277
+ # reset valve
278
+ eval(f"mon_ana_drv.{set_command}(True)")
279
+ print(f"Scenario: mode {op_mode} {src_mode}, {set_command}")
280
+
281
+ # mimic an error situation: FwdFbk does not change to False after reset changes to True
282
+ mon_ana_drv["FwdFbk"] = True
283
+ time.sleep(0.6)
284
+
285
+ assert mon_ana_drv["MonDynErr"] == True
286
+ assert mon_ana_drv["MonStatErr"] == False
287
+ assert mon_ana_drv["SafePosAct"] == True
288
+ assert mon_ana_drv["FwdFbk"] == True # safe position is clockwise rotation
289
+ finally:
290
+ mon_ana_drv.set_stop_monitor()
291
+ mon_ana_drv.monitor_static_thread.join()
292
+ mon_ana_drv.monitor_dynamic_thread.join()
293
+ mon_ana_drv.monitor_rpm_error_thread.join()
294
+
295
+
296
+ test_scenario_rpm = [
297
+ ("op", "int", "set_rpm_int", False), # op shall not set rpm_int
298
+ ("aut", "int", "set_rpm_int", True),
299
+ ("op", "man", "set_rpm_man", True),
300
+ ("aut", "man", "set_rpm_man", False), # aut shall not set rpm_man
301
+ ]
302
+
303
+
304
+ @pytest.mark.parametrize(
305
+ "op_mode, src_mode, set_command, changes_expected", test_scenario_rpm
306
+ )
307
+ def test_rpm_error(op_mode, src_mode, set_command, changes_expected):
308
+ for command in [-500, 500, 700, 10000]:
309
+ mon_ana_drv = init_mon_ana_drv(
310
+ init_op_mode=op_mode,
311
+ init_src_mode=src_mode,
312
+ rpm_fbk_calc=True,
313
+ rmp_ah_en=False,
314
+ rmp_al_en=False,
315
+ )
316
+ mon_ana_drv.start_monitor()
317
+ try:
318
+ time.sleep(0.5)
319
+ eval(f"mon_ana_drv.{set_command}({command})")
320
+
321
+ print(
322
+ f"Scenario: mode {op_mode} {src_mode}, {set_command}, {command} changes expected: {changes_expected}"
323
+ )
324
+ mon_ana_drv["RpmFbk"] = 400
325
+ # RpmFbk is 400, it does not reach desired rpm (500 or 700)
326
+ time.sleep(0.5)
327
+ if changes_expected:
328
+ if -10 <= command <= 1000:
329
+ if command == 500:
330
+ assert mon_ana_drv["RpmErr"] == 100
331
+ elif command == 700:
332
+ assert mon_ana_drv["RpmErr"] == 300
333
+ else:
334
+ assert mon_ana_drv["RpmErr"] == -410
335
+ else:
336
+ assert mon_ana_drv["RpmErr"] == -410
337
+
338
+ assert mon_ana_drv["SafePosAct"] == True
339
+ assert mon_ana_drv["FwdFbk"] == True # safe position is clockwise rotation
340
+ finally:
341
+ mon_ana_drv.set_stop_monitor()
342
+ mon_ana_drv.monitor_static_thread.join()
343
+ mon_ana_drv.monitor_dynamic_thread.join()
344
+ mon_ana_drv.monitor_rpm_error_thread.join()
345
+
346
+
347
+ @pytest.mark.parametrize(
348
+ "op_mode, src_mode, set_command, changes_expected", test_scenario_rpm
349
+ )
350
+ def test_rpm_high_limit_alarm(op_mode, src_mode, set_command, changes_expected):
351
+ for command in [901, 999, 10000]: # high limit is 900
352
+ mon_ana_drv = init_mon_ana_drv(
353
+ init_op_mode=op_mode,
354
+ init_src_mode=src_mode,
355
+ rpm_fbk_calc=True,
356
+ rmp_ah_en=True,
357
+ rmp_al_en=False,
358
+ )
359
+ rpm = mon_ana_drv[MonAnaDrv.RPM_]
360
+ mon_ana_drv.start_monitor()
361
+ try:
362
+ time.sleep(0.5)
363
+ eval(f"mon_ana_drv.{set_command}({command})")
364
+ print(
365
+ f"Scenario: mode {op_mode} {src_mode}, {set_command}, {command} changes expected: {changes_expected}"
366
+ )
367
+ time.sleep(0.5)
368
+
369
+ if changes_expected:
370
+ if -10 <= command <= 1000:
371
+ assert mon_ana_drv["RpmAHAct"] == True
372
+ else:
373
+ assert mon_ana_drv["RpmAHAct"] == False
374
+ else:
375
+ assert mon_ana_drv[MonAnaDrv.RPM_] == rpm
376
+ assert mon_ana_drv["RpmAHAct"] == False
377
+ finally:
378
+ mon_ana_drv.set_stop_monitor()
379
+ mon_ana_drv.monitor_static_thread.join()
380
+ mon_ana_drv.monitor_dynamic_thread.join()
381
+ mon_ana_drv.monitor_rpm_error_thread.join()
382
+
383
+ mon_ana_drv.monitor_rpm_limit_high_thread.join()
384
+
385
+
386
+ @pytest.mark.parametrize(
387
+ "op_mode, src_mode, set_command, changes_expected", test_scenario_rpm
388
+ )
389
+ def test_rpm_low_limit_alarm(op_mode, src_mode, set_command, changes_expected):
390
+ for command in [10, 40]: # low limit is 50
391
+ mon_ana_drv = init_mon_ana_drv(
392
+ init_op_mode=op_mode,
393
+ init_src_mode=src_mode,
394
+ rpm_fbk_calc=True,
395
+ rmp_ah_en=False,
396
+ rmp_al_en=True,
397
+ )
398
+ mon_ana_drv.start_monitor()
399
+ try:
400
+ eval(f"mon_ana_drv.{set_command}({command})")
401
+ print(
402
+ f"Scenario: mode {op_mode} {src_mode}, {set_command}, {command} changes expected: {changes_expected}"
403
+ )
404
+ time.sleep(0.5)
405
+
406
+ assert mon_ana_drv["RpmALAct"] == True
407
+ finally:
408
+ mon_ana_drv.set_stop_monitor()
409
+ mon_ana_drv.monitor_static_thread.join()
410
+ mon_ana_drv.monitor_dynamic_thread.join()
411
+ mon_ana_drv.monitor_rpm_error_thread.join()
412
+
413
+ mon_ana_drv.monitor_rpm_limit_low_thread.join()
414
+
415
+
416
+ if __name__ == "__main__":
417
+ # This allows running the tests directly if needed
418
+ pytest.main([__file__, "-v"])