epyt-flow 0.1.0__py3-none-any.whl → 0.2.0__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.
- epyt_flow/EPANET/compile_linux.sh +4 -0
- epyt_flow/VERSION +1 -1
- epyt_flow/__init__.py +21 -8
- epyt_flow/rest_api/scada_data/__init__.py +0 -0
- epyt_flow/rest_api/{scada_data_handler.py → scada_data/data_handlers.py} +3 -162
- epyt_flow/rest_api/scada_data/export_handlers.py +140 -0
- epyt_flow/rest_api/scada_data/handlers.py +167 -0
- epyt_flow/rest_api/scenario/__init__.py +0 -0
- epyt_flow/rest_api/scenario/event_handlers.py +118 -0
- epyt_flow/rest_api/{scenario_handler.py → scenario/handlers.py} +86 -67
- epyt_flow/rest_api/scenario/simulation_handlers.py +174 -0
- epyt_flow/rest_api/scenario/uncertainty_handlers.py +118 -0
- epyt_flow/rest_api/server.py +59 -24
- epyt_flow/simulation/scada/scada_data.py +2 -2
- epyt_flow/simulation/scada/scada_data_export.py +1 -7
- epyt_flow/simulation/scenario_config.py +12 -18
- epyt_flow/simulation/scenario_simulator.py +387 -132
- epyt_flow/simulation/sensor_config.py +370 -9
- epyt_flow/topology.py +47 -6
- epyt_flow/utils.py +75 -18
- {epyt_flow-0.1.0.dist-info → epyt_flow-0.2.0.dist-info}/METADATA +29 -5
- {epyt_flow-0.1.0.dist-info → epyt_flow-0.2.0.dist-info}/RECORD +25 -18
- epyt_flow/EPANET/compile.sh +0 -4
- {epyt_flow-0.1.0.dist-info → epyt_flow-0.2.0.dist-info}/LICENSE +0 -0
- {epyt_flow-0.1.0.dist-info → epyt_flow-0.2.0.dist-info}/WHEEL +0 -0
- {epyt_flow-0.1.0.dist-info → epyt_flow-0.2.0.dist-info}/top_level.txt +0 -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
|
epyt_flow/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.2.0
|
epyt_flow/__init__.py
CHANGED
|
@@ -1,24 +1,37 @@
|
|
|
1
|
-
import sys
|
|
2
1
|
import subprocess
|
|
3
|
-
import
|
|
2
|
+
import warnings
|
|
4
3
|
import shutil
|
|
5
|
-
|
|
4
|
+
import sys
|
|
5
|
+
import os
|
|
6
6
|
|
|
7
7
|
with open(os.path.join(os.path.dirname(__file__), 'VERSION'), encoding="utf-8") as f:
|
|
8
8
|
VERSION = f.read().strip()
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
def compile_libraries_unix(lib_epanet_name, compile_script_name):
|
|
12
|
+
"""Compile EPANET and EPANET-MSX libraries if needed."""
|
|
12
13
|
path_to_custom_libs = os.path.join(os.path.dirname(__file__), "customlibs")
|
|
13
|
-
path_to_lib_epanet = os.path.join(path_to_custom_libs,
|
|
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")
|
|
14
16
|
|
|
15
17
|
update = False
|
|
16
18
|
if os.path.isfile(path_to_lib_epanet):
|
|
17
19
|
if os.path.getmtime(__file__) > os.path.getmtime(path_to_lib_epanet):
|
|
18
20
|
update = True
|
|
19
21
|
|
|
20
|
-
if not os.path.isfile(path_to_lib_epanet) or update
|
|
22
|
+
if not os.path.isfile(path_to_lib_epanet) or update:
|
|
21
23
|
if shutil.which("gcc") is not None:
|
|
22
24
|
print("Compiling EPANET and EPANET-MSX...")
|
|
23
|
-
|
|
24
|
-
|
|
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")
|
|
File without changes
|
|
@@ -1,170 +1,11 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
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 .
|
|
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
|
|
File without changes
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides REST API handlers for scenario events.
|
|
3
|
+
"""
|
|
4
|
+
import warnings
|
|
5
|
+
import falcon
|
|
6
|
+
|
|
7
|
+
from .handlers import ScenarioBaseHandler
|
|
8
|
+
from ...simulation import Leakage, SensorFault
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ScenarioLeakageHandler(ScenarioBaseHandler):
|
|
12
|
+
"""
|
|
13
|
+
Class for handling GET and POST requests concerning leakages.
|
|
14
|
+
"""
|
|
15
|
+
def on_get(self, _, resp: falcon.Response, scenario_id: str) -> None:
|
|
16
|
+
"""
|
|
17
|
+
Gets all leakages of a given scenario.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
resp : `falcon.Response`
|
|
22
|
+
Response instance.
|
|
23
|
+
scenario_id : `str`
|
|
24
|
+
UUID of the scenario.
|
|
25
|
+
"""
|
|
26
|
+
try:
|
|
27
|
+
if self.scenario_mgr.validate_uuid(scenario_id) is False:
|
|
28
|
+
self.send_invalid_resource_id_error(resp)
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
my_leakages = self.scenario_mgr.get(scenario_id).leakages
|
|
32
|
+
self.send_json_response(resp, my_leakages)
|
|
33
|
+
except Exception as ex:
|
|
34
|
+
warnings.warn(str(ex))
|
|
35
|
+
resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
|
|
36
|
+
|
|
37
|
+
def on_post(self, req: falcon.Request, resp: falcon.Response, scenario_id: str) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Adds a new leakage to a given scenario.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
req : `falcon.Request`
|
|
44
|
+
Request instance.
|
|
45
|
+
resp : `falcon.Response`
|
|
46
|
+
Response instance.
|
|
47
|
+
scenario_id : `str`
|
|
48
|
+
UUID of the scenario.
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
if self.scenario_mgr.validate_uuid(scenario_id) is False:
|
|
52
|
+
self.send_invalid_resource_id_error(resp)
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
leakage = self.load_json_data_from_request(req)
|
|
56
|
+
if not isinstance(leakage, Leakage):
|
|
57
|
+
self.send_json_parsing_error(resp)
|
|
58
|
+
return
|
|
59
|
+
|
|
60
|
+
self.scenario_mgr.get(scenario_id).add_leakage(leakage)
|
|
61
|
+
except Exception as ex:
|
|
62
|
+
warnings.warn(str(ex))
|
|
63
|
+
resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ScenarioSensorFaultHandler(ScenarioBaseHandler):
|
|
67
|
+
"""
|
|
68
|
+
Class for handling GET and POST requests concerning sensor faults.
|
|
69
|
+
"""
|
|
70
|
+
def on_get(self, _, resp: falcon.Response, scenario_id: str) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Gets all sensor faults of a given scenario.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
resp : `falcon.Response`
|
|
77
|
+
Response instance.
|
|
78
|
+
scenario_id : `str`
|
|
79
|
+
UUID of the scenario.
|
|
80
|
+
"""
|
|
81
|
+
try:
|
|
82
|
+
if self.scenario_mgr.validate_uuid(scenario_id) is False:
|
|
83
|
+
self.send_invalid_resource_id_error(resp)
|
|
84
|
+
return
|
|
85
|
+
|
|
86
|
+
my_sensor_faults = self.scenario_mgr.get(scenario_id).sensor_faults
|
|
87
|
+
self.send_json_response(resp, my_sensor_faults)
|
|
88
|
+
except Exception as ex:
|
|
89
|
+
warnings.warn(str(ex))
|
|
90
|
+
resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
|
|
91
|
+
|
|
92
|
+
def on_post(self, req: falcon.Request, resp: falcon.Response, scenario_id: str) -> None:
|
|
93
|
+
"""
|
|
94
|
+
Adds a new sensor fault to a given scenario.
|
|
95
|
+
|
|
96
|
+
Parameters
|
|
97
|
+
----------
|
|
98
|
+
req : `falcon.Request`
|
|
99
|
+
Request instance.
|
|
100
|
+
resp : `falcon.Response`
|
|
101
|
+
Response instance.
|
|
102
|
+
scenario_id : `str`
|
|
103
|
+
UUID of the scenario.
|
|
104
|
+
"""
|
|
105
|
+
try:
|
|
106
|
+
if self.scenario_mgr.validate_uuid(scenario_id) is False:
|
|
107
|
+
self.send_invalid_resource_id_error(resp)
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
sensor_fault = self.load_json_data_from_request(req)
|
|
111
|
+
if not isinstance(sensor_fault, SensorFault):
|
|
112
|
+
self.send_json_parsing_error(resp)
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
self.scenario_mgr.get(scenario_id).add_sensor_fault(sensor_fault)
|
|
116
|
+
except Exception as ex:
|
|
117
|
+
warnings.warn(str(ex))
|
|
118
|
+
resp.status = falcon.HTTP_INTERNAL_SERVER_ERROR
|