PyAutomationIO 1.1.1__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 +1792 -0
  7. automation/dbmodels/__init__.py +23 -0
  8. automation/dbmodels/alarms.py +549 -0
  9. automation/dbmodels/core.py +86 -0
  10. automation/dbmodels/events.py +178 -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 +434 -0
  27. automation/logger/core.py +265 -0
  28. automation/logger/datalogger.py +877 -0
  29. automation/logger/events.py +202 -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 +81 -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 +85 -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 +254 -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 +1674 -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-1.1.1.dist-info/METADATA +199 -0
  135. pyautomationio-1.1.1.dist-info/RECORD +138 -0
  136. pyautomationio-1.1.1.dist-info/WHEEL +5 -0
  137. pyautomationio-1.1.1.dist-info/licenses/LICENSE +21 -0
  138. pyautomationio-1.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,921 @@
1
+ from peewee import CharField, BooleanField, FloatField, ForeignKeyField, IntegerField, TimestampField, BooleanField
2
+ from .core import BaseModel
3
+ from datetime import datetime
4
+
5
+
6
+ class Manufacturer(BaseModel):
7
+
8
+ name = CharField(unique=True)
9
+
10
+ @classmethod
11
+ def create(cls, name:str)-> dict:
12
+ r"""
13
+
14
+ """
15
+ if not cls.name_exist(name):
16
+
17
+ query = cls(name=name)
18
+ query.save()
19
+
20
+ return query
21
+
22
+ @classmethod
23
+ def read_by_name(cls, name:str)->bool:
24
+ r"""
25
+ Get instance by its a name
26
+
27
+ **Parameters**
28
+
29
+ * **name:** (str) Variable name
30
+
31
+ **Returns**
32
+
33
+ * **bool:** If True, name exist into database
34
+ """
35
+ query = cls.get_or_none(name=name)
36
+
37
+ if query is not None:
38
+
39
+ return query
40
+
41
+ return None
42
+
43
+ @classmethod
44
+ def name_exist(cls, name:str)->bool:
45
+ r"""
46
+ Verify is a name exist into database
47
+
48
+ **Parameters**
49
+
50
+ * **name:** (str) Variable name
51
+
52
+ **Returns**
53
+
54
+ * **bool:** If True, name exist into database
55
+ """
56
+ query = cls.get_or_none(name=name)
57
+
58
+ if query is not None:
59
+
60
+ return True
61
+
62
+ return False
63
+
64
+ def serialize(self)-> dict:
65
+ r"""
66
+ Serialize database record to a jsonable object
67
+ """
68
+
69
+ return {
70
+ "id": self.id,
71
+ "name": self.name
72
+ }
73
+
74
+
75
+ class Segment(BaseModel):
76
+
77
+ name = CharField()
78
+ manufacturer = ForeignKeyField(Manufacturer, backref='segments')
79
+
80
+ @classmethod
81
+ def create(cls, name:str, manufacturer:str)-> dict:
82
+ r"""Documentation here
83
+ """
84
+ if Manufacturer.name_exist(name=manufacturer):
85
+
86
+ manufacturer_obj = Manufacturer.read_by_name(name=manufacturer)
87
+
88
+ else:
89
+
90
+ manufacturer_obj = Manufacturer.create(name=manufacturer)
91
+
92
+ segment_obj = Segment.select().where(Segment.name == name, Segment.manufacturer == manufacturer_obj).exists()
93
+
94
+ if not segment_obj:
95
+ query = cls(name=name, manufacturer=manufacturer_obj)
96
+ query.save()
97
+ return query
98
+
99
+ return Segment.read_by_name(name=name)
100
+
101
+ @classmethod
102
+ def read_by_name(cls, name:str)->bool:
103
+ r"""
104
+
105
+ """
106
+ query = cls.get_or_none(name=name)
107
+
108
+ if query is not None:
109
+
110
+ return query
111
+
112
+ return None
113
+
114
+ @classmethod
115
+ def name_exist(cls, name:str)->bool:
116
+ r"""
117
+
118
+ """
119
+ query = cls.get_or_none(name=name)
120
+
121
+ if query is not None:
122
+
123
+ return True
124
+
125
+ return False
126
+
127
+ def serialize(self)-> dict:
128
+ r"""
129
+ Serialize database record to a jsonable object
130
+ """
131
+
132
+ return {
133
+ "id": self.id,
134
+ "name": self.name,
135
+ "manufacturer": self.manufacturer.serialize()
136
+ }
137
+
138
+
139
+ class Variables(BaseModel):
140
+
141
+ name = CharField(unique=True)
142
+
143
+ @classmethod
144
+ def create(cls, name:str)-> dict:
145
+ r"""
146
+ You can use Model.create() to create a new model instance. This method accepts keyword arguments, where the keys correspond
147
+ to the names of the model's fields. A new instance is returned and a row is added to the table.
148
+
149
+ ```python
150
+ >>> Variables.create(name='Pressure')
151
+ {
152
+ 'message': (str)
153
+ 'data': (dict) {
154
+ 'name': 'pressure'
155
+ }
156
+ }
157
+ ```
158
+
159
+ This will INSERT a new row into the database. The primary key will automatically be retrieved and stored on the model instance.
160
+
161
+ **Parameters**
162
+
163
+ * **name:** (str), Industrial protocol name
164
+
165
+ **Returns**
166
+
167
+ * **result:** (dict) --> {'message': (str), 'data': (dict) row serialized}
168
+
169
+ """
170
+ result = dict()
171
+ data = dict()
172
+
173
+ if not cls.name_exist(name):
174
+
175
+ query = cls(name=name)
176
+ query.save()
177
+
178
+ message = f"{name} variable created successfully"
179
+ data.update(query.serialize())
180
+
181
+ result.update(
182
+ {
183
+ 'message': message,
184
+ 'data': data
185
+ }
186
+ )
187
+ return result
188
+
189
+ message = f"{name} variable is already into database"
190
+ result.update(
191
+ {
192
+ 'message': message,
193
+ 'data': data
194
+ }
195
+ )
196
+ return result
197
+
198
+ @classmethod
199
+ def read_by_name(cls, name:str)->bool:
200
+ r"""
201
+ Get instance by its a name
202
+
203
+ **Parameters**
204
+
205
+ * **name:** (str) Variable name
206
+
207
+ **Returns**
208
+
209
+ * **bool:** If True, name exist into database
210
+ """
211
+ query = cls.get_or_none(name=name)
212
+
213
+ if query is not None:
214
+
215
+ return query
216
+
217
+ return None
218
+
219
+ @classmethod
220
+ def name_exist(cls, name:str)->bool:
221
+ r"""
222
+ Verify is a name exist into database
223
+
224
+ **Parameters**
225
+
226
+ * **name:** (str) Variable name
227
+
228
+ **Returns**
229
+
230
+ * **bool:** If True, name exist into database
231
+ """
232
+ query = cls.get_or_none(name=name)
233
+
234
+ if query is not None:
235
+
236
+ return True
237
+
238
+ return False
239
+
240
+ def serialize(self)-> dict:
241
+ r"""
242
+ Serialize database record to a jsonable object
243
+ """
244
+
245
+ return {
246
+ "id": self.id,
247
+ "name": self.name
248
+ }
249
+
250
+
251
+ class Units(BaseModel):
252
+
253
+ name = CharField(unique=True)
254
+ unit = CharField(unique=True)
255
+ variable_id = ForeignKeyField(Variables, backref='units', on_delete='CASCADE')
256
+
257
+ @classmethod
258
+ def create(cls, name:str, unit:str, variable:str)-> dict:
259
+ r"""
260
+ You can use Model.create() to create a new model instance. This method accepts keyword arguments, where the keys correspond
261
+ to the names of the model's fields. A new instance is returned and a row is added to the table.
262
+
263
+ ```python
264
+ >>> Variables.create(name='Pa', variable='Pressure')
265
+ {
266
+ 'message': (str)
267
+ 'data': (dict) {
268
+ 'id': 1,
269
+ 'name': 'Pa',
270
+ 'variable': 'pressure'
271
+ }
272
+ }
273
+ ```
274
+
275
+ This will INSERT a new row into the database. The primary key will automatically be retrieved and stored on the model instance.
276
+
277
+ **Parameters**
278
+
279
+ * **name:** (str), Industrial protocol name
280
+
281
+ **Returns**
282
+
283
+ * **result:** (dict) --> {'message': (str), 'data': (dict) row serialized}
284
+
285
+ """
286
+ result = dict()
287
+ data = dict()
288
+ name = name
289
+
290
+ if not cls.name_exist(name):
291
+
292
+ query_variable = Variables.read_by_name(variable)
293
+
294
+ if query_variable is not None:
295
+
296
+ variable_id = query_variable
297
+
298
+ query = cls(name=name, unit=unit, variable_id=variable_id)
299
+ query.save()
300
+
301
+ message = f"{name} unit created successfully"
302
+ data.update(query.serialize())
303
+
304
+ result.update(
305
+ {
306
+ 'message': message,
307
+ 'data': data
308
+ }
309
+ )
310
+ return result
311
+
312
+
313
+ message = f"{variable} variable not exist into database"
314
+
315
+ result.update(
316
+ {
317
+ 'message': message,
318
+ 'data': data
319
+ }
320
+ )
321
+ return result
322
+
323
+ message = f"{name} unit is already into database"
324
+ result.update(
325
+ {
326
+ 'message': message,
327
+ 'data': data
328
+ }
329
+ )
330
+ return result
331
+
332
+ @classmethod
333
+ def read_by_name(cls, name:str)->bool:
334
+ r"""
335
+ Get instance by its a name
336
+
337
+ **Parameters**
338
+
339
+ * **name:** (str) Variable name
340
+
341
+ **Returns**
342
+
343
+ * **bool:** If True, name exist into database
344
+ """
345
+ query = cls.get_or_none(name=name)
346
+
347
+ if query is not None:
348
+
349
+ return query.serialize()
350
+
351
+ return None
352
+
353
+ @classmethod
354
+ def read_by_unit(cls, unit:str)->bool:
355
+ r"""
356
+ Get instance by its a name
357
+
358
+ **Parameters**
359
+
360
+ * **name:** (str) Variable name
361
+
362
+ **Returns**
363
+
364
+ * **bool:** If True, name exist into database
365
+ """
366
+ query = cls.get_or_none(unit=unit)
367
+
368
+ if query is not None:
369
+
370
+ return query
371
+
372
+ return None
373
+
374
+ @classmethod
375
+ def read_by_unit(cls, unit:str)->bool:
376
+ r"""
377
+ Get instance by its a name
378
+
379
+ **Parameters**
380
+
381
+ * **name:** (str) Variable name
382
+
383
+ **Returns**
384
+
385
+ * **bool:** If True, name exist into database
386
+ """
387
+ query = cls.get_or_none(unit=unit)
388
+
389
+ if query is not None:
390
+
391
+ return query
392
+
393
+ return None
394
+
395
+ @classmethod
396
+ def name_exist(cls, name:str)->bool:
397
+ r"""
398
+ Verify is a name exist into database
399
+
400
+ **Parameters**
401
+
402
+ * **name:** (str) Variable name
403
+
404
+ **Returns**
405
+
406
+ * **bool:** If True, name exist into database
407
+ """
408
+ query = cls.get_or_none(name=name)
409
+
410
+ if query is not None:
411
+
412
+ return True
413
+
414
+ return False
415
+
416
+ def serialize(self)-> dict:
417
+ r"""
418
+ Serialize database record to a jsonable object
419
+ """
420
+
421
+ return {
422
+ "id": self.id,
423
+ "name": self.name,
424
+ "variable": self.variable_id.name,
425
+ "unit": self.unit
426
+ }
427
+
428
+
429
+ class DataTypes(BaseModel):
430
+
431
+ name = CharField(unique=True)
432
+
433
+ @classmethod
434
+ def create(cls, name:str)-> dict:
435
+ r"""
436
+ You can use Model.create() to create a new model instance. This method accepts keyword arguments, where the keys correspond
437
+ to the names of the model's fields. A new instance is returned and a row is added to the table.
438
+
439
+ ```python
440
+ >>> Variables.create(name='Pressure')
441
+ {
442
+ 'message': (str)
443
+ 'data': (dict) {
444
+ 'name': 'pressure'
445
+ }
446
+ }
447
+ ```
448
+
449
+ This will INSERT a new row into the database. The primary key will automatically be retrieved and stored on the model instance.
450
+
451
+ **Parameters**
452
+
453
+ * **name:** (str), Industrial protocol name
454
+
455
+ **Returns**
456
+
457
+ * **result:** (dict) --> {'message': (str), 'data': (dict) row serialized}
458
+
459
+ """
460
+ result = dict()
461
+ data = dict()
462
+
463
+ if not cls.name_exist(name):
464
+
465
+ query = cls(name=name)
466
+ query.save()
467
+
468
+ message = f"{name} DataType created successfully"
469
+ data.update(query.serialize())
470
+
471
+ result.update(
472
+ {
473
+ 'message': message,
474
+ 'data': data
475
+ }
476
+ )
477
+ return result
478
+
479
+ message = f"{name} DataType is already into database"
480
+ result.update(
481
+ {
482
+ 'message': message,
483
+ 'data': data
484
+ }
485
+ )
486
+ return result
487
+
488
+ @classmethod
489
+ def read_by_name(cls, name:str)->bool:
490
+ r"""
491
+ Get instance by its a name
492
+
493
+ **Parameters**
494
+
495
+ * **name:** (str) Variable name
496
+
497
+ **Returns**
498
+
499
+ * **bool:** If True, name exist into database
500
+ """
501
+ query = cls.get_or_none(name=name)
502
+
503
+ if query is not None:
504
+
505
+ return query
506
+
507
+ return None
508
+
509
+ @classmethod
510
+ def name_exist(cls, name:str)->bool:
511
+ r"""
512
+ Verify is a name exist into database
513
+
514
+ **Parameters**
515
+
516
+ * **name:** (str) Variable name
517
+
518
+ **Returns**
519
+
520
+ * **bool:** If True, name exist into database
521
+ """
522
+ query = cls.get_or_none(name=name)
523
+
524
+ if query is not None:
525
+
526
+ return True
527
+
528
+ return False
529
+
530
+ def serialize(self)-> dict:
531
+ r"""
532
+ Serialize database record to a jsonable object
533
+ """
534
+
535
+ return {
536
+ "id": self.id,
537
+ "name": self.name
538
+ }
539
+
540
+
541
+ class Tags(BaseModel):
542
+
543
+ identifier = CharField(unique=True)
544
+ name = CharField(unique=True)
545
+ unit = ForeignKeyField(Units, backref='tags')
546
+ data_type = ForeignKeyField(DataTypes, backref='tags')
547
+ segment = ForeignKeyField(Segment, backref='tags', null=True)
548
+ description = CharField(null=True, max_length=256)
549
+ display_name = CharField(unique=True)
550
+ display_unit = ForeignKeyField(Units)
551
+ opcua_address = CharField(null=True)
552
+ node_namespace = CharField(null=True)
553
+ scan_time = IntegerField(null=True)
554
+ dead_band = FloatField(null=True)
555
+ active = BooleanField(default=True)
556
+ process_filter = BooleanField(default=False)
557
+ gaussian_filter = BooleanField(default=False)
558
+ gaussian_filter_threshold = FloatField(default=1.0)
559
+ gaussian_filter_r_value = FloatField(default=0.0)
560
+ out_of_range_detection = BooleanField(default=False)
561
+ outlier_detection = BooleanField(default=False)
562
+ frozen_data_detection = BooleanField(default=False)
563
+
564
+ @classmethod
565
+ def create(
566
+ cls,
567
+ id:str,
568
+ name:str,
569
+ unit:str,
570
+ data_type:str,
571
+ description:str,
572
+ display_name:str,
573
+ display_unit:str,
574
+ opcua_address:str="",
575
+ node_namespace:str="",
576
+ segment:str="",
577
+ manufacturer:str="",
578
+ scan_time:int=0,
579
+ dead_band:float=0.0,
580
+ active:bool=True,
581
+ process_filter:bool=False,
582
+ gaussian_filter:bool=False,
583
+ gaussian_filter_threshold:float=1.0,
584
+ gaussian_filter_r_value:float=0.0,
585
+ out_of_range_detection:bool=False,
586
+ outlier_detection:bool=False,
587
+ frozen_data_detection:bool=False
588
+ ):
589
+ r"""
590
+ Documentation here
591
+ """
592
+ result = dict()
593
+ message = f"{name} already exist into database"
594
+ data = dict()
595
+ _unit = Units.read_by_unit(unit=unit)
596
+ _display_unit = Units.read_by_unit(unit=display_unit)
597
+ _data_type = DataTypes.read_by_name(name=data_type)
598
+
599
+ if not cls.name_exist(name):
600
+
601
+ if not cls.display_name_exist(name):
602
+
603
+ if _unit is not None and _display_unit is not None:
604
+
605
+ if _data_type is not None:
606
+
607
+ if segment and manufacturer:
608
+
609
+ segment_obj = Segment.create(name=segment, manufacturer=manufacturer)
610
+
611
+ if not segment_obj:
612
+
613
+ result.update(
614
+ {
615
+ 'message': f"Duplicated {manufacturer}->{segment}",
616
+ 'data': data
617
+ }
618
+ )
619
+
620
+ return result
621
+
622
+
623
+ query = cls(
624
+ identifier=id,
625
+ name=name,
626
+ unit=_unit,
627
+ data_type=_data_type,
628
+ description=description,
629
+ display_name=display_name,
630
+ display_unit=_display_unit,
631
+ opcua_address=opcua_address,
632
+ node_namespace=node_namespace,
633
+ scan_time=scan_time,
634
+ dead_band=dead_band,
635
+ active=active,
636
+ process_filter=process_filter,
637
+ gaussian_filter=gaussian_filter,
638
+ gaussian_filter_threshold=gaussian_filter_threshold,
639
+ gaussian_filter_r_value=gaussian_filter_r_value,
640
+ out_of_range_detection=out_of_range_detection,
641
+ outlier_detection=outlier_detection,
642
+ frozen_data_detection=frozen_data_detection,
643
+ segment=segment_obj
644
+ )
645
+ else:
646
+ query = cls(
647
+ identifier=id,
648
+ name=name,
649
+ unit=_unit,
650
+ data_type=_data_type,
651
+ description=description,
652
+ display_name=display_name,
653
+ display_unit=_display_unit,
654
+ opcua_address=opcua_address,
655
+ node_namespace=node_namespace,
656
+ scan_time=scan_time,
657
+ dead_band=dead_band,
658
+ active=active,
659
+ process_filter=process_filter,
660
+ gaussian_filter=gaussian_filter,
661
+ gaussian_filter_threshold=gaussian_filter_threshold,
662
+ gaussian_filter_r_value=gaussian_filter_r_value,
663
+ out_of_range_detection=out_of_range_detection,
664
+ outlier_detection=outlier_detection,
665
+ frozen_data_detection=frozen_data_detection
666
+ )
667
+ query.save()
668
+ message = f"{name} tag created successfully"
669
+
670
+ data.update(query.serialize())
671
+
672
+ result.update(
673
+ {
674
+ 'message': message,
675
+ 'data': data
676
+ }
677
+ )
678
+
679
+ return result
680
+
681
+ message = f"{data_type} data type not exist into database"
682
+ result.update(
683
+ {
684
+ 'message': message,
685
+ 'data': data
686
+ }
687
+ )
688
+ return result
689
+
690
+ message = f"{unit} unit not exist into database"
691
+ result.update(
692
+ {
693
+ 'message': message,
694
+ 'data': data
695
+ }
696
+ )
697
+ return result
698
+
699
+ else:
700
+
701
+ if _unit is not None and _display_unit is not None:
702
+
703
+ if _data_type is not None:
704
+ tag, _ = cls.get_or_create(name=name)
705
+ payload = {
706
+ "unit":_unit,
707
+ "data_type":_data_type,
708
+ "description":description,
709
+ "display_name":display_name,
710
+ "display_unit":_display_unit,
711
+ "opcua_address":opcua_address,
712
+ "node_namespace":node_namespace,
713
+ "scan_time":scan_time,
714
+ "dead_band":dead_band,
715
+ "active": True
716
+ }
717
+ cls.put(id=tag.id, **payload)
718
+
719
+ message = f"{data_type} data type not exist into database"
720
+ result.update(
721
+ {
722
+ 'message': message,
723
+ 'data': data
724
+ }
725
+ )
726
+ return result
727
+
728
+ message = f"{unit} unit not exist into database"
729
+ result.update(
730
+ {
731
+ 'message': message,
732
+ 'data': data
733
+ }
734
+ )
735
+ return result
736
+
737
+ result.update(
738
+ {
739
+ 'message': message,
740
+ 'data': data
741
+ }
742
+ )
743
+ return result
744
+
745
+ @classmethod
746
+ def put(cls, id:int, **fields)-> dict:
747
+ r""""
748
+ Update a single record
749
+
750
+ Once a model instance has a primary key, you UPDATE a field by its id.
751
+ The model's primary key will not change:
752
+ """
753
+
754
+ if cls.id_exists(id):
755
+
756
+ if "unit" in fields:
757
+
758
+ unit = fields["unit"]
759
+ if isinstance(unit, str):
760
+ query = Units.read_by_unit(unit=unit)
761
+ if query:
762
+
763
+ fields["unit"] = query
764
+
765
+ if "display_unit" in fields:
766
+
767
+ display_unit = fields["display_unit"]
768
+ if isinstance(display_unit, str):
769
+ query = Units.read_by_unit(unit=display_unit)
770
+ if query:
771
+
772
+ fields["display_unit"] = query
773
+
774
+ if "data_type" in fields:
775
+
776
+ data_type = fields["data_type"]
777
+ if isinstance(data_type, str):
778
+ query = DataTypes.read_by_name(name=data_type)
779
+ if query:
780
+
781
+ fields["data_type"] = query
782
+
783
+ if "segment" in fields:
784
+
785
+ if "manufacturer" in fields:
786
+
787
+ segment = fields["segment"]
788
+ manufacturer = fields.pop("manufacturer")
789
+ if isinstance(segment, str) and isinstance(manufacturer, str):
790
+ manufacturer_obj = Manufacturer.get_or_none(name=manufacturer)
791
+ if manufacturer_obj:
792
+ query = Segment.get_or_none((Segment.name == segment) & (Segment.manufacturer == manufacturer_obj))
793
+
794
+ if query:
795
+
796
+ fields["segment"] = query
797
+
798
+ query = cls.update(**fields).where(cls.id == id)
799
+ query.execute()
800
+ return query
801
+
802
+ @classmethod
803
+ def read_by_name(cls, name):
804
+ r"""
805
+ Documentation here
806
+ """
807
+ return cls.get_or_none(name=name)
808
+
809
+ @classmethod
810
+ def read_by_names(cls, names):
811
+ r"""
812
+ Documentation here
813
+ """
814
+ query = cls.select().where(cls.name in names)
815
+ return query
816
+
817
+ @classmethod
818
+ def name_exist(cls, name):
819
+ r"""
820
+ Documentation here
821
+ """
822
+ tag = cls.get_or_none(name=name)
823
+ if tag is not None:
824
+
825
+ return True
826
+
827
+ return False
828
+
829
+ @classmethod
830
+ def display_name_exist(cls, name):
831
+ r"""
832
+ Documentation here
833
+ """
834
+ tag = cls.get_or_none(name=name)
835
+ if tag is not None:
836
+
837
+ return True
838
+
839
+ return False
840
+
841
+ def get_machines(self):
842
+
843
+ return self.machines
844
+
845
+ def serialize(self):
846
+ r"""
847
+ Documentation here
848
+ """
849
+ segment = ""
850
+ manufacturer = ""
851
+ if self.segment:
852
+
853
+ segment = self.segment.serialize()
854
+ manufacturer = segment["manufacturer"]["name"]
855
+ segment = segment["name"]
856
+
857
+ gaussian_filter_r_value = 0
858
+ if hasattr(self, "gaussian_filter_r_value"):
859
+
860
+ gaussian_filter_r_value = self.gaussian_filter_r_value
861
+
862
+ gaussian_filter_threshold = 0
863
+ if hasattr(self, "gaussian_filter_threshold"):
864
+
865
+ gaussian_filter_threshold = self.gaussian_filter_threshold
866
+
867
+ return {
868
+ 'id': self.identifier,
869
+ 'name': self.name,
870
+ 'unit': self.unit.unit,
871
+ 'data_type': self.data_type.name,
872
+ 'description': self.description,
873
+ 'display_name': self.display_name,
874
+ 'display_unit': self.display_unit.unit,
875
+ 'opcua_address': self.opcua_address,
876
+ 'node_namespace': self.node_namespace,
877
+ 'scan_time': self.scan_time,
878
+ 'dead_band': self.dead_band,
879
+ 'variable': self.unit.variable_id.name,
880
+ 'active': self.active,
881
+ 'process_filter': self.process_filter,
882
+ 'gaussian_filter': self.gaussian_filter,
883
+ 'gaussian_filter_threshold': gaussian_filter_threshold,
884
+ 'gaussian_filter_r_value': gaussian_filter_r_value,
885
+ 'out_of_range_detection': self.out_of_range_detection,
886
+ 'frozen_data_detection': self.frozen_data_detection,
887
+ 'outlier_detection': self.outlier_detection,
888
+ 'segment': segment,
889
+ "manufacturer": manufacturer
890
+ }
891
+
892
+
893
+ class TagValue(BaseModel):
894
+
895
+ tag = ForeignKeyField(Tags, backref='values')
896
+ unit = ForeignKeyField(Units, backref='values')
897
+ value = FloatField()
898
+ timestamp = TimestampField(utc=True)
899
+
900
+ class Meta:
901
+ indexes = (
902
+ (('timestamp',), False),
903
+ )
904
+
905
+ @classmethod
906
+ def create(
907
+ cls,
908
+ tag:Tags,
909
+ value:float,
910
+ timestamp:datetime,
911
+ unit=Units):
912
+ r"""
913
+ Documentation here
914
+ """
915
+ query = cls(
916
+ tag=tag,
917
+ value=value,
918
+ timestamp=timestamp,
919
+ unit=unit
920
+ )
921
+ query.save()