epyt-flow 0.1.0__tar.gz → 0.2.0__tar.gz

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 (151) hide show
  1. {epyt_flow-0.1.0/epyt_flow.egg-info → epyt_flow-0.2.0}/PKG-INFO +29 -5
  2. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/README.md +26 -2
  3. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/REQUIREMENTS.txt +1 -1
  4. epyt_flow-0.2.0/epyt_flow/EPANET/compile_linux.sh +4 -0
  5. epyt_flow-0.2.0/epyt_flow/VERSION +1 -0
  6. epyt_flow-0.2.0/epyt_flow/__init__.py +37 -0
  7. epyt_flow-0.2.0/epyt_flow/rest_api/scada_data/__init__.py +0 -0
  8. epyt_flow-0.1.0/epyt_flow/rest_api/scada_data_handler.py → epyt_flow-0.2.0/epyt_flow/rest_api/scada_data/data_handlers.py +3 -162
  9. epyt_flow-0.2.0/epyt_flow/rest_api/scada_data/export_handlers.py +140 -0
  10. epyt_flow-0.2.0/epyt_flow/rest_api/scada_data/handlers.py +167 -0
  11. epyt_flow-0.2.0/epyt_flow/rest_api/scenario/__init__.py +0 -0
  12. epyt_flow-0.2.0/epyt_flow/rest_api/scenario/event_handlers.py +118 -0
  13. epyt_flow-0.1.0/epyt_flow/rest_api/scenario_handler.py → epyt_flow-0.2.0/epyt_flow/rest_api/scenario/handlers.py +86 -67
  14. epyt_flow-0.2.0/epyt_flow/rest_api/scenario/simulation_handlers.py +174 -0
  15. epyt_flow-0.2.0/epyt_flow/rest_api/scenario/uncertainty_handlers.py +118 -0
  16. epyt_flow-0.2.0/epyt_flow/rest_api/server.py +141 -0
  17. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/scada/scada_data.py +2 -2
  18. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/scada/scada_data_export.py +1 -7
  19. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/scenario_config.py +12 -18
  20. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/scenario_simulator.py +387 -132
  21. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/sensor_config.py +370 -9
  22. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/topology.py +47 -6
  23. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/utils.py +75 -18
  24. {epyt_flow-0.1.0 → epyt_flow-0.2.0/epyt_flow.egg-info}/PKG-INFO +29 -5
  25. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow.egg-info/SOURCES.txt +10 -3
  26. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow.egg-info/requires.txt +1 -1
  27. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/pyproject.toml +1 -1
  28. epyt_flow-0.1.0/epyt_flow/EPANET/compile.sh +0 -4
  29. epyt_flow-0.1.0/epyt_flow/VERSION +0 -1
  30. epyt_flow-0.1.0/epyt_flow/__init__.py +0 -24
  31. epyt_flow-0.1.0/epyt_flow/rest_api/server.py +0 -106
  32. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/CODE_OF_CONDUCT.md +0 -0
  33. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/LICENSE +0 -0
  34. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/MANIFEST.in +0 -0
  35. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/AUTHORS +0 -0
  36. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/LICENSE +0 -0
  37. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/Readme_SRC_Engines.txt +0 -0
  38. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/enumstxt.h +0 -0
  39. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/epanet.c +0 -0
  40. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/epanet2.c +0 -0
  41. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/epanet2.def +0 -0
  42. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/errors.dat +0 -0
  43. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/funcs.h +0 -0
  44. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/genmmd.c +0 -0
  45. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/hash.c +0 -0
  46. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/hash.h +0 -0
  47. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/hydcoeffs.c +0 -0
  48. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/hydraul.c +0 -0
  49. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/hydsolver.c +0 -0
  50. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/hydstatus.c +0 -0
  51. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2.h +0 -0
  52. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_2.h +0 -0
  53. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/include/epanet2_enums.h +0 -0
  54. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/inpfile.c +0 -0
  55. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/input1.c +0 -0
  56. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/input2.c +0 -0
  57. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/input3.c +0 -0
  58. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/main.c +0 -0
  59. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/mempool.c +0 -0
  60. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/mempool.h +0 -0
  61. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/output.c +0 -0
  62. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/project.c +0 -0
  63. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/quality.c +0 -0
  64. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/qualreact.c +0 -0
  65. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/qualroute.c +0 -0
  66. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/report.c +0 -0
  67. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/rules.c +0 -0
  68. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/smatrix.c +0 -0
  69. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/text.h +0 -0
  70. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET/SRC_engines/types.h +0 -0
  71. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/MSX_Updates.txt +0 -0
  72. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/dispersion.h +0 -0
  73. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/hash.c +0 -0
  74. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/hash.h +0 -0
  75. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx.h +0 -0
  76. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/include/epanetmsx_export.h +0 -0
  77. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.c +0 -0
  78. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/mathexpr.h +0 -0
  79. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/mempool.c +0 -0
  80. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/mempool.h +0 -0
  81. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxchem.c +0 -0
  82. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxcompiler.c +0 -0
  83. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxdict.h +0 -0
  84. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxdispersion.c +0 -0
  85. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxerr.c +0 -0
  86. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxfile.c +0 -0
  87. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.c +0 -0
  88. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxfuncs.h +0 -0
  89. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxinp.c +0 -0
  90. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxout.c +0 -0
  91. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxproj.c +0 -0
  92. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxqual.c +0 -0
  93. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxrpt.c +0 -0
  94. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxtank.c +0 -0
  95. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxtoolkit.c +0 -0
  96. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxtypes.h +0 -0
  97. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxutils.c +0 -0
  98. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/msxutils.h +0 -0
  99. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/newton.c +0 -0
  100. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/newton.h +0 -0
  101. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/rk5.c +0 -0
  102. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/rk5.h +0 -0
  103. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/ros2.c +0 -0
  104. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/ros2.h +0 -0
  105. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/smatrix.c +0 -0
  106. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/Src/smatrix.h +0 -0
  107. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/EPANET/EPANET-MSX/readme.txt +0 -0
  108. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/__init__.py +0 -0
  109. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/benchmarks/__init__.py +0 -0
  110. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/benchmarks/batadal.py +0 -0
  111. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/benchmarks/batadal_data.py +0 -0
  112. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/benchmarks/battledim.py +0 -0
  113. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/benchmarks/battledim_data.py +0 -0
  114. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/benchmarks/gecco_water_quality.py +0 -0
  115. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/benchmarks/leakdb.py +0 -0
  116. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/benchmarks/leakdb_data.py +0 -0
  117. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/benchmarks/water_usage.py +0 -0
  118. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/data/networks.py +0 -0
  119. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/gym/__init__.py +0 -0
  120. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/gym/control_gyms.py +0 -0
  121. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/gym/scenario_control_env.py +0 -0
  122. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/metrics.py +0 -0
  123. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/models/__init__.py +0 -0
  124. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/models/event_detector.py +0 -0
  125. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/models/sensor_interpolation_detector.py +0 -0
  126. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/rest_api/__init__.py +0 -0
  127. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/rest_api/base_handler.py +0 -0
  128. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/rest_api/res_manager.py +0 -0
  129. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/serialization.py +0 -0
  130. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/__init__.py +0 -0
  131. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/events/__init__.py +0 -0
  132. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/events/actuator_events.py +0 -0
  133. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/events/event.py +0 -0
  134. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/events/leakages.py +0 -0
  135. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/events/sensor_faults.py +0 -0
  136. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/events/sensor_reading_attack.py +0 -0
  137. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/events/sensor_reading_event.py +0 -0
  138. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/events/system_event.py +0 -0
  139. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/parallel_simulation.py +0 -0
  140. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/scada/__init__.py +0 -0
  141. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/scada/advanced_control.py +0 -0
  142. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/simulation/scenario_visualizer.py +0 -0
  143. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/uncertainty/__init__.py +0 -0
  144. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/uncertainty/model_uncertainty.py +0 -0
  145. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/uncertainty/sensor_noise.py +0 -0
  146. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/uncertainty/uncertainties.py +0 -0
  147. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow/uncertainty/utils.py +0 -0
  148. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow.egg-info/dependency_links.txt +0 -0
  149. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/epyt_flow.egg-info/top_level.txt +0 -0
  150. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/setup.cfg +0 -0
  151. {epyt_flow-0.1.0 → epyt_flow-0.2.0}/setup.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: epyt-flow
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: EPyT-Flow -- EPANET Python Toolkit - Flow
5
5
  Author-email: André Artelt <aartelt@techfak.uni-bielefeld.de>, "Marios S. Kyriakou" <kiriakou.marios@ucy.ac.cy>, "Stelios G. Vrachimis" <vrachimis.stelios@ucy.ac.cy>
6
6
  License: MIT License
7
7
  Project-URL: Homepage, https://github.com/WaterFutures/EPyT-Flow
8
- Project-URL: Documentation, https://epytflow.readthedocs.io/en/latest/
8
+ Project-URL: Documentation, https://epyt-flow.readthedocs.io/en/latest/
9
9
  Project-URL: Repository, https://github.com/WaterFutures/EPyT-Flow.git
10
10
  Project-URL: Issues, https://github.com/WaterFutures/EPyT-Flow/issues
11
11
  Keywords: epanet,water,networks,hydraulics,quality,simulations
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.12
20
20
  Requires-Python: >=3.9
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
- Requires-Dist: epyt>=1.1.3
23
+ Requires-Dist: epyt>=1.1.6
24
24
  Requires-Dist: requests>=2.31.0
25
25
  Requires-Dist: scipy>=1.11.4
26
26
  Requires-Dist: u-msgpack-python>=2.8.0
@@ -32,6 +32,13 @@ Requires-Dist: falcon>=3.1.3
32
32
  Requires-Dist: multiprocess>=0.70.16
33
33
  Requires-Dist: psutil
34
34
 
35
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
36
+ [![pypi](https://img.shields.io/pypi/v/epyt-flow.svg)](https://pypi.org/project/epyt-flow/)
37
+ [![build](https://github.com/WaterFutures/EPyT-Flow/actions/workflows/build_tests.yml/badge.svg)](https://github.com/WaterFutures/EPyT-Flow/actions/workflows/build_tests.yml)
38
+ [![Documentation Status](https://readthedocs.org/projects/epyt-flow/badge/?version=stable)](https://epyt-flow.readthedocs.io/en/stable/?badge=stable)
39
+ [![Downloads](https://static.pepy.tech/badge/epyt-flow)](https://pepy.tech/project/epyt-flow)
40
+ [![Downloads](https://static.pepy.tech/badge/epyt-flow/month)](https://pepy.tech/project/epyt-flow)
41
+
35
42
  # EPyT-Flow -- EPANET Python Toolkit - Flow
36
43
 
37
44
  EPyT-Flow is a Python package building on top of [EPyT](https://github.com/OpenWaterAnalytics/EPyT)
@@ -45,11 +52,28 @@ Furthermore, it also provides an environment for developing and testing control
45
52
 
46
53
  ![](https://github.com/WaterFutures/EPyT-Flow/blob/main/docs/_static/net1_plot.png?raw=true)
47
54
 
55
+
56
+ ## Unique Features
57
+
58
+ Unique features of EPyT-Flow that make it superior to other (Python) toolboxes are the following:
59
+
60
+ - High-performance hydraulic and (advanced) water quality simulation
61
+ - High- and low-level interface
62
+ - Object-orientated design that is easy to extend and customize
63
+ - Sensor configurations
64
+ - Wide variety of pre-defined events (e.g. leakages, sensor faults, actuator events, cyber-attacks, etc.)
65
+ - Wide variety of pre-defined types of uncertainties (e.g. model uncertainties)
66
+ - Step-wise simulation and environment for training and evaluating control strategies
67
+ - Serialization module for easy exchange of data and (scenario) configurations
68
+ - REST API to make EPyT-Flow accessible in other applications
69
+ - Access to many WDNs and popular benchmarks (incl. their evaluation)
70
+
71
+
48
72
  ## Installation
49
73
 
50
74
  EPyT-Flow supports Python 3.9 - 3.12
51
75
 
52
- Note that [EPANET and EPANET-MSX sources](epyt_flow/EPANET/) are compiled and overrite the binaries
76
+ Note that [EPANET and EPANET-MSX sources](epyt_flow/EPANET/) are compiled and overwrite the binaries
53
77
  shipped by EPyT IF EPyT-Flow is installed on a Linux system. By this we not only aim to achieve
54
78
  a better performance of the simulations but also avoid any compatibility problems of pre-compiled binaries.
55
79
 
@@ -113,7 +137,7 @@ if __name__ == "__main__":
113
137
 
114
138
  ## Documentation
115
139
 
116
- Documentation is available on readthedocs: [https://epytflow.readthedocs.io/en/latest/](https://epytflow.readthedocs.io/en/latest/)
140
+ Documentation is available on readthedocs:[https://epyt-flow.readthedocs.io/en/latest/](https://epyt-flow.readthedocs.io/en/stable)
117
141
 
118
142
  ## License
119
143
 
@@ -1,3 +1,10 @@
1
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
2
+ [![pypi](https://img.shields.io/pypi/v/epyt-flow.svg)](https://pypi.org/project/epyt-flow/)
3
+ [![build](https://github.com/WaterFutures/EPyT-Flow/actions/workflows/build_tests.yml/badge.svg)](https://github.com/WaterFutures/EPyT-Flow/actions/workflows/build_tests.yml)
4
+ [![Documentation Status](https://readthedocs.org/projects/epyt-flow/badge/?version=stable)](https://epyt-flow.readthedocs.io/en/stable/?badge=stable)
5
+ [![Downloads](https://static.pepy.tech/badge/epyt-flow)](https://pepy.tech/project/epyt-flow)
6
+ [![Downloads](https://static.pepy.tech/badge/epyt-flow/month)](https://pepy.tech/project/epyt-flow)
7
+
1
8
  # EPyT-Flow -- EPANET Python Toolkit - Flow
2
9
 
3
10
  EPyT-Flow is a Python package building on top of [EPyT](https://github.com/OpenWaterAnalytics/EPyT)
@@ -11,11 +18,28 @@ Furthermore, it also provides an environment for developing and testing control
11
18
 
12
19
  ![](https://github.com/WaterFutures/EPyT-Flow/blob/main/docs/_static/net1_plot.png?raw=true)
13
20
 
21
+
22
+ ## Unique Features
23
+
24
+ Unique features of EPyT-Flow that make it superior to other (Python) toolboxes are the following:
25
+
26
+ - High-performance hydraulic and (advanced) water quality simulation
27
+ - High- and low-level interface
28
+ - Object-orientated design that is easy to extend and customize
29
+ - Sensor configurations
30
+ - Wide variety of pre-defined events (e.g. leakages, sensor faults, actuator events, cyber-attacks, etc.)
31
+ - Wide variety of pre-defined types of uncertainties (e.g. model uncertainties)
32
+ - Step-wise simulation and environment for training and evaluating control strategies
33
+ - Serialization module for easy exchange of data and (scenario) configurations
34
+ - REST API to make EPyT-Flow accessible in other applications
35
+ - Access to many WDNs and popular benchmarks (incl. their evaluation)
36
+
37
+
14
38
  ## Installation
15
39
 
16
40
  EPyT-Flow supports Python 3.9 - 3.12
17
41
 
18
- Note that [EPANET and EPANET-MSX sources](epyt_flow/EPANET/) are compiled and overrite the binaries
42
+ Note that [EPANET and EPANET-MSX sources](epyt_flow/EPANET/) are compiled and overwrite the binaries
19
43
  shipped by EPyT IF EPyT-Flow is installed on a Linux system. By this we not only aim to achieve
20
44
  a better performance of the simulations but also avoid any compatibility problems of pre-compiled binaries.
21
45
 
@@ -79,7 +103,7 @@ if __name__ == "__main__":
79
103
 
80
104
  ## Documentation
81
105
 
82
- Documentation is available on readthedocs: [https://epytflow.readthedocs.io/en/latest/](https://epytflow.readthedocs.io/en/latest/)
106
+ Documentation is available on readthedocs:[https://epyt-flow.readthedocs.io/en/latest/](https://epyt-flow.readthedocs.io/en/stable)
83
107
 
84
108
  ## License
85
109
 
@@ -1,4 +1,4 @@
1
- epyt>=1.1.3
1
+ epyt>=1.1.6
2
2
  requests>=2.31.0
3
3
  scipy>=1.11.4
4
4
  u-msgpack-python>=2.8.0
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+ mkdir -p "../customlibs/"
3
+ gcc -w -O3 -march=native -shared -Wl,-soname,libepanet2_2.so -fPIC -o "../customlibs/libepanet2_2.so" EPANET/SRC_engines/*.c -IEPANET/SRC_engines/include -lc -lm -pthread
4
+ gcc -w -O3 -march=native -fPIC -shared -Wl,-soname,libepanetmsx2_2_0.so -o "../customlibs/libepanetmsx2_2_0.so" -fopenmp -Depanetmsx_EXPORTS -IEPANET-MSX/Src/include -IEPANET/SRC_engines/include EPANET-MSX/Src/*.c -Wl,-rpath=. "../customlibs/libepanet2_2.so" -lm -lgomp -lpthread
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,37 @@
1
+ import subprocess
2
+ import warnings
3
+ import shutil
4
+ import sys
5
+ import os
6
+
7
+ with open(os.path.join(os.path.dirname(__file__), 'VERSION'), encoding="utf-8") as f:
8
+ VERSION = f.read().strip()
9
+
10
+
11
+ def compile_libraries_unix(lib_epanet_name, compile_script_name):
12
+ """Compile EPANET and EPANET-MSX libraries if needed."""
13
+ path_to_custom_libs = os.path.join(os.path.dirname(__file__), "customlibs")
14
+ path_to_lib_epanet = os.path.join(path_to_custom_libs, lib_epanet_name)
15
+ path_to_epanet = os.path.join(os.path.dirname(__file__), "EPANET")
16
+
17
+ update = False
18
+ if os.path.isfile(path_to_lib_epanet):
19
+ if os.path.getmtime(__file__) > os.path.getmtime(path_to_lib_epanet):
20
+ update = True
21
+
22
+ if not os.path.isfile(path_to_lib_epanet) or update:
23
+ if shutil.which("gcc") is not None:
24
+ print("Compiling EPANET and EPANET-MSX...")
25
+ try:
26
+ subprocess.check_call(f"cd \"{path_to_epanet}\"; bash {compile_script_name}",
27
+ shell=True)
28
+ print("Done")
29
+ except subprocess.CalledProcessError as ex:
30
+ print(f"Compilation failed\n{ex}")
31
+ else:
32
+ warnings.warn("GCC is not available to compile the required libraries.\n" +
33
+ "Falling back to pre-compiled library shipped by EPyT.")
34
+
35
+
36
+ if sys.platform.startswith("linux"):
37
+ compile_libraries_unix("libepanet2_2.so", "compile_linux.sh")
@@ -1,170 +1,11 @@
1
1
  """
2
- The module provides all handlers for SCADA data requests.
2
+ This module provides REST API handlers for accessing the final sensor readings
3
+ (e.g. pressure, flow rate, etc.).
3
4
  """
4
5
  import warnings
5
6
  import falcon
6
7
 
7
- from .base_handler import BaseHandler
8
- from .res_manager import ResourceManager
9
- from ..simulation import SensorConfig, SensorFault
10
-
11
-
12
- class ScadaDataManager(ResourceManager):
13
- """
14
- Class for managing SCADA data.
15
- """
16
-
17
-
18
- class ScadaDataBaseHandler(BaseHandler):
19
- """
20
- Base class for all handlers concerning SCADA data.
21
-
22
- Parameters
23
- ----------
24
- scada_data_mgr : `~epyt_flow.rest_api.scenario_handler.ScadaDataBaseHandler`
25
- SCADA data manager.
26
- """
27
- def __init__(self, scada_data_mgr: ScadaDataManager):
28
- self.scada_data_mgr = scada_data_mgr
29
-
30
-
31
- class ScadaDataRemoveHandler(ScadaDataBaseHandler):
32
- """
33
- Class for handling a DELETE request for a given SCADA data instance.
34
- """
35
- def on_delete(self, _, resp: falcon.Response, data_id: str) -> None:
36
- """
37
- Deletes a given SCADA data instance.
38
-
39
- Parameters
40
- ----------
41
- resp : `falcon.Response`
42
- Response instance.
43
- data_id : `str`
44
- UUID of the SCADA data instance.
45
- """
46
- try:
47
- if self.scada_data_mgr.validate_uuid(data_id) is False:
48
- self.send_invalid_resource_id_error(resp)
49
- return
50
-
51
- self.scada_data_mgr.remove(data_id)
52
- except Exception as ex:
53
- warnings.warn(str(ex))
54
- resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
55
-
56
-
57
- class ScadaDataSensorConfigHandler(ScadaDataBaseHandler):
58
- """
59
- Class for handling GET and POST requests for the sensor configuration
60
- of a given SCADA data instance.
61
- """
62
- def on_get(self, _, resp: falcon.Response, data_id: str) -> None:
63
- """
64
- Gets the sensor configuration of a given SCADA data instance.
65
-
66
- Parameters
67
- ----------
68
- resp : `falcon.Response`
69
- Response instance.
70
- data_id : `str`
71
- UUID of the SCADA data.
72
- """
73
- try:
74
- if self.scada_data_mgr.validate_uuid(data_id) is False:
75
- self.send_invalid_resource_id_error(resp)
76
- return
77
-
78
- my_sensor_config = self.scada_data_mgr.get(data_id).sensor_config
79
- self.send_json_response(resp, my_sensor_config)
80
- except Exception as ex:
81
- warnings.warn(str(ex))
82
- resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
83
-
84
- def on_post(self, req: falcon.Request, resp: falcon.Response, data_id: str) -> None:
85
- """
86
- Sets the sensor configuration of a given SCADA data instance.
87
-
88
- Parameters
89
- ----------
90
- req : `falcon.Request`
91
- Request instance.
92
- resp : `falcon.Response`
93
- Response instance.
94
- data_id : `str`
95
- UUID of the SCADA data.
96
- """
97
- try:
98
- if self.scada_data_mgr.validate_uuid(data_id) is False:
99
- self.send_invalid_resource_id_error(resp)
100
- return
101
-
102
- sensor_config = self.load_json_data_from_request(req)
103
- if not isinstance(sensor_config, SensorConfig):
104
- self.send_json_parsing_error(resp)
105
- return
106
-
107
- self.scada_data_mgr.get(data_id).sensor_config = sensor_config
108
- except Exception as ex:
109
- warnings.warn(str(ex))
110
- resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
111
-
112
-
113
- class ScadaDataSensorFaultsHandler(ScadaDataBaseHandler):
114
- """
115
- Class for handling GET and POST requests concerning sensor faults in a
116
- given SCADA data instance.
117
- """
118
- def on_get(self, _, resp: falcon.Response, data_id: str) -> None:
119
- """
120
- Gets all sensor faults of a given SCADA data instance.
121
-
122
- Parameters
123
- ----------
124
- resp : `falcon.Response`
125
- Response instance.
126
- data_id : `str`
127
- UUID of the SCADA data.
128
- """
129
- try:
130
- if self.scada_data_mgr.validate_uuid(data_id) is False:
131
- self.send_invalid_resource_id_error(resp)
132
- return
133
-
134
- sensor_faults = self.scada_data_mgr.get(data_id).sensor_faults
135
- self.send_json_response(resp, sensor_faults)
136
- except Exception as ex:
137
- warnings.warn(str(ex))
138
- resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
139
-
140
- def on_post(self, req: falcon.Request, resp: falcon.Response, data_id: str) -> None:
141
- """
142
- Sets (i.e. overrides) the sensor faults in a given SCADA data instance.
143
-
144
- Parameters
145
- ----------
146
- req : `falcon.Request`
147
- Request instance.
148
- resp : `falcon.Response`
149
- Response instance.
150
- data_id : `str`
151
- UUID of the SCADA data.
152
- """
153
- try:
154
- if self.scada_data_mgr.validate_uuid(data_id) is False:
155
- self.send_invalid_resource_id_error(resp)
156
- return
157
-
158
- sensor_faults = self.load_json_data_from_request(req)
159
- if not isinstance(sensor_faults, list) or \
160
- any(not isinstance(e, SensorFault) for e in sensor_faults):
161
- self.send_json_parsing_error(resp)
162
- return
163
-
164
- self.scada_data_mgr.get(data_id).sensor_faults = sensor_faults
165
- except Exception as ex:
166
- warnings.warn(str(ex))
167
- resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
8
+ from .handlers import ScadaDataBaseHandler
168
9
 
169
10
 
170
11
  class ScadaDataPressuresHandler(ScadaDataBaseHandler):
@@ -0,0 +1,140 @@
1
+ """
2
+ This module provides REST API handlers for exporting a given SCADA data instance.
3
+ """
4
+ import os
5
+ from abc import abstractmethod
6
+ import warnings
7
+ import falcon
8
+
9
+ from .handlers import ScadaDataBaseHandler
10
+ from ...utils import get_temp_folder
11
+ from ...simulation.scada import ScadaData, ScadaDataNumpyExport, ScadaDataMatlabExport, \
12
+ ScadaDataXlsxExport
13
+
14
+
15
+ class ScadaDataBaseExportHandler(ScadaDataBaseHandler):
16
+ """
17
+ Base handler for exporting a given SCADA data instance.
18
+ """
19
+ def __init__(self, file_ext: str, **kwds):
20
+ self.__file_ext = file_ext
21
+
22
+ super().__init__(**kwds)
23
+
24
+ def create_temp_file_path(self, data_id: str, file_ext: str) -> None:
25
+ """
26
+ Returns a path to a temporary file for storing the SCADA data instance.
27
+
28
+ Parameters
29
+ ----------
30
+ data_id : `str`
31
+ UUID of the SCADA data.
32
+ file_ext : `str`
33
+ File extension.
34
+ """
35
+ return os.path.join(get_temp_folder(), f"{data_id}.{file_ext}")
36
+
37
+ def send_temp_file(self, resp: falcon.Response, tmp_file: str,
38
+ content_type: str = "application/octet-stream") -> None:
39
+ """
40
+ Sends a given file (`tmp_file`) to the the client.
41
+
42
+ Parameters
43
+ ----------
44
+ resp : `falcon.Response`
45
+ Response instance.
46
+ tmp_file : `str`
47
+ Path to the temporary file to be send.
48
+ """
49
+ resp.status = falcon.HTTP_200
50
+ resp.content_type = content_type
51
+ with open(tmp_file, 'rb') as f:
52
+ resp.text = f.read()
53
+
54
+ @abstractmethod
55
+ def export(self, scada_data: ScadaData, tmp_file: str) -> None:
56
+ """
57
+ Exports a given SCADA data instance to a temporary file.
58
+
59
+ Parameters
60
+ ----------
61
+ scada_data : :class:`~epyt_flow.simulation.scada.scada_data.ScadaData`
62
+ SCADA data instance to be exported.
63
+ tmp_file : `str`
64
+ Path to temporary file.
65
+ """
66
+ raise NotImplementedError()
67
+
68
+ def on_get(self, _, resp: falcon.Response, data_id: str) -> None:
69
+ """
70
+ Gets the given SCADA data instance.
71
+
72
+ Parameters
73
+ ----------
74
+ resp : `falcon.Response`
75
+ Response instance.
76
+ data_id : `str`
77
+ UUID of the SCADA data.
78
+ """
79
+ try:
80
+ if self.scada_data_mgr.validate_uuid(data_id) is False:
81
+ self.send_invalid_resource_id_error(resp)
82
+ return
83
+
84
+ my_scada_data = self.scada_data_mgr.get(data_id)
85
+
86
+ tmp_file = self.create_temp_file_path(data_id, self.__file_ext)
87
+ self.export(my_scada_data, tmp_file)
88
+
89
+ self.send_temp_file(resp, tmp_file)
90
+
91
+ os.remove(tmp_file)
92
+ except Exception as ex:
93
+ warnings.warn(str(ex))
94
+ resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
95
+
96
+
97
+ class ScadaDataExportHandler(ScadaDataBaseExportHandler):
98
+ """
99
+ Class for handling a GET requests for exporting a given SCADA data instance
100
+ to an .epytflow_scada_data file.
101
+ """
102
+ def __init__(self, **kwds):
103
+ super().__init__(file_ext=".epytflow_scada_data", **kwds)
104
+
105
+ def export(self, scada_data: ScadaData, tmp_file: str) -> None:
106
+ scada_data.save_to_file(tmp_file)
107
+
108
+
109
+ class ScadaDataXlsxExportHandler(ScadaDataBaseExportHandler):
110
+ """
111
+ Class for handling a GET requests for exporting a given SCADA data instance to a .xlsx file.
112
+ """
113
+ def __init__(self, **kwds):
114
+ super().__init__(file_ext=".xlsx", **kwds)
115
+
116
+ def export(self, scada_data: ScadaData, tmp_file: str) -> None:
117
+ ScadaDataXlsxExport(tmp_file).export(scada_data)
118
+
119
+
120
+ class ScadaDataNumpyExportHandler(ScadaDataBaseExportHandler):
121
+ """
122
+ Class for handling a GET requests for exporting a given SCADA data instance to Numpy data file.
123
+ """
124
+ def __init__(self, **kwds):
125
+ super().__init__(file_ext=".npz", **kwds)
126
+
127
+ def export(self, scada_data: ScadaData, tmp_file: str) -> None:
128
+ ScadaDataNumpyExport(tmp_file).export(scada_data)
129
+
130
+
131
+ class ScadaDataMatlabExportHandler(ScadaDataBaseExportHandler):
132
+ """
133
+ Class for handling a GET requests for exporting a given SCADA data instance
134
+ to a Matlab data file.
135
+ """
136
+ def __init__(self, **kwds):
137
+ super().__init__(file_ext=".mat", **kwds)
138
+
139
+ def export(self, scada_data: ScadaData, tmp_file: str) -> None:
140
+ ScadaDataMatlabExport(tmp_file).export(scada_data)
@@ -0,0 +1,167 @@
1
+ """
2
+ The module provides REST API handlers for some SCADA data requests.
3
+ """
4
+ import warnings
5
+ import falcon
6
+
7
+ from ..base_handler import BaseHandler
8
+ from ..res_manager import ResourceManager
9
+ from ...simulation import SensorConfig, SensorFault
10
+
11
+
12
+ class ScadaDataManager(ResourceManager):
13
+ """
14
+ Class for managing SCADA data.
15
+ """
16
+
17
+
18
+ class ScadaDataBaseHandler(BaseHandler):
19
+ """
20
+ Base class for all handlers concerning SCADA data.
21
+
22
+ Parameters
23
+ ----------
24
+ scada_data_mgr : :class:`~epyt_flow.rest_api.scada_data.handlers.ScadaDataManager`
25
+ SCADA data manager.
26
+ """
27
+ def __init__(self, scada_data_mgr: ScadaDataManager):
28
+ self.scada_data_mgr = scada_data_mgr
29
+
30
+
31
+ class ScadaDataRemoveHandler(ScadaDataBaseHandler):
32
+ """
33
+ Class for handling a DELETE request for a given SCADA data instance.
34
+ """
35
+ def on_delete(self, _, resp: falcon.Response, data_id: str) -> None:
36
+ """
37
+ Deletes a given SCADA data instance.
38
+
39
+ Parameters
40
+ ----------
41
+ resp : `falcon.Response`
42
+ Response instance.
43
+ data_id : `str`
44
+ UUID of the SCADA data instance.
45
+ """
46
+ try:
47
+ if self.scada_data_mgr.validate_uuid(data_id) is False:
48
+ self.send_invalid_resource_id_error(resp)
49
+ return
50
+
51
+ self.scada_data_mgr.remove(data_id)
52
+ except Exception as ex:
53
+ warnings.warn(str(ex))
54
+ resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
55
+
56
+
57
+ class ScadaDataSensorConfigHandler(ScadaDataBaseHandler):
58
+ """
59
+ Class for handling GET and POST requests for the sensor configuration
60
+ of a given SCADA data instance.
61
+ """
62
+ def on_get(self, _, resp: falcon.Response, data_id: str) -> None:
63
+ """
64
+ Gets the sensor configuration of a given SCADA data instance.
65
+
66
+ Parameters
67
+ ----------
68
+ resp : `falcon.Response`
69
+ Response instance.
70
+ data_id : `str`
71
+ UUID of the SCADA data.
72
+ """
73
+ try:
74
+ if self.scada_data_mgr.validate_uuid(data_id) is False:
75
+ self.send_invalid_resource_id_error(resp)
76
+ return
77
+
78
+ my_sensor_config = self.scada_data_mgr.get(data_id).sensor_config
79
+ self.send_json_response(resp, my_sensor_config)
80
+ except Exception as ex:
81
+ warnings.warn(str(ex))
82
+ resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
83
+
84
+ def on_post(self, req: falcon.Request, resp: falcon.Response, data_id: str) -> None:
85
+ """
86
+ Sets the sensor configuration of a given SCADA data instance.
87
+
88
+ Parameters
89
+ ----------
90
+ req : `falcon.Request`
91
+ Request instance.
92
+ resp : `falcon.Response`
93
+ Response instance.
94
+ data_id : `str`
95
+ UUID of the SCADA data.
96
+ """
97
+ try:
98
+ if self.scada_data_mgr.validate_uuid(data_id) is False:
99
+ self.send_invalid_resource_id_error(resp)
100
+ return
101
+
102
+ sensor_config = self.load_json_data_from_request(req)
103
+ if not isinstance(sensor_config, SensorConfig):
104
+ self.send_json_parsing_error(resp)
105
+ return
106
+
107
+ self.scada_data_mgr.get(data_id).sensor_config = sensor_config
108
+ except Exception as ex:
109
+ warnings.warn(str(ex))
110
+ resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
111
+
112
+
113
+ class ScadaDataSensorFaultsHandler(ScadaDataBaseHandler):
114
+ """
115
+ Class for handling GET and POST requests concerning sensor faults in a
116
+ given SCADA data instance.
117
+ """
118
+ def on_get(self, _, resp: falcon.Response, data_id: str) -> None:
119
+ """
120
+ Gets all sensor faults of a given SCADA data instance.
121
+
122
+ Parameters
123
+ ----------
124
+ resp : `falcon.Response`
125
+ Response instance.
126
+ data_id : `str`
127
+ UUID of the SCADA data.
128
+ """
129
+ try:
130
+ if self.scada_data_mgr.validate_uuid(data_id) is False:
131
+ self.send_invalid_resource_id_error(resp)
132
+ return
133
+
134
+ sensor_faults = self.scada_data_mgr.get(data_id).sensor_faults
135
+ self.send_json_response(resp, sensor_faults)
136
+ except Exception as ex:
137
+ warnings.warn(str(ex))
138
+ resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
139
+
140
+ def on_post(self, req: falcon.Request, resp: falcon.Response, data_id: str) -> None:
141
+ """
142
+ Sets (i.e. overrides) the sensor faults in a given SCADA data instance.
143
+
144
+ Parameters
145
+ ----------
146
+ req : `falcon.Request`
147
+ Request instance.
148
+ resp : `falcon.Response`
149
+ Response instance.
150
+ data_id : `str`
151
+ UUID of the SCADA data.
152
+ """
153
+ try:
154
+ if self.scada_data_mgr.validate_uuid(data_id) is False:
155
+ self.send_invalid_resource_id_error(resp)
156
+ return
157
+
158
+ sensor_faults = self.load_json_data_from_request(req)
159
+ if not isinstance(sensor_faults, list) or \
160
+ any(not isinstance(e, SensorFault) for e in sensor_faults):
161
+ self.send_json_parsing_error(resp)
162
+ return
163
+
164
+ self.scada_data_mgr.get(data_id).sensor_faults = sensor_faults
165
+ except Exception as ex:
166
+ warnings.warn(str(ex))
167
+ resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR