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.
- automation/__init__.py +46 -0
- automation/alarms/__init__.py +563 -0
- automation/alarms/states.py +192 -0
- automation/alarms/trigger.py +64 -0
- automation/buffer.py +132 -0
- automation/core.py +1775 -0
- automation/dbmodels/__init__.py +23 -0
- automation/dbmodels/alarms.py +524 -0
- automation/dbmodels/core.py +86 -0
- automation/dbmodels/events.py +153 -0
- automation/dbmodels/logs.py +155 -0
- automation/dbmodels/machines.py +181 -0
- automation/dbmodels/opcua.py +81 -0
- automation/dbmodels/opcua_server.py +174 -0
- automation/dbmodels/tags.py +921 -0
- automation/dbmodels/users.py +259 -0
- automation/extensions/__init__.py +15 -0
- automation/extensions/api.py +149 -0
- automation/extensions/cors.py +18 -0
- automation/filter/__init__.py +19 -0
- automation/iad/__init__.py +3 -0
- automation/iad/frozen_data.py +54 -0
- automation/iad/out_of_range.py +51 -0
- automation/iad/outliers.py +51 -0
- automation/logger/__init__.py +0 -0
- automation/logger/alarms.py +426 -0
- automation/logger/core.py +265 -0
- automation/logger/datalogger.py +646 -0
- automation/logger/events.py +194 -0
- automation/logger/logdict.py +53 -0
- automation/logger/logs.py +203 -0
- automation/logger/machines.py +248 -0
- automation/logger/opcua_server.py +130 -0
- automation/logger/users.py +96 -0
- automation/managers/__init__.py +4 -0
- automation/managers/alarms.py +455 -0
- automation/managers/db.py +328 -0
- automation/managers/opcua_client.py +186 -0
- automation/managers/state_machine.py +183 -0
- automation/models.py +174 -0
- automation/modules/__init__.py +14 -0
- automation/modules/alarms/__init__.py +0 -0
- automation/modules/alarms/resources/__init__.py +10 -0
- automation/modules/alarms/resources/alarms.py +280 -0
- automation/modules/alarms/resources/summary.py +79 -0
- automation/modules/events/__init__.py +0 -0
- automation/modules/events/resources/__init__.py +10 -0
- automation/modules/events/resources/events.py +83 -0
- automation/modules/events/resources/logs.py +109 -0
- automation/modules/tags/__init__.py +0 -0
- automation/modules/tags/resources/__init__.py +8 -0
- automation/modules/tags/resources/tags.py +201 -0
- automation/modules/users/__init__.py +2 -0
- automation/modules/users/resources/__init__.py +10 -0
- automation/modules/users/resources/models/__init__.py +2 -0
- automation/modules/users/resources/models/roles.py +5 -0
- automation/modules/users/resources/models/users.py +14 -0
- automation/modules/users/resources/roles.py +38 -0
- automation/modules/users/resources/users.py +113 -0
- automation/modules/users/roles.py +121 -0
- automation/modules/users/users.py +335 -0
- automation/opcua/__init__.py +1 -0
- automation/opcua/models.py +541 -0
- automation/opcua/subscription.py +259 -0
- automation/pages/__init__.py +0 -0
- automation/pages/alarms.py +34 -0
- automation/pages/alarms_history.py +21 -0
- automation/pages/assets/styles.css +7 -0
- automation/pages/callbacks/__init__.py +28 -0
- automation/pages/callbacks/alarms.py +218 -0
- automation/pages/callbacks/alarms_summary.py +20 -0
- automation/pages/callbacks/db.py +222 -0
- automation/pages/callbacks/filter.py +238 -0
- automation/pages/callbacks/machines.py +29 -0
- automation/pages/callbacks/machines_detailed.py +581 -0
- automation/pages/callbacks/opcua.py +266 -0
- automation/pages/callbacks/opcua_server.py +244 -0
- automation/pages/callbacks/tags.py +495 -0
- automation/pages/callbacks/trends.py +119 -0
- automation/pages/communications.py +129 -0
- automation/pages/components/__init__.py +123 -0
- automation/pages/components/alarms.py +151 -0
- automation/pages/components/alarms_summary.py +45 -0
- automation/pages/components/database.py +128 -0
- automation/pages/components/gaussian_filter.py +69 -0
- automation/pages/components/machines.py +396 -0
- automation/pages/components/opcua.py +384 -0
- automation/pages/components/opcua_server.py +53 -0
- automation/pages/components/tags.py +253 -0
- automation/pages/components/trends.py +66 -0
- automation/pages/database.py +26 -0
- automation/pages/filter.py +55 -0
- automation/pages/machines.py +20 -0
- automation/pages/machines_detailed.py +41 -0
- automation/pages/main.py +63 -0
- automation/pages/opcua_server.py +28 -0
- automation/pages/tags.py +40 -0
- automation/pages/trends.py +35 -0
- automation/singleton.py +30 -0
- automation/state_machine.py +1672 -0
- automation/tags/__init__.py +2 -0
- automation/tags/cvt.py +1198 -0
- automation/tags/filter.py +55 -0
- automation/tags/tag.py +418 -0
- automation/tests/__init__.py +10 -0
- automation/tests/test_alarms.py +110 -0
- automation/tests/test_core.py +257 -0
- automation/tests/test_unit.py +21 -0
- automation/tests/test_user.py +155 -0
- automation/utils/__init__.py +164 -0
- automation/utils/decorators.py +222 -0
- automation/utils/npw.py +294 -0
- automation/utils/observer.py +21 -0
- automation/utils/units.py +118 -0
- automation/variables/__init__.py +55 -0
- automation/variables/adimentional.py +30 -0
- automation/variables/current.py +71 -0
- automation/variables/density.py +115 -0
- automation/variables/eng_time.py +68 -0
- automation/variables/force.py +90 -0
- automation/variables/length.py +104 -0
- automation/variables/mass.py +80 -0
- automation/variables/mass_flow.py +101 -0
- automation/variables/percentage.py +30 -0
- automation/variables/power.py +113 -0
- automation/variables/pressure.py +93 -0
- automation/variables/temperature.py +168 -0
- automation/variables/volume.py +70 -0
- automation/variables/volumetric_flow.py +100 -0
- automation/workers/__init__.py +2 -0
- automation/workers/logger.py +164 -0
- automation/workers/state_machine.py +207 -0
- automation/workers/worker.py +36 -0
- pyautomationio-0.0.0.dist-info/METADATA +198 -0
- pyautomationio-0.0.0.dist-info/RECORD +138 -0
- pyautomationio-0.0.0.dist-info/WHEEL +5 -0
- pyautomationio-0.0.0.dist-info/licenses/LICENSE +21 -0
- 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,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,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
|