PyAutomationIO 0.0.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.
Files changed (138) hide show
  1. automation/__init__.py +46 -0
  2. automation/alarms/__init__.py +563 -0
  3. automation/alarms/states.py +192 -0
  4. automation/alarms/trigger.py +64 -0
  5. automation/buffer.py +132 -0
  6. automation/core.py +1775 -0
  7. automation/dbmodels/__init__.py +23 -0
  8. automation/dbmodels/alarms.py +524 -0
  9. automation/dbmodels/core.py +86 -0
  10. automation/dbmodels/events.py +153 -0
  11. automation/dbmodels/logs.py +155 -0
  12. automation/dbmodels/machines.py +181 -0
  13. automation/dbmodels/opcua.py +81 -0
  14. automation/dbmodels/opcua_server.py +174 -0
  15. automation/dbmodels/tags.py +921 -0
  16. automation/dbmodels/users.py +259 -0
  17. automation/extensions/__init__.py +15 -0
  18. automation/extensions/api.py +149 -0
  19. automation/extensions/cors.py +18 -0
  20. automation/filter/__init__.py +19 -0
  21. automation/iad/__init__.py +3 -0
  22. automation/iad/frozen_data.py +54 -0
  23. automation/iad/out_of_range.py +51 -0
  24. automation/iad/outliers.py +51 -0
  25. automation/logger/__init__.py +0 -0
  26. automation/logger/alarms.py +426 -0
  27. automation/logger/core.py +265 -0
  28. automation/logger/datalogger.py +646 -0
  29. automation/logger/events.py +194 -0
  30. automation/logger/logdict.py +53 -0
  31. automation/logger/logs.py +203 -0
  32. automation/logger/machines.py +248 -0
  33. automation/logger/opcua_server.py +130 -0
  34. automation/logger/users.py +96 -0
  35. automation/managers/__init__.py +4 -0
  36. automation/managers/alarms.py +455 -0
  37. automation/managers/db.py +328 -0
  38. automation/managers/opcua_client.py +186 -0
  39. automation/managers/state_machine.py +183 -0
  40. automation/models.py +174 -0
  41. automation/modules/__init__.py +14 -0
  42. automation/modules/alarms/__init__.py +0 -0
  43. automation/modules/alarms/resources/__init__.py +10 -0
  44. automation/modules/alarms/resources/alarms.py +280 -0
  45. automation/modules/alarms/resources/summary.py +79 -0
  46. automation/modules/events/__init__.py +0 -0
  47. automation/modules/events/resources/__init__.py +10 -0
  48. automation/modules/events/resources/events.py +83 -0
  49. automation/modules/events/resources/logs.py +109 -0
  50. automation/modules/tags/__init__.py +0 -0
  51. automation/modules/tags/resources/__init__.py +8 -0
  52. automation/modules/tags/resources/tags.py +201 -0
  53. automation/modules/users/__init__.py +2 -0
  54. automation/modules/users/resources/__init__.py +10 -0
  55. automation/modules/users/resources/models/__init__.py +2 -0
  56. automation/modules/users/resources/models/roles.py +5 -0
  57. automation/modules/users/resources/models/users.py +14 -0
  58. automation/modules/users/resources/roles.py +38 -0
  59. automation/modules/users/resources/users.py +113 -0
  60. automation/modules/users/roles.py +121 -0
  61. automation/modules/users/users.py +335 -0
  62. automation/opcua/__init__.py +1 -0
  63. automation/opcua/models.py +541 -0
  64. automation/opcua/subscription.py +259 -0
  65. automation/pages/__init__.py +0 -0
  66. automation/pages/alarms.py +34 -0
  67. automation/pages/alarms_history.py +21 -0
  68. automation/pages/assets/styles.css +7 -0
  69. automation/pages/callbacks/__init__.py +28 -0
  70. automation/pages/callbacks/alarms.py +218 -0
  71. automation/pages/callbacks/alarms_summary.py +20 -0
  72. automation/pages/callbacks/db.py +222 -0
  73. automation/pages/callbacks/filter.py +238 -0
  74. automation/pages/callbacks/machines.py +29 -0
  75. automation/pages/callbacks/machines_detailed.py +581 -0
  76. automation/pages/callbacks/opcua.py +266 -0
  77. automation/pages/callbacks/opcua_server.py +244 -0
  78. automation/pages/callbacks/tags.py +495 -0
  79. automation/pages/callbacks/trends.py +119 -0
  80. automation/pages/communications.py +129 -0
  81. automation/pages/components/__init__.py +123 -0
  82. automation/pages/components/alarms.py +151 -0
  83. automation/pages/components/alarms_summary.py +45 -0
  84. automation/pages/components/database.py +128 -0
  85. automation/pages/components/gaussian_filter.py +69 -0
  86. automation/pages/components/machines.py +396 -0
  87. automation/pages/components/opcua.py +384 -0
  88. automation/pages/components/opcua_server.py +53 -0
  89. automation/pages/components/tags.py +253 -0
  90. automation/pages/components/trends.py +66 -0
  91. automation/pages/database.py +26 -0
  92. automation/pages/filter.py +55 -0
  93. automation/pages/machines.py +20 -0
  94. automation/pages/machines_detailed.py +41 -0
  95. automation/pages/main.py +63 -0
  96. automation/pages/opcua_server.py +28 -0
  97. automation/pages/tags.py +40 -0
  98. automation/pages/trends.py +35 -0
  99. automation/singleton.py +30 -0
  100. automation/state_machine.py +1672 -0
  101. automation/tags/__init__.py +2 -0
  102. automation/tags/cvt.py +1198 -0
  103. automation/tags/filter.py +55 -0
  104. automation/tags/tag.py +418 -0
  105. automation/tests/__init__.py +10 -0
  106. automation/tests/test_alarms.py +110 -0
  107. automation/tests/test_core.py +257 -0
  108. automation/tests/test_unit.py +21 -0
  109. automation/tests/test_user.py +155 -0
  110. automation/utils/__init__.py +164 -0
  111. automation/utils/decorators.py +222 -0
  112. automation/utils/npw.py +294 -0
  113. automation/utils/observer.py +21 -0
  114. automation/utils/units.py +118 -0
  115. automation/variables/__init__.py +55 -0
  116. automation/variables/adimentional.py +30 -0
  117. automation/variables/current.py +71 -0
  118. automation/variables/density.py +115 -0
  119. automation/variables/eng_time.py +68 -0
  120. automation/variables/force.py +90 -0
  121. automation/variables/length.py +104 -0
  122. automation/variables/mass.py +80 -0
  123. automation/variables/mass_flow.py +101 -0
  124. automation/variables/percentage.py +30 -0
  125. automation/variables/power.py +113 -0
  126. automation/variables/pressure.py +93 -0
  127. automation/variables/temperature.py +168 -0
  128. automation/variables/volume.py +70 -0
  129. automation/variables/volumetric_flow.py +100 -0
  130. automation/workers/__init__.py +2 -0
  131. automation/workers/logger.py +164 -0
  132. automation/workers/state_machine.py +207 -0
  133. automation/workers/worker.py +36 -0
  134. pyautomationio-0.0.0.dist-info/METADATA +198 -0
  135. pyautomationio-0.0.0.dist-info/RECORD +138 -0
  136. pyautomationio-0.0.0.dist-info/WHEEL +5 -0
  137. pyautomationio-0.0.0.dist-info/licenses/LICENSE +21 -0
  138. pyautomationio-0.0.0.dist-info/top_level.txt +1 -0
automation/models.py ADDED
@@ -0,0 +1,174 @@
1
+ # -*- coding: utf-8 -*-
2
+ """automation/models.py
3
+
4
+ This module implements a Tags and other classes for
5
+ modelling the subjects involved in the core of the engine.
6
+ """
7
+ from .modules.users.users import User
8
+ from .tags.tag import Tag
9
+ from .utils.decorators import set_event, logging_error_handler
10
+ from datetime import datetime, timezone
11
+
12
+
13
+ FLOAT = "float"
14
+ INTEGER = "int"
15
+ BOOL = "bool"
16
+ STRING = "str"
17
+
18
+ class PropertyType:
19
+
20
+ """
21
+ Implement an abstract property type
22
+ """
23
+
24
+ def __init__(self, _type, default=None, unit=None):
25
+ from .tags.cvt import CVTEngine
26
+ from .opcua.subscription import DAS
27
+ self._type = _type
28
+ self.unit = unit
29
+ self.__value = default
30
+ self.cvt = CVTEngine()
31
+ self.das = DAS()
32
+
33
+ @property
34
+ def value(self):
35
+ r"""
36
+ Documentation here
37
+ """
38
+ return self.__value
39
+
40
+ @value.setter
41
+ def value(self, value):
42
+
43
+ self.__value = value
44
+
45
+ @set_event(message=f"Attribute updated", classification="State Machine", priority=2, criticity=3)
46
+ def set_value(self, value, user:User=None, name:str=None, machine=None):
47
+
48
+ if isinstance(self, ProcessType):
49
+
50
+ if not self.read_only:
51
+
52
+ if hasattr(self, "tag"):
53
+
54
+ if self.tag:
55
+
56
+ if hasattr(machine, "data_timestamp"):
57
+ timestamp = machine.data_timestamp
58
+ else:
59
+ timestamp = datetime.now(timezone.utc)
60
+ val = self.tag.value.convert_value(value=value.value, from_unit=self.tag.get_unit(), to_unit=self.tag.get_display_unit())
61
+ self.tag.value.set_value(value=val, unit=self.tag.get_display_unit())
62
+ self.cvt.set_value(id=self.tag.id, value=val, timestamp=timestamp)
63
+ if self.tag.get_name() in self.das.buffer:
64
+ self.das.buffer[self.tag.get_name()]["timestamp"](timestamp)
65
+ self.das.buffer[self.tag.get_name()]["values"](val)
66
+
67
+ if self.value:
68
+ if value.value!=self.value.value:
69
+ if machine:
70
+ if machine.sio:
71
+ if name:
72
+ payload = {machine.name.value: {name: value.value}}
73
+ machine.sio.emit("on.machine.property", data=payload)
74
+ machine.sio.emit("on.machine", data=machine.serialize())
75
+
76
+ if name=="machine_interval":
77
+
78
+ return value, f"{name} To: {value.value} s."
79
+
80
+ self.value = value
81
+
82
+ return value, f"{name} To: {value.value}"
83
+
84
+
85
+ class StringType(PropertyType):
86
+
87
+ """
88
+ Implement a Float Type
89
+ """
90
+
91
+ def __init__(self, default=None, unit=None):
92
+
93
+ super(StringType, self).__init__(STRING, default, unit)
94
+
95
+
96
+ class FloatType(PropertyType):
97
+
98
+ """
99
+ Implement a Float Type
100
+ """
101
+
102
+ def __init__(self, default=None, unit=None):
103
+
104
+ super(FloatType, self).__init__(FLOAT, default, unit)
105
+
106
+
107
+ class IntegerType(PropertyType):
108
+
109
+ """
110
+ Implement an Integer Typle
111
+ """
112
+
113
+ def __init__(self, default=None, unit=None):
114
+
115
+ super(IntegerType, self).__init__(INTEGER, default, unit)
116
+
117
+
118
+ class BooleanType(PropertyType):
119
+
120
+ """
121
+ Implement a Boolean Type
122
+ """
123
+
124
+ def __init__(self, default=None, unit=None):
125
+
126
+ super(BooleanType, self).__init__(BOOL, default, unit)
127
+
128
+
129
+ class ProcessType(FloatType):
130
+
131
+ """
132
+ Implement a Process Type
133
+
134
+ Attributes
135
+
136
+ - read_only: [bool] only read from CVT, used to field data.
137
+ - tag: [Tag] Tag binded on CVT
138
+ """
139
+
140
+ def __init__(self, tag:Tag|None=None, default=None, read_only:bool=True, unit:str=None):
141
+
142
+ self.tag = tag
143
+ self.read_only = read_only
144
+
145
+ super(ProcessType, self).__init__(default=default, unit=unit)
146
+
147
+ @logging_error_handler
148
+ def serialize(self):
149
+ r"""
150
+ Documentation here
151
+ """
152
+ tag = None
153
+ if self.tag:
154
+
155
+ tag = self.tag.serialize()
156
+
157
+ value = None
158
+ if self.value:
159
+
160
+ if isinstance(self.value, (bool, float, int, str)):
161
+
162
+ value = self.value
163
+
164
+ elif isinstance(self.value, (BooleanType, FloatType, IntegerType, StringType)):
165
+
166
+ value = self.value.value
167
+
168
+ return {
169
+ "value": value,
170
+ "unit": self.unit,
171
+ "tag": tag,
172
+ "read_only": self.read_only
173
+ }
174
+
@@ -0,0 +1,14 @@
1
+ from .users import Role, Roles, Users
2
+
3
+ # Init Resources
4
+ def init_app(app):
5
+
6
+ from ..modules.tags.resources import init_app as init_tags
7
+ from ..modules.alarms.resources import init_app as init_alarms
8
+ from ..modules.users.resources import init_app as init_users
9
+ from ..modules.events.resources import init_app as init_events
10
+
11
+ init_tags()
12
+ init_alarms()
13
+ init_users()
14
+ init_events()
File without changes
@@ -0,0 +1,10 @@
1
+ from ....extensions.api import api
2
+
3
+
4
+ def init_app():
5
+
6
+ from .alarms import ns as ns_alarms
7
+ from .summary import ns as ns_summary
8
+
9
+ api.add_namespace(ns_alarms, path="/alarms")
10
+ api.add_namespace(ns_summary, path="/alarms/summary")
@@ -0,0 +1,280 @@
1
+ from flask_restx import Namespace, Resource, fields, reqparse
2
+ from .... import PyAutomation
3
+ from automation.alarms import AlarmState
4
+ from ....extensions.api import api
5
+ from ....extensions import _api as Api
6
+
7
+
8
+ ns = Namespace('Alarms', description='Alarms')
9
+ app = PyAutomation()
10
+
11
+ shelve_alarm_resource_by_name_model = api.model("shelve_alarm_resource_by_name_model",{
12
+ 'seconds': fields.Integer(required=False, description='Shelve time'),
13
+ 'minutes': fields.Integer(required=False, description='Shelve time'),
14
+ 'hours': fields.Integer(required=False, description='Shelve time'),
15
+ 'days': fields.Integer(required=False, description='Shelve time'),
16
+ 'weeks': fields.Integer(required=False, description='Shelve time')
17
+ })
18
+ shelve_alarm_parser = reqparse.RequestParser()
19
+ shelve_alarm_parser.add_argument("seconds", type=int, required=False, help='Shelve time', default=0)
20
+ shelve_alarm_parser.add_argument("minutes", type=int, required=False, help='Shelve time', default=0)
21
+ shelve_alarm_parser.add_argument("hours", type=int, required=False, help='Shelve time', default=0)
22
+ shelve_alarm_parser.add_argument("days", type=int, required=False, help='Shelve time', default=0)
23
+ shelve_alarm_parser.add_argument("weeks", type=int, required=False, help='Shelve time', default=0)
24
+
25
+ append_alarm_resource_model = api.model("append_alarm_resource_model",{
26
+ 'name': fields.String(required=True, description='Alarm Name'),
27
+ 'tag': fields.String(required=True, description='Tag to whom the alarm will be subscribed'),
28
+ 'description': fields.String(required=False, description='Alarm description'),
29
+ 'type': fields.String(required=True, description='Alarm Type - Allowed ["HIGH-HIGH", "HIGH", "BOOL", "LOW", "LOW-LOW"]'),
30
+ 'trigger_value': fields.Float(required=True, description="Alarm trigger value")
31
+ })
32
+ append_alarm_parser = reqparse.RequestParser()
33
+ append_alarm_parser.add_argument('name', type=str, required=True, help='Alarm Name')
34
+ append_alarm_parser.add_argument('tag', type=str, required=True, help='Tag to whom the alarm will be subscribed')
35
+ append_alarm_parser.add_argument('description', type=str, required=False, help='Alarm description', default="")
36
+ append_alarm_parser.add_argument('type', type=str, required=True, help='Alarm Type', choices=["HIGH-HIGH", "HIGH", "BOOL", "LOW", "LOW-LOW"])
37
+ append_alarm_parser.add_argument('trigger_value', type=float, required=True, help="Alarm trigger value")
38
+
39
+
40
+ @ns.route('/')
41
+ class AlarmsCollection(Resource):
42
+
43
+ @api.doc(security='apikey')
44
+ @Api.token_required(auth=True)
45
+ def get(self):
46
+ """
47
+ Get Alarms
48
+ """
49
+ return app.alarm_manager.serialize(), 200
50
+
51
+ @ns.route('/active_alarms')
52
+ class ActiveAlarmsCollection(Resource):
53
+
54
+ @api.doc(security='apikey')
55
+ @Api.token_required(auth=True)
56
+ def get(self):
57
+ """
58
+ Are there active alarms?
59
+ """
60
+ if app.alarm_manager.get_lasts_active_alarms(lasts=1):
61
+
62
+ return True, 200
63
+
64
+ return False, 200
65
+
66
+
67
+ @ns.route('/<id>')
68
+ class AlarmResource(Resource):
69
+
70
+ @api.doc(security='apikey')
71
+ @Api.token_required(auth=True)
72
+ def get(self, id):
73
+ """
74
+ Gets alarm by alarm id
75
+ """
76
+ alarm = app.get_alarm(id)
77
+
78
+ if alarm:
79
+
80
+ return alarm.serialize(), 200
81
+
82
+ return {'message': f"Alarm ID {id} is not exist"}, 400
83
+
84
+
85
+ @ns.route('/name/<alarm_name>')
86
+ class AlarmByNameResource(Resource):
87
+
88
+ @api.doc(security='apikey')
89
+ @Api.token_required(auth=True)
90
+ def get(self, alarm_name):
91
+ """
92
+ Get alarm info
93
+ """
94
+ alarm = app.alarm_manager.get_alarm_by_name(alarm_name)
95
+
96
+ if alarm:
97
+
98
+ return alarm.serialize(), 200
99
+
100
+ return {'message': f"Alarm Name {alarm_name} is not exist"}, 400
101
+
102
+
103
+ @ns.route('/acknowledge/<alarm_name>')
104
+ class AckAlarmByNameResource(Resource):
105
+
106
+ @api.doc(security='apikey')
107
+ @Api.token_required(auth=True)
108
+ def post(self, alarm_name:str):
109
+ """
110
+ Acknowledge alarm
111
+ """
112
+ result = dict()
113
+ alarm = app.alarm_manager.get_alarm_by_name(alarm_name)
114
+
115
+ if alarm:
116
+
117
+ if alarm.state in [AlarmState.UNACK, AlarmState.RTNUN]:
118
+ user = Api.get_current_user()
119
+ alarm.acknowledge(user=user)
120
+ result['message'] = f"{alarm.name} was acknowledged successfully"
121
+ result['data'] = alarm.serialize()
122
+
123
+ return result, 200
124
+
125
+ return {'message': f"Alarm Name {alarm_name} is not in Unacknowledged state"}, 400
126
+
127
+ return {'message': f"Alarm Name {alarm_name} is not exist"}, 400
128
+
129
+
130
+ @ns.route('/acknowledge_all')
131
+ class AckAllAlarmsResource(Resource):
132
+
133
+ @api.doc(security='apikey')
134
+ @Api.token_required(auth=True)
135
+ def post(self):
136
+ """
137
+ Acknowledge all alarms triggered
138
+ """
139
+ alarms = app.alarm_manager.get_alarms()
140
+
141
+ for _, alarm in alarms.items():
142
+
143
+ if alarm.state in [AlarmState.UNACK, AlarmState.RTNUN]:
144
+
145
+ user = Api.get_current_user()
146
+ alarm.acknowledge(user=user)
147
+
148
+ result = {
149
+ 'message': "Alarms were acknowledged successfully"
150
+ }
151
+
152
+ return result, 200
153
+
154
+
155
+ @ns.route('/designed_suppression/<alarm_name>')
156
+ class SuppressByDesignAlarmByNameResource(Resource):
157
+
158
+ @api.doc(security='apikey')
159
+ @Api.token_required(auth=True)
160
+ def post(self, alarm_name:str):
161
+ """
162
+ Suppressed by design alarm
163
+ """
164
+ result = dict()
165
+ alarm = app.alarm_manager.get_alarm_by_name(alarm_name)
166
+
167
+ if alarm:
168
+ user = Api.get_current_user()
169
+ alarm.designed_suppression(user=user)
170
+ result['message'] = f"{alarm.name} was suppressed by design successfully"
171
+ result['data'] = alarm.serialize()
172
+
173
+ return result, 200
174
+
175
+ return {'message': f"Alarm Name {alarm_name} is not exist"}, 400
176
+
177
+
178
+ @ns.route('/designed_unsuppression/<alarm_name>')
179
+ class DesignedUnsuppressionAlarmByNameResource(Resource):
180
+
181
+ @api.doc(security='apikey')
182
+ @Api.token_required(auth=True)
183
+ def post(self, alarm_name:str):
184
+ """
185
+ Unsuppress by design alarm
186
+ """
187
+ result = dict()
188
+ alarm = app.alarm_manager.get_alarm_by_name(alarm_name)
189
+
190
+ if alarm:
191
+
192
+ if alarm.state in [AlarmState.DSUPR]:
193
+ user = Api.get_current_user()
194
+ alarm.designed_unsuppression(user=user)
195
+ result['message'] = f"{alarm.name} was suppressed by design successfully"
196
+ result['data'] = alarm.serialize()
197
+
198
+ return result, 200
199
+
200
+ return {'message': f"You cannot unsuppress by design an alarm if not in suppress state"}, 400
201
+
202
+ return {'message': f"Alarm Name {alarm_name} is not exist"}, 400
203
+
204
+
205
+ @ns.route('/remove_from_service/<alarm_name>')
206
+ class OutOfServiceAlarmByNameResource(Resource):
207
+
208
+ @api.doc(security='apikey')
209
+ @Api.token_required(auth=True)
210
+ def post(self, alarm_name:str):
211
+ """
212
+ Out Of Service alarm
213
+ """
214
+ result = dict()
215
+ alarm = app.alarm_manager.get_alarm_by_name(alarm_name)
216
+
217
+ if alarm:
218
+ user = Api.get_current_user()
219
+ alarm.remove_from_service(user=user)
220
+ result['message'] = f"{alarm.name} was pusshed in out of service successfully"
221
+ result['data'] = alarm.serialize()
222
+
223
+ return result, 200
224
+
225
+ return {'message': f"Alarm Name {alarm_name} is not exist"}, 400
226
+
227
+
228
+ @ns.route('/shelve/<alarm_name>')
229
+ class ShelveAlarmByNameResource(Resource):
230
+
231
+ @api.doc(security='apikey')
232
+ @Api.token_required(auth=True)
233
+ @ns.expect(shelve_alarm_resource_by_name_model)
234
+ def post(self, alarm_name:str):
235
+ """
236
+ Shelve alarm
237
+ """
238
+ result = dict()
239
+ args = shelve_alarm_parser.parse_args()
240
+ alarm = app.alarm_manager.get_alarm_by_name(alarm_name)
241
+ if alarm:
242
+ user = Api.get_current_user()
243
+ alarm.shelve(
244
+ user=user,
245
+ **args
246
+ )
247
+ result['message'] = f"{alarm.name} was shelved successfully"
248
+ result['data'] = alarm.serialize()
249
+
250
+ return result, 200
251
+
252
+ return {'message': f"Alarm Name {alarm_name} is not exist"}, 400
253
+
254
+
255
+ @ns.route('/return_to_service/<alarm_name>')
256
+ class ReturnToServiceAlarmByNameResource(Resource):
257
+
258
+ @api.doc(security='apikey')
259
+ @Api.token_required(auth=True)
260
+ def post(self, alarm_name:str):
261
+ """
262
+ Return to service alarm
263
+ """
264
+ result = dict()
265
+ alarm = app.alarm_manager.get_alarm_by_name(alarm_name)
266
+
267
+ if alarm:
268
+
269
+ if alarm.state in [AlarmState.OOSRV]:
270
+ user = Api.get_current_user()
271
+ alarm.return_to_service(user=user)
272
+ result['message'] = f"{alarm.name} was returned to service successfully"
273
+ result['data'] = alarm.serialize()
274
+
275
+ return result, 200
276
+
277
+ return {'message': f"You cannot returned to service an alarm if not in out of service state"}, 400
278
+
279
+ return {'message': f"Alarm Name {alarm_name} is not exist"}, 400
280
+
@@ -0,0 +1,79 @@
1
+ import pytz
2
+ from datetime import datetime, timedelta
3
+ from flask_restx import Namespace, Resource, fields
4
+ from .... import PyAutomation
5
+ from ....extensions.api import api
6
+ from ....extensions import _api as Api
7
+ from ....dbmodels.alarms import AlarmSummary
8
+ from .... import _TIMEZONE, TIMEZONE
9
+
10
+ ns = Namespace('Alarms Summary', description='Alarms Summary')
11
+ app = PyAutomation()
12
+
13
+ alarms_summary_filter_model = api.model("alarms_summary_filter_model",{
14
+ 'names': fields.List(fields.String(), required=False),
15
+ 'states': fields.List(fields.String(), required=False),
16
+ 'tags': fields.List(fields.String(), required=False),
17
+ 'greater_than_timestamp': fields.DateTime(required=False, default=datetime.now(pytz.utc).astimezone(TIMEZONE) - timedelta(minutes=30), description=f'Greater than timestamp - DateTime Format: {app.cvt.DATETIME_FORMAT}'),
18
+ 'less_than_timestamp': fields.DateTime(required=False, default=datetime.now(pytz.utc).astimezone(TIMEZONE), description=f'Less than timestamp - DateTime Format: {app.cvt.DATETIME_FORMAT}'),
19
+ 'timezone': fields.String(required=False, default=_TIMEZONE)
20
+ })
21
+
22
+
23
+ @ns.route('/filter_by')
24
+ class AlarmsSummarygFilterByResource(Resource):
25
+
26
+ @api.doc(security='apikey')
27
+ @Api.token_required(auth=True)
28
+ @ns.expect(alarms_summary_filter_model)
29
+ def post(self):
30
+ r"""
31
+ Alarms Summary Filter By
32
+ """
33
+ timezone = _TIMEZONE
34
+ if "timezone" in api.payload:
35
+
36
+ timezone = api.payload["timezone"]
37
+
38
+ if timezone not in pytz.all_timezones:
39
+
40
+ return f"Invalid Timezone", 400
41
+
42
+ separator = '.'
43
+ if 'greater_than_timestamp' in api.payload:
44
+
45
+ greater_than_timestamp = api.payload['greater_than_timestamp']
46
+ api.payload['greater_than_timestamp'] = greater_than_timestamp.replace("T", " ").split(separator, 1)[0] + '.00'
47
+
48
+ if "less_than_timestamp" in api.payload:
49
+
50
+ less_than_timestamp = api.payload['less_than_timestamp']
51
+ api.payload['less_than_timestamp'] = less_than_timestamp.replace("T", " ").split(separator, 1)[0] + '.00'
52
+
53
+ return app.filter_alarms_by(**api.payload)
54
+
55
+
56
+ @ns.route('/lasts/<lasts>')
57
+ class LastsAlarmsResource(Resource):
58
+
59
+ @api.doc(security='apikey')
60
+ @Api.token_required(auth=True)
61
+ def get(self, lasts:int=10):
62
+ r"""
63
+ Get lasts alarms
64
+ """
65
+
66
+ return app.get_lasts_alarms(lasts=int(lasts))
67
+
68
+
69
+ @ns.route('/<id>/comments')
70
+ class AlarmsSummaryCommentsResource(Resource):
71
+
72
+ @api.doc(security='apikey')
73
+ @Api.token_required(auth=True)
74
+ def get(self, id:int):
75
+ r"""
76
+ Get Alarm Summary Comments
77
+ """
78
+ comments = AlarmSummary.get_alarm_summary_comments(id=id)
79
+ return comments, 200
File without changes
@@ -0,0 +1,10 @@
1
+ from ....extensions.api import api
2
+
3
+
4
+ def init_app():
5
+
6
+ from .events import ns as ns_events
7
+ from .logs import ns as ns_logs
8
+
9
+ api.add_namespace(ns_events, path="/events")
10
+ api.add_namespace(ns_logs, path="/logs")
@@ -0,0 +1,83 @@
1
+ import pytz
2
+ from datetime import datetime, timedelta
3
+ from flask_restx import Namespace, Resource, fields
4
+ from .... import PyAutomation
5
+ from ....extensions.api import api
6
+ from ....extensions import _api as Api
7
+ from ....dbmodels.events import Events
8
+ from .... import _TIMEZONE, TIMEZONE
9
+
10
+ ns = Namespace('Events Logger', description='Events Logger')
11
+ app = PyAutomation()
12
+
13
+
14
+ events_filter_model = api.model("events_filter_model",{
15
+ 'usernames': fields.List(fields.String(), required=False),
16
+ 'priorities': fields.List(fields.Integer(), required=False),
17
+ 'criticities': fields.List(fields.Integer(), required=False),
18
+ 'message': fields.String(required=False),
19
+ 'classification': fields.String(required=False),
20
+ 'description': fields.String(required=False),
21
+ 'greater_than_timestamp': fields.DateTime(required=False, default=datetime.now(pytz.utc).astimezone(TIMEZONE) - timedelta(minutes=30), description=f'Greater than timestamp - DateTime Format: {app.cvt.DATETIME_FORMAT}'),
22
+ 'less_than_timestamp': fields.DateTime(required=False, default=datetime.now(pytz.utc).astimezone(TIMEZONE), description=f'Less than timestamp - DateTime Format: {app.cvt.DATETIME_FORMAT}'),
23
+ 'timezone': fields.String(required=False, default=_TIMEZONE)
24
+ })
25
+
26
+
27
+ @ns.route('/filter_by')
28
+ class EventsSummaryFilterByResource(Resource):
29
+
30
+ @api.doc(security='apikey')
31
+ @Api.token_required(auth=True)
32
+ @ns.expect(events_filter_model)
33
+ def post(self):
34
+ r"""
35
+ Events Summary Filter By
36
+ """
37
+ timezone = _TIMEZONE
38
+ if "timezone" in api.payload:
39
+
40
+ timezone = api.payload["timezone"]
41
+
42
+ if timezone not in pytz.all_timezones:
43
+
44
+ return f"Invalid Timezone", 400
45
+
46
+ separator = '.'
47
+ if 'greater_than_timestamp' in api.payload:
48
+
49
+ greater_than_timestamp = api.payload['greater_than_timestamp']
50
+ api.payload['greater_than_timestamp'] = greater_than_timestamp.replace("T", " ").split(separator, 1)[0] + '.00'
51
+
52
+ if "less_than_timestamp" in api.payload:
53
+
54
+ less_than_timestamp = api.payload['less_than_timestamp']
55
+ api.payload['less_than_timestamp'] = less_than_timestamp.replace("T", " ").split(separator, 1)[0] + '.00'
56
+
57
+ return app.filter_events_by(**api.payload)
58
+
59
+
60
+ @ns.route('/lasts/<lasts>')
61
+ class LastsEventsResource(Resource):
62
+
63
+ @api.doc(security='apikey')
64
+ @Api.token_required(auth=True)
65
+ def get(self, lasts:int=10):
66
+ r"""
67
+ Get lasts events
68
+ """
69
+
70
+ return app.get_lasts_events(lasts=int(lasts))
71
+
72
+
73
+ @ns.route('/<id>/comments')
74
+ class EventsCommentsResource(Resource):
75
+
76
+ @api.doc(security='apikey')
77
+ @Api.token_required(auth=True)
78
+ def get(self, id:int):
79
+ r"""
80
+ Get Alarm Summary Comments
81
+ """
82
+ comments = Events.get_comments(id=id)
83
+ return comments, 200