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
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from .core import BaseModel, proxy
|
|
2
|
+
from .tags import (
|
|
3
|
+
Manufacturer,
|
|
4
|
+
Segment,
|
|
5
|
+
Tags,
|
|
6
|
+
TagValue,
|
|
7
|
+
Variables,
|
|
8
|
+
Units,
|
|
9
|
+
DataTypes
|
|
10
|
+
)
|
|
11
|
+
from .alarms import (
|
|
12
|
+
AlarmStates,
|
|
13
|
+
AlarmTypes,
|
|
14
|
+
Alarms,
|
|
15
|
+
AlarmSummary
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from .opcua import OPCUA
|
|
19
|
+
from .users import Roles, Users
|
|
20
|
+
from .events import Events
|
|
21
|
+
from .logs import Logs
|
|
22
|
+
from .machines import Machines, TagsMachines
|
|
23
|
+
from .opcua_server import AccessType, OPCUAServer
|
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
import pytz
|
|
2
|
+
from peewee import CharField, FloatField, ForeignKeyField, TimestampField
|
|
3
|
+
from ..dbmodels.core import BaseModel
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from .tags import Tags
|
|
6
|
+
from ..alarms.states import States
|
|
7
|
+
from ..tags.cvt import CVTEngine
|
|
8
|
+
|
|
9
|
+
tag_engine = CVTEngine()
|
|
10
|
+
|
|
11
|
+
class AlarmTypes(BaseModel):
|
|
12
|
+
|
|
13
|
+
name = CharField(unique=True) # high-high , high , bool , low , low-low
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def create(cls, name:str)-> dict:
|
|
17
|
+
r"""
|
|
18
|
+
You can use Model.create() to create a new model instance. This method accepts keyword arguments, where the keys correspond
|
|
19
|
+
to the names of the model's fields. A new instance is returned and a row is added to the table.
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
>>> AlarmsType.create(name='High-High')
|
|
23
|
+
{
|
|
24
|
+
'message': (str)
|
|
25
|
+
'data': (dict) {
|
|
26
|
+
'name': 'HIGH-HIGH'
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This will INSERT a new row into the database. The primary key will automatically be retrieved and stored on the model instance.
|
|
32
|
+
|
|
33
|
+
**Parameters**
|
|
34
|
+
|
|
35
|
+
* **name:** (str), Industrial protocol name
|
|
36
|
+
|
|
37
|
+
**Returns**
|
|
38
|
+
|
|
39
|
+
* **result:** (dict) --> {'message': (str), 'data': (dict) row serialized}
|
|
40
|
+
|
|
41
|
+
"""
|
|
42
|
+
result = dict()
|
|
43
|
+
data = dict()
|
|
44
|
+
name = name.upper()
|
|
45
|
+
|
|
46
|
+
if not cls.name_exist(name):
|
|
47
|
+
|
|
48
|
+
query = cls(name=name)
|
|
49
|
+
query.save()
|
|
50
|
+
|
|
51
|
+
message = f"Alarm type {name} created successfully"
|
|
52
|
+
data.update(query.serialize())
|
|
53
|
+
|
|
54
|
+
result.update(
|
|
55
|
+
{
|
|
56
|
+
'message': message,
|
|
57
|
+
'data': data
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
return result
|
|
61
|
+
|
|
62
|
+
message = f"Alarm type {name} is already into database"
|
|
63
|
+
result.update(
|
|
64
|
+
{
|
|
65
|
+
'message': message,
|
|
66
|
+
'data': data
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
return result
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
def read_by_name(cls, name:str):
|
|
73
|
+
r"""
|
|
74
|
+
Get instance by its a name
|
|
75
|
+
|
|
76
|
+
**Parameters**
|
|
77
|
+
|
|
78
|
+
* **name:** (str) Alarm type name
|
|
79
|
+
|
|
80
|
+
**Returns**
|
|
81
|
+
|
|
82
|
+
* **bool:** If True, name exist into database
|
|
83
|
+
"""
|
|
84
|
+
return cls.get_or_none(name=name.upper())
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def name_exist(cls, name:str)->bool:
|
|
88
|
+
r"""
|
|
89
|
+
Verify is a name exist into database
|
|
90
|
+
|
|
91
|
+
**Parameters**
|
|
92
|
+
|
|
93
|
+
* **name:** (str) Alarm type name
|
|
94
|
+
|
|
95
|
+
**Returns**
|
|
96
|
+
|
|
97
|
+
* **bool:** If True, name exist into database
|
|
98
|
+
"""
|
|
99
|
+
query = cls.get_or_none(name=name.upper())
|
|
100
|
+
|
|
101
|
+
if query is not None:
|
|
102
|
+
|
|
103
|
+
return True
|
|
104
|
+
|
|
105
|
+
return False
|
|
106
|
+
|
|
107
|
+
def serialize(self)-> dict:
|
|
108
|
+
r"""
|
|
109
|
+
Serialize database record to a jsonable object
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
"id": self.id,
|
|
114
|
+
"name": self.name
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class AlarmStates(BaseModel):
|
|
119
|
+
r"""
|
|
120
|
+
Based on ISA 18.2
|
|
121
|
+
"""
|
|
122
|
+
name = CharField(unique=True)
|
|
123
|
+
mnemonic = CharField(max_length=20)
|
|
124
|
+
condition = CharField(max_length=20)
|
|
125
|
+
status = CharField(max_length=20)
|
|
126
|
+
|
|
127
|
+
@classmethod
|
|
128
|
+
def create(cls, name:str, mnemonic:str, condition:str, status:str)-> dict:
|
|
129
|
+
r"""
|
|
130
|
+
You can use Model.create() to create a new model instance. This method accepts keyword arguments, where the keys correspond
|
|
131
|
+
to the names of the model's fields. A new instance is returned and a row is added to the table.
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
>>> AlarmsType.create(name='Unacknowledged', mnemonic='UNACKED', description='Alarm unacknowledged')
|
|
135
|
+
{
|
|
136
|
+
'message': (str)
|
|
137
|
+
'data': (dict) {
|
|
138
|
+
'id': 1,
|
|
139
|
+
'name': 'unacknowledged',
|
|
140
|
+
'mnemonic': 'UNACKED',
|
|
141
|
+
'description': 'Alarm unacknowledged'
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
This will INSERT a new row into the database. The primary key will automatically be retrieved and stored on the model instance.
|
|
147
|
+
|
|
148
|
+
**Parameters**
|
|
149
|
+
|
|
150
|
+
* **name:** (str), Industrial protocol name
|
|
151
|
+
|
|
152
|
+
**Returns**
|
|
153
|
+
|
|
154
|
+
* **result:** (dict) --> {'message': (str), 'data': (dict) row serialized}
|
|
155
|
+
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
if not cls.name_exist(name):
|
|
159
|
+
|
|
160
|
+
query = cls(name=name, mnemonic=mnemonic, condition=condition, status=status)
|
|
161
|
+
query.save()
|
|
162
|
+
|
|
163
|
+
return query
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def read_by_name(cls, name:str)->bool:
|
|
167
|
+
r"""
|
|
168
|
+
Get instance by its a name
|
|
169
|
+
|
|
170
|
+
**Parameters**
|
|
171
|
+
|
|
172
|
+
* **name:** (str) Alarm type name
|
|
173
|
+
|
|
174
|
+
**Returns**
|
|
175
|
+
|
|
176
|
+
* **bool:** If True, name exist into database
|
|
177
|
+
"""
|
|
178
|
+
return cls.get_or_none(name=name)
|
|
179
|
+
|
|
180
|
+
@classmethod
|
|
181
|
+
def name_exist(cls, name:str)->bool:
|
|
182
|
+
r"""
|
|
183
|
+
Verify is a name exist into database
|
|
184
|
+
|
|
185
|
+
**Parameters**
|
|
186
|
+
|
|
187
|
+
* **name:** (str) Alarm type name
|
|
188
|
+
|
|
189
|
+
**Returns**
|
|
190
|
+
|
|
191
|
+
* **bool:** If True, name exist into database
|
|
192
|
+
"""
|
|
193
|
+
query = cls.get_or_none(name=name)
|
|
194
|
+
|
|
195
|
+
if query is not None:
|
|
196
|
+
|
|
197
|
+
return True
|
|
198
|
+
|
|
199
|
+
return False
|
|
200
|
+
|
|
201
|
+
def serialize(self)-> dict:
|
|
202
|
+
r"""
|
|
203
|
+
Serialize database record to a jsonable object
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
"id": self.id,
|
|
208
|
+
"name": self.name,
|
|
209
|
+
"mnemonic": self.mnemonic,
|
|
210
|
+
"condition": self.condition,
|
|
211
|
+
"status": self.status
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class Alarms(BaseModel):
|
|
216
|
+
|
|
217
|
+
identifier = CharField(unique=True)
|
|
218
|
+
name = CharField(unique=True, max_length=128)
|
|
219
|
+
tag = ForeignKeyField(Tags, backref='alarms')
|
|
220
|
+
trigger_type = ForeignKeyField(AlarmTypes, backref='alarms')
|
|
221
|
+
trigger_value = FloatField()
|
|
222
|
+
description = CharField(null=True, max_length=256)
|
|
223
|
+
state = ForeignKeyField(AlarmStates, backref='alarms')
|
|
224
|
+
timestamp = TimestampField(utc=True, null=True)
|
|
225
|
+
|
|
226
|
+
@classmethod
|
|
227
|
+
def create(
|
|
228
|
+
cls,
|
|
229
|
+
identifier:str,
|
|
230
|
+
name:str,
|
|
231
|
+
tag:str,
|
|
232
|
+
trigger_type:str,
|
|
233
|
+
trigger_value:float,
|
|
234
|
+
description:str=None,
|
|
235
|
+
state:str=States.NORM.value,
|
|
236
|
+
timestamp:datetime=None
|
|
237
|
+
):
|
|
238
|
+
r"""Documentation here
|
|
239
|
+
|
|
240
|
+
# Parameters
|
|
241
|
+
|
|
242
|
+
-
|
|
243
|
+
|
|
244
|
+
# Returns
|
|
245
|
+
|
|
246
|
+
-
|
|
247
|
+
"""
|
|
248
|
+
trigger_type = AlarmTypes.read_by_name(name=trigger_type)
|
|
249
|
+
tag = Tags.read_by_name(name=tag)
|
|
250
|
+
state = AlarmStates.read_by_name(name=state)
|
|
251
|
+
if not cls.name_exists(name):
|
|
252
|
+
|
|
253
|
+
alarm = super().create(
|
|
254
|
+
identifier=identifier,
|
|
255
|
+
name=name,
|
|
256
|
+
tag=tag,
|
|
257
|
+
trigger_type=trigger_type,
|
|
258
|
+
trigger_value=trigger_value,
|
|
259
|
+
description=description,
|
|
260
|
+
state=state,
|
|
261
|
+
timestamp=timestamp
|
|
262
|
+
)
|
|
263
|
+
alarm.save()
|
|
264
|
+
|
|
265
|
+
return alarm
|
|
266
|
+
|
|
267
|
+
@classmethod
|
|
268
|
+
def name_exists(cls, name:str)->bool|None:
|
|
269
|
+
r"""Documentation here
|
|
270
|
+
|
|
271
|
+
# Parameters
|
|
272
|
+
|
|
273
|
+
-
|
|
274
|
+
|
|
275
|
+
# Returns
|
|
276
|
+
|
|
277
|
+
-
|
|
278
|
+
"""
|
|
279
|
+
tag = cls.get_or_none(name=name)
|
|
280
|
+
if tag:
|
|
281
|
+
|
|
282
|
+
return True
|
|
283
|
+
|
|
284
|
+
@classmethod
|
|
285
|
+
def read(cls, id:str):
|
|
286
|
+
r"""Documentation here
|
|
287
|
+
|
|
288
|
+
# Parameters
|
|
289
|
+
|
|
290
|
+
-
|
|
291
|
+
|
|
292
|
+
# Returns
|
|
293
|
+
|
|
294
|
+
-
|
|
295
|
+
"""
|
|
296
|
+
return cls.get_or_none(id=id)
|
|
297
|
+
|
|
298
|
+
@classmethod
|
|
299
|
+
def read_by_identifier(cls, identifier:str):
|
|
300
|
+
r"""Documentation here
|
|
301
|
+
|
|
302
|
+
# Parameters
|
|
303
|
+
|
|
304
|
+
-
|
|
305
|
+
|
|
306
|
+
# Returns
|
|
307
|
+
|
|
308
|
+
-
|
|
309
|
+
"""
|
|
310
|
+
return cls.get_or_none(identifier=identifier)
|
|
311
|
+
|
|
312
|
+
@classmethod
|
|
313
|
+
def read_by_name(cls, name:str):
|
|
314
|
+
r"""Documentation here
|
|
315
|
+
|
|
316
|
+
# Parameters
|
|
317
|
+
|
|
318
|
+
-
|
|
319
|
+
|
|
320
|
+
# Returns
|
|
321
|
+
|
|
322
|
+
-
|
|
323
|
+
"""
|
|
324
|
+
return cls.get_or_none(name=name)
|
|
325
|
+
|
|
326
|
+
def serialize(self):
|
|
327
|
+
r"""Documentation here
|
|
328
|
+
|
|
329
|
+
# Parameters
|
|
330
|
+
|
|
331
|
+
-
|
|
332
|
+
|
|
333
|
+
# Returns
|
|
334
|
+
|
|
335
|
+
-
|
|
336
|
+
"""
|
|
337
|
+
timestamp = self.timestamp
|
|
338
|
+
if timestamp:
|
|
339
|
+
|
|
340
|
+
timestamp = timestamp.strftime(tag_engine.DATETIME_FORMAT)
|
|
341
|
+
|
|
342
|
+
return {
|
|
343
|
+
'identifier': self.identifier,
|
|
344
|
+
'name': self.name,
|
|
345
|
+
'tag': self.tag.name,
|
|
346
|
+
'alarm_type': self.trigger_type.name,
|
|
347
|
+
'trigger_value': self.trigger_value,
|
|
348
|
+
'description': self.description,
|
|
349
|
+
'state': self.state.name,
|
|
350
|
+
'timestamp': timestamp
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
class AlarmSummary(BaseModel):
|
|
355
|
+
|
|
356
|
+
alarm = ForeignKeyField(Alarms, backref='summary')
|
|
357
|
+
state = ForeignKeyField(AlarmStates, backref='summary')
|
|
358
|
+
alarm_time = TimestampField(utc=True)
|
|
359
|
+
ack_time = TimestampField(utc=True, null=True)
|
|
360
|
+
|
|
361
|
+
@classmethod
|
|
362
|
+
def create(cls, name:str, state:str, timestamp:datetime, ack_timestamp:datetime=None):
|
|
363
|
+
_alarm = Alarms.read_by_name(name=name)
|
|
364
|
+
_state = AlarmStates.read_by_name(name=state)
|
|
365
|
+
|
|
366
|
+
if _alarm:
|
|
367
|
+
|
|
368
|
+
if _state:
|
|
369
|
+
|
|
370
|
+
# Create record
|
|
371
|
+
query = cls(alarm=_alarm.id, state=_state.id, alarm_time=timestamp, ack_time=ack_timestamp)
|
|
372
|
+
query.save()
|
|
373
|
+
|
|
374
|
+
return query
|
|
375
|
+
|
|
376
|
+
@classmethod
|
|
377
|
+
def read_by_name(cls, name:str)->bool:
|
|
378
|
+
r"""
|
|
379
|
+
Get instance by its a name
|
|
380
|
+
|
|
381
|
+
**Parameters**
|
|
382
|
+
|
|
383
|
+
* **name:** (str) Alarm type name
|
|
384
|
+
|
|
385
|
+
**Returns**
|
|
386
|
+
|
|
387
|
+
* **bool:** If True, name exist into database
|
|
388
|
+
"""
|
|
389
|
+
alarm = Alarms.read_by_name(name=name)
|
|
390
|
+
return cls.select().where(cls.alarm==alarm).order_by(cls.id.desc()).get_or_none()
|
|
391
|
+
|
|
392
|
+
@classmethod
|
|
393
|
+
def read_by_alarm_id(cls, alarm_id:int)->bool:
|
|
394
|
+
r"""
|
|
395
|
+
Get instance by its a name
|
|
396
|
+
|
|
397
|
+
**Parameters**
|
|
398
|
+
|
|
399
|
+
* **name:** (str) Alarm type name
|
|
400
|
+
|
|
401
|
+
**Returns**
|
|
402
|
+
|
|
403
|
+
* **bool:** If True, name exist into database
|
|
404
|
+
"""
|
|
405
|
+
alarm = Alarms.read(id=alarm_id)
|
|
406
|
+
return cls.select().where(cls.alarm==alarm).order_by(cls.id.desc()).get_or_none()
|
|
407
|
+
|
|
408
|
+
@classmethod
|
|
409
|
+
def read_all(cls):
|
|
410
|
+
r"""
|
|
411
|
+
Select all records
|
|
412
|
+
|
|
413
|
+
You can use this method to retrieve all instances matching in the database.
|
|
414
|
+
|
|
415
|
+
This method is a shortcut that calls Model.select() with the given query.
|
|
416
|
+
|
|
417
|
+
**Parameters**
|
|
418
|
+
|
|
419
|
+
**Returns**
|
|
420
|
+
|
|
421
|
+
* **result:** (dict) --> {'message': (str), 'data': (list) row serialized}
|
|
422
|
+
"""
|
|
423
|
+
data = list()
|
|
424
|
+
|
|
425
|
+
try:
|
|
426
|
+
data = [query.serialize() for query in cls.select().order_by(cls.id.desc())]
|
|
427
|
+
|
|
428
|
+
return data
|
|
429
|
+
|
|
430
|
+
except Exception as _err:
|
|
431
|
+
|
|
432
|
+
return data
|
|
433
|
+
|
|
434
|
+
@classmethod
|
|
435
|
+
def read_lasts(cls, lasts:int=1):
|
|
436
|
+
r"""
|
|
437
|
+
Documentation here
|
|
438
|
+
"""
|
|
439
|
+
alarms = cls.select().order_by(cls.id.desc()).limit(lasts)
|
|
440
|
+
|
|
441
|
+
return [alarm.serialize() for alarm in alarms]
|
|
442
|
+
|
|
443
|
+
@classmethod
|
|
444
|
+
def filter_by(
|
|
445
|
+
cls,
|
|
446
|
+
states:list[str]=None,
|
|
447
|
+
names:list[str]=None,
|
|
448
|
+
tags:list[str]=None,
|
|
449
|
+
greater_than_timestamp:datetime=None,
|
|
450
|
+
less_than_timestamp:datetime=None,
|
|
451
|
+
timezone:str='UTC'
|
|
452
|
+
):
|
|
453
|
+
r"""
|
|
454
|
+
Documentation here
|
|
455
|
+
"""
|
|
456
|
+
_timezone = pytz.timezone(timezone)
|
|
457
|
+
query = cls.select()
|
|
458
|
+
|
|
459
|
+
if states:
|
|
460
|
+
subquery = AlarmStates.select(AlarmStates.id).where(AlarmStates.name.in_(states))
|
|
461
|
+
query = query.join(AlarmStates).where(AlarmStates.id.in_(subquery))
|
|
462
|
+
|
|
463
|
+
if names:
|
|
464
|
+
subquery = Alarms.select(Alarms.id).where(Alarms.name.in_(names))
|
|
465
|
+
query = query.join(Alarms).where(Alarms.id.in_(subquery))
|
|
466
|
+
|
|
467
|
+
if tags:
|
|
468
|
+
subquery = Tags.select(Tags.id).where(Tags.name.in_(tags))
|
|
469
|
+
subquery = Alarms.select(Alarms.id).join(Tags).where(Tags.id.in_(subquery))
|
|
470
|
+
query = query.join(Alarms).where(Alarms.id.in_(subquery))
|
|
471
|
+
|
|
472
|
+
if greater_than_timestamp:
|
|
473
|
+
greater_than_timestamp = _timezone.localize(datetime.strptime(greater_than_timestamp, '%Y-%m-%d %H:%M:%S.%f')).astimezone(pytz.UTC)
|
|
474
|
+
query = query.where(cls.alarm_time > greater_than_timestamp)
|
|
475
|
+
|
|
476
|
+
if less_than_timestamp:
|
|
477
|
+
less_than_timestamp = _timezone.localize(datetime.strptime(less_than_timestamp, '%Y-%m-%d %H:%M:%S.%f')).astimezone(pytz.UTC)
|
|
478
|
+
query = query.where(cls.alarm_time < less_than_timestamp)
|
|
479
|
+
|
|
480
|
+
query = query.order_by(cls.id.desc())
|
|
481
|
+
if not query.exists():
|
|
482
|
+
|
|
483
|
+
return []
|
|
484
|
+
|
|
485
|
+
return [alarm.serialize() for alarm in query]
|
|
486
|
+
|
|
487
|
+
@classmethod
|
|
488
|
+
def get_alarm_summary_comments(cls, id:int):
|
|
489
|
+
r"""
|
|
490
|
+
Documentation here
|
|
491
|
+
"""
|
|
492
|
+
query = cls.read(id=id)
|
|
493
|
+
|
|
494
|
+
return [comment.serialize() for comment in query.logs]
|
|
495
|
+
|
|
496
|
+
def serialize(self):
|
|
497
|
+
r"""
|
|
498
|
+
Documentation here
|
|
499
|
+
"""
|
|
500
|
+
from .. import TIMEZONE
|
|
501
|
+
|
|
502
|
+
ack_time = None
|
|
503
|
+
if self.ack_time:
|
|
504
|
+
ack_time = self.ack_time
|
|
505
|
+
ack_time = pytz.UTC.localize(ack_time).astimezone(TIMEZONE)
|
|
506
|
+
ack_time = ack_time.strftime(tag_engine.DATETIME_FORMAT)
|
|
507
|
+
|
|
508
|
+
alarm_time = self.alarm_time
|
|
509
|
+
alarm_time = pytz.UTC.localize(alarm_time).astimezone(TIMEZONE)
|
|
510
|
+
alarm_time = alarm_time.strftime(tag_engine.DATETIME_FORMAT)
|
|
511
|
+
|
|
512
|
+
return {
|
|
513
|
+
'id': self.id,
|
|
514
|
+
'name': self.alarm.name,
|
|
515
|
+
'tag': self.alarm.tag.name,
|
|
516
|
+
'description': self.alarm.description,
|
|
517
|
+
'state': self.state.name,
|
|
518
|
+
'mnemonic': self.state.mnemonic,
|
|
519
|
+
'status': self.state.status,
|
|
520
|
+
'alarm_time': alarm_time,
|
|
521
|
+
'ack_time': ack_time,
|
|
522
|
+
'has_comments': True if self.logs else False
|
|
523
|
+
}
|
|
524
|
+
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from peewee import Proxy, Model
|
|
2
|
+
|
|
3
|
+
proxy = Proxy()
|
|
4
|
+
|
|
5
|
+
SQLITE = 'sqlite'
|
|
6
|
+
MYSQL = 'mysql'
|
|
7
|
+
POSTGRESQL = 'postgresql'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BaseModel(Model):
|
|
11
|
+
|
|
12
|
+
@classmethod
|
|
13
|
+
def read(cls, id:int|str):
|
|
14
|
+
r"""
|
|
15
|
+
Select a single record
|
|
16
|
+
|
|
17
|
+
You can use this method to retrieve a single instance matching the given query.
|
|
18
|
+
|
|
19
|
+
This method is a shortcut that calls Model.select() with the given query, but limits the result set to a single row.
|
|
20
|
+
Additionally, if no model matches the given query, a DoesNotExist exception will be raised.
|
|
21
|
+
|
|
22
|
+
**Parameters**
|
|
23
|
+
|
|
24
|
+
* **id:** (int), Record ID
|
|
25
|
+
|
|
26
|
+
**Returns**
|
|
27
|
+
|
|
28
|
+
* **result:** (dict) --> {'message': (str), 'data': (list) row serialized}
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
query = cls.select().where(cls.id == id).get_or_none()
|
|
32
|
+
|
|
33
|
+
if query:
|
|
34
|
+
|
|
35
|
+
return query
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def read_all(cls):
|
|
39
|
+
r"""
|
|
40
|
+
Select all records
|
|
41
|
+
|
|
42
|
+
You can use this method to retrieve all instances matching in the database.
|
|
43
|
+
|
|
44
|
+
This method is a shortcut that calls Model.select() with the given query.
|
|
45
|
+
|
|
46
|
+
**Parameters**
|
|
47
|
+
|
|
48
|
+
**Returns**
|
|
49
|
+
|
|
50
|
+
* **result:** (dict) --> {'message': (str), 'data': (list) row serialized}
|
|
51
|
+
"""
|
|
52
|
+
data = [query.serialize() for query in cls.select()]
|
|
53
|
+
|
|
54
|
+
return data
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def put(cls, id:str, **fields):
|
|
58
|
+
r""""
|
|
59
|
+
Update a single record
|
|
60
|
+
|
|
61
|
+
Once a model instance has a primary key, you UPDATE a field by its id.
|
|
62
|
+
The model's primary key will not change:
|
|
63
|
+
"""
|
|
64
|
+
if cls.id_exists(id):
|
|
65
|
+
|
|
66
|
+
query = cls.update(**fields).where(cls.id == id)
|
|
67
|
+
query.execute()
|
|
68
|
+
return query
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def id_exists(cls, id:str|int)->bool|None:
|
|
72
|
+
r"""
|
|
73
|
+
Verify if a record exist by its id
|
|
74
|
+
|
|
75
|
+
**Parameters**
|
|
76
|
+
|
|
77
|
+
* **id:** (int) Record ID
|
|
78
|
+
|
|
79
|
+
**Returns**
|
|
80
|
+
|
|
81
|
+
* **bool:** If True, so id record exist into database
|
|
82
|
+
"""
|
|
83
|
+
return True if cls.get_or_none(id=id) else False
|
|
84
|
+
|
|
85
|
+
class Meta:
|
|
86
|
+
database = proxy
|