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/__init__.py ADDED
@@ -0,0 +1,46 @@
1
+ import os, pytz
2
+ from flask import Flask
3
+ from .core import PyAutomation
4
+ from .state_machine import OPCUAServer
5
+
6
+ app = Flask(__name__, instance_relative_config=False)
7
+
8
+ MANUFACTURER = os.environ.get('MANUFACTURER')
9
+ SEGMENT = os.environ.get('SEGMENT')
10
+ _TIMEZONE = os.environ.get('TIMEZONE') or "America/Caracas"
11
+ TIMEZONE = pytz.timezone(_TIMEZONE)
12
+ CERT_FILE = os.path.join(".", "ssl", os.environ.get('CERT_FILE') or "")
13
+ KEY_FILE = os.path.join(".", "ssl", os.environ.get('KEY_FILE') or "")
14
+ if not os.path.isfile(CERT_FILE):
15
+ CERT_FILE = None
16
+
17
+ if not os.path.isfile(KEY_FILE):
18
+ KEY_FILE = None
19
+ OPCUA_SERVER_PORT = os.environ.get('OPCUA_SERVER_PORT') or "53530"
20
+
21
+
22
+ class CreateApp():
23
+ """Initialize the core application."""
24
+
25
+ def __call__(self):
26
+ """
27
+ Documentation here
28
+ """
29
+ app.client = None
30
+ self.application = app
31
+
32
+ with app.app_context():
33
+
34
+ from . import extensions
35
+ extensions.init_app(app)
36
+
37
+ from . import modules
38
+ modules.init_app(app)
39
+
40
+ return app
41
+
42
+ __application = CreateApp()
43
+ server = __application()
44
+ server.config['TPT_TOKEN'] = '073821603fcc483f9afee3f1500782a4'
45
+ server.config['BUNDLE_ERRORS'] = True
46
+ opcua_server = OPCUAServer()
@@ -0,0 +1,563 @@
1
+ import secrets
2
+ from datetime import datetime, timedelta, timezone
3
+ from .states import AlarmState, AlarmAttrs
4
+ from .trigger import Trigger, TriggerType
5
+ from ..tags.tag import Tag, MachineObserver
6
+ from ..tags.cvt import CVTEngine
7
+ from ..modules.users.users import User
8
+ from ..utils.decorators import validate_types, logging_error_handler, set_event, put_alarm_state
9
+ from ..models import FloatType, IntegerType, StringType
10
+ from ..variables import *
11
+ from statemachine import State, StateMachine
12
+ from flask_socketio import SocketIO
13
+
14
+
15
+ class Alarm(StateMachine):
16
+
17
+ # MAIN STATES
18
+ normal = State("normal", initial=True)
19
+ unack_alarm = State("unack_alarm")
20
+ ack_alarm = State("ack_alarm")
21
+ rtn_unack = State("rtn_unack")
22
+
23
+ # OUT OF SERVICE STATES
24
+ shelved = State("shelved")
25
+ suppressed_by_design = State("suppressed_by_design")
26
+ out_of_service = State("out_of_service")
27
+
28
+ # MAIN TRANSITIONS
29
+ normal_to_unack_alarm = normal.to(unack_alarm)
30
+ unack_alarm_to_ack_alarm = unack_alarm.to(ack_alarm)
31
+ ack_alarm_to_normal = ack_alarm.to(normal)
32
+ unack_alarm_to_rtn_unack = unack_alarm.to(rtn_unack)
33
+ rtn_unack_to_normal = rtn_unack.to(normal)
34
+ rtn_unack_to_unack_alarm = rtn_unack.to(unack_alarm)
35
+
36
+ # SHELVED TRANSITIONS
37
+ normal_to_shelved = normal.to(shelved)
38
+ unack_alarm_to_shelved = unack_alarm.to(shelved)
39
+ ack_alarm_to_shelved = ack_alarm.to(shelved)
40
+ rtn_unack_to_shelved = rtn_unack.to(shelved)
41
+ shelved_to_normal = shelved.to(normal)
42
+ shelved_to_unack_alarm = shelved.to(unack_alarm)
43
+
44
+ # SUPPRESSED BY DESIGN TRANSITIONS
45
+ normal_to_suppressed_by_design = normal.to(suppressed_by_design)
46
+ unack_alarm_to_suppressed_by_design = unack_alarm.to(suppressed_by_design)
47
+ ack_alarm_to_suppressed_by_design = ack_alarm.to(suppressed_by_design)
48
+ rtn_unack_to_suppressed_by_design = rtn_unack.to(suppressed_by_design)
49
+ suppressed_by_design_to_normal = suppressed_by_design.to(normal)
50
+ suppressed_by_design_to_unack_alarm = suppressed_by_design.to(unack_alarm)
51
+
52
+
53
+ # OUT OF SERVICE TRANSITIONS
54
+ normal_to_out_of_service = normal.to(out_of_service)
55
+ unack_alarm_to_out_of_service = unack_alarm.to(out_of_service)
56
+ ack_alarm_to_out_of_service = ack_alarm.to(out_of_service)
57
+ rtn_unack_to_out_of_service = rtn_unack.to(out_of_service)
58
+ out_of_service_to_normal = out_of_service.to(normal)
59
+ out_of_service_to_unack_alarm = out_of_service.to(unack_alarm)
60
+
61
+ def __init__(
62
+ self,
63
+ name:str,
64
+ tag:Tag,
65
+ alarm_type:StringType,
66
+ alarm_setpoint:IntegerType|FloatType,
67
+ description:str="",
68
+ state:str=None,
69
+ timestamp:datetime=None,
70
+ ack_timestamp:datetime=None,
71
+ alarm_deadband:IntegerType|FloatType=FloatType(0.0),
72
+ alarm_on_delay:IntegerType|FloatType=FloatType(0.0),
73
+ alarm_off_delay:IntegerType|FloatType=FloatType(0.0),
74
+ identifier:str=None,
75
+ user:User=None,
76
+ reload:bool=False
77
+ ):
78
+ from ..logger.alarms import AlarmsLoggerEngine
79
+ self.alarm_engine = AlarmsLoggerEngine()
80
+ self.tag_engine = CVTEngine()
81
+ self.name = name
82
+ self.tag = tag
83
+ self.segment = tag.segment
84
+ self.manufacturer = tag.manufacturer
85
+ self.attach(machine=self, tag=tag)
86
+ self.description = description
87
+ self.alarm_setpoint = Trigger()
88
+ self.alarm_setpoint.value = alarm_setpoint.value
89
+ self.alarm_setpoint.type = TriggerType(value=alarm_type.value.upper())
90
+ alarm_deadband.unit = tag.get_display_unit()
91
+ self.alarm_deadband = alarm_deadband
92
+ self.alarm_on_delay = alarm_on_delay
93
+ self.alarm_off_delay = alarm_off_delay
94
+ self.timestamp = timestamp
95
+ self.ack_timestamp = ack_timestamp
96
+ self.state = AlarmState.NORM
97
+ if state:
98
+
99
+ for _, attr in AlarmState.__dict__.items():
100
+
101
+ if isinstance(attr, AlarmAttrs):
102
+
103
+ if state==attr.state:
104
+
105
+ self.state = attr
106
+ break
107
+ if identifier:
108
+ self.identifier = identifier
109
+ else:
110
+ self.identifier = secrets.token_hex(4)
111
+
112
+ self._shelved_time:datetime = None
113
+ self._shelved_until:datetime = None
114
+ self._shelved_options_time = {
115
+ 'days': 0,
116
+ 'seconds': 0,
117
+ 'microseconds': 0,
118
+ 'milliseconds': 0,
119
+ 'minutes': 0,
120
+ 'hours': 0,
121
+ 'weeks': 0
122
+ }
123
+ transitions = []
124
+ for state in self.states:
125
+ transitions.extend(state.transitions)
126
+ self.transitions = transitions
127
+ self.sio:SocketIO|None = None
128
+ super(Alarm, self).__init__()
129
+
130
+ @logging_error_handler
131
+ @put_alarm_state
132
+ def on_enter_normal(self):
133
+ self.state = AlarmState.NORM
134
+ self.timestamp = None
135
+ self.ack_timestamp = None
136
+
137
+ @logging_error_handler
138
+ @put_alarm_state
139
+ def on_enter_unack_alarm(self):
140
+
141
+ self.state = AlarmState.UNACK
142
+ self.timestamp = self.__timestamp
143
+ self.alarm_engine.create_record_on_alarm_summary(
144
+ name=self.name,
145
+ state=self.state.state,
146
+ timestamp=self.timestamp,
147
+ ack_timestamp=self.ack_timestamp
148
+ )
149
+
150
+ @logging_error_handler
151
+ @put_alarm_state
152
+ def on_enter_ack_alarm(self):
153
+
154
+ self.state = AlarmState.ACKED
155
+ self.ack_timestamp = self.__timestamp
156
+ self.alarm_engine.put_record_on_alarm_summary(
157
+ name=self.name,
158
+ state=self.state.state,
159
+ ack_timestamp=self.ack_timestamp
160
+ )
161
+
162
+ @logging_error_handler
163
+ @put_alarm_state
164
+ def on_enter_rtn_unack(self):
165
+
166
+ self.timestamp = None
167
+ self.state = AlarmState.RTNUN
168
+ self.alarm_engine.put_record_on_alarm_summary(
169
+ name=self.name,
170
+ state=self.state.state
171
+ )
172
+
173
+ @logging_error_handler
174
+ @put_alarm_state
175
+ def on_enter_shelved(self):
176
+
177
+ self.state = AlarmState.SHLVD
178
+
179
+ @logging_error_handler
180
+ @put_alarm_state
181
+ def on_enter_suppressed_by_design(self):
182
+
183
+ self.state = AlarmState.DSUPR
184
+
185
+ @logging_error_handler
186
+ @put_alarm_state
187
+ def on_enter_out_of_service(self):
188
+
189
+ self.state = AlarmState.OOSRV
190
+
191
+ def set_socketio(self, sio:SocketIO):
192
+ r"""
193
+ Documentation here
194
+ """
195
+ self.sio:SocketIO = sio
196
+
197
+ @logging_error_handler
198
+ @validate_types(
199
+ tag=str,
200
+ value=Temperature|Length|Current|Time|Pressure|Mass|Force|Power|VolumetricFlow|MassFlow|Density|Percentage|Adimentional,
201
+ timestamp=datetime,
202
+ output=None)
203
+ def notify(
204
+ self,
205
+ tag:str,
206
+ value:Temperature|Length|Current|Time|Pressure|Mass|Force|Power|VolumetricFlow|MassFlow|Density|Percentage|Adimentional,
207
+ timestamp:datetime):
208
+ r"""
209
+ This method provide an interface to CVT to notify if tag value has change
210
+
211
+ # Parameters
212
+
213
+ - *tag:* [Tag] tag Object
214
+ - *value:* [int|float|bool] tag value
215
+ """
216
+ self.__timestamp = timestamp
217
+ if self.state not in (AlarmState.DSUPR, AlarmState.SHLVD, AlarmState.OOSRV):
218
+ if self.alarm_setpoint.type in (TriggerType.HH, TriggerType.H):
219
+
220
+ if value.value > self.alarm_setpoint.value:
221
+
222
+ self.abnormal_condition()
223
+
224
+ else:
225
+
226
+ self.normal_condition()
227
+
228
+ elif self.alarm_setpoint.type in (TriggerType.L, TriggerType.LL):
229
+
230
+ if value.value < self.alarm_setpoint.value:
231
+
232
+ self.abnormal_condition()
233
+
234
+ else:
235
+
236
+ self.normal_condition()
237
+
238
+ else: # Boolean Alarm
239
+
240
+ if value.value == bool(self.alarm_setpoint.value):
241
+
242
+ self.abnormal_condition()
243
+
244
+ else:
245
+
246
+ self.normal_condition()
247
+
248
+ if self.state==AlarmState.SHLVD:
249
+
250
+ if datetime.now(timezone.utc) >= self._shelved_until:
251
+
252
+ self.unshelve()
253
+
254
+ @logging_error_handler
255
+ def abnormal_condition(self):
256
+ r"""
257
+ Documentation here
258
+ """
259
+ current_state = self.current_state.name.lower()
260
+ transition_name = f'{current_state}_to_unack_alarm'
261
+ self.__transition(transition_name=transition_name)
262
+
263
+ @logging_error_handler
264
+ def normal_condition(self):
265
+ r"""
266
+ Documentation here
267
+ """
268
+ current_state = self.current_state.name.lower()
269
+
270
+ if current_state=="unack_alarm":
271
+
272
+ transition_name = f'{current_state}_to_rtn_unack'
273
+ self.__transition(transition_name=transition_name)
274
+
275
+ elif current_state=="ack_alarm":
276
+
277
+ transition_name = f'{current_state}_to_normal'
278
+ self.__transition(transition_name=transition_name)
279
+
280
+ @logging_error_handler
281
+ @set_event(message=f"Acknowledged", classification="Alarm", priority=2, criticity=3)
282
+ def acknowledge(self, user:User=None):
283
+ r"""
284
+ Documentation here
285
+ """
286
+ current_state = self.current_state.name.lower()
287
+
288
+ if current_state=="unack_alarm":
289
+
290
+ transition_name = f'{current_state}_to_ack_alarm'
291
+
292
+ elif current_state=="rtn_unack":
293
+
294
+ transition_name = f'{current_state}_to_normal'
295
+
296
+
297
+ tag = self.tag_engine.get_tag_by_name(name=self.tag.name)
298
+ self.alarm_engine.put_record_on_alarm_summary(
299
+ name=self.name,
300
+ ack_timestamp=tag.get_timestamp()
301
+ )
302
+ self.__transition(transition_name=transition_name)
303
+ return self, f"{self.tag.get_name()}"
304
+
305
+ @logging_error_handler
306
+ @set_event(message=f"Shelved", classification="Alarm", priority=2, criticity=3)
307
+ def shelve(self, user:User=None, **options):
308
+ r"""
309
+ Documentation here
310
+ **Parameters**
311
+
312
+ * **days:** (int)
313
+ * **seconds:** (int)
314
+ * **minutes:** (int)
315
+ * **hours:** (int)
316
+ * **weeks:** (int)
317
+ """
318
+ options_time = {key: options[key] if key in options else self._shelved_options_time[key] for key in self._shelved_options_time}
319
+
320
+ if options_time!=self._shelved_options_time:
321
+
322
+ self._shelved_time = datetime.now(timezone.utc)
323
+ self._shelved_until = self._shelved_time + timedelta(**options_time)
324
+
325
+ current_state = self.current_state.name.lower()
326
+ transition_name = f'{current_state}_to_shelved'
327
+ self.__transition(transition_name=transition_name)
328
+ return self, f"{self.tag.get_name()}"
329
+
330
+ @logging_error_handler
331
+ @set_event(message=f"Unshelved", classification="Alarm", priority=2, criticity=3)
332
+ def unshelve(self, user:User=None):
333
+ r"""
334
+ Documentation here
335
+ """
336
+ self.__return_to_service()
337
+ return self, f"{self.tag.get_name()}"
338
+
339
+ @logging_error_handler
340
+ @set_event(message=f"Designed suppression", classification="Alarm", priority=2, criticity=3)
341
+ def designed_suppression(self, user:User=None):
342
+ r"""
343
+ Documentation here
344
+ """
345
+ current_state = self.current_state.name.lower()
346
+ transition_name = f'{current_state}_to_suppressed_by_design'
347
+ self.__transition(transition_name=transition_name)
348
+ return self, f"{self.tag.get_name()}"
349
+
350
+ @logging_error_handler
351
+ @set_event(message=f"Designed unsuppression", classification="Alarm", priority=2, criticity=3)
352
+ def designed_unsuppression(self, user:User=None):
353
+ r"""
354
+ Documentation here
355
+ """
356
+ self.__return_to_service()
357
+ return self, f"{self.tag.get_name()}"
358
+
359
+ @logging_error_handler
360
+ @set_event(message=f"Removed from service", classification="Alarm", priority=2, criticity=3)
361
+ def remove_from_service(self, user:User=None):
362
+ r"""
363
+ Documentation here
364
+ """
365
+ current_state = self.current_state.name.lower()
366
+ transition_name = f'{current_state}_to_out_of_service'
367
+ self.__transition(transition_name=transition_name)
368
+ return self, f"{self.tag.get_name()}"
369
+
370
+ @logging_error_handler
371
+ @set_event(message=f"Returned to service", classification="Alarm", priority=2, criticity=3)
372
+ def return_to_service(self, user:User=None):
373
+ r"""
374
+ Documentation here
375
+ """
376
+ self.__return_to_service()
377
+
378
+ return self, f"{self.tag.get_name()}"
379
+
380
+ @logging_error_handler
381
+ def attach(self, machine, tag:Tag):
382
+
383
+ def attach_observer(machine, tag:Tag):
384
+
385
+ observer = MachineObserver(machine)
386
+ query = dict()
387
+ query["action"] = "attach_observer"
388
+ query["parameters"] = {
389
+ "name": tag.name,
390
+ "observer": observer,
391
+ }
392
+ self.tag_engine.request(query)
393
+ self.tag_engine.response()
394
+
395
+ attach_observer(machine, tag)
396
+
397
+ @set_event(message=f"Updated", classification="Alarm", priority=2, criticity=3)
398
+ def put(
399
+ self,
400
+ user:User=None,
401
+ name:str=None,
402
+ tag:str=None,
403
+ description:str=None,
404
+ alarm_type:TriggerType=None,
405
+ trigger_value:float=None):
406
+ r"""
407
+ Update alarm configuration
408
+
409
+ **Parameters**
410
+
411
+ * **name** (str): Alarm name
412
+ * **tag** (str): Tag binded to alarm
413
+ * **description** (str): Alarm description
414
+ * **type** (str): Alarm type ['HIGH-HIGH', 'HIGH', 'LOW', 'LOW-LOW', 'BOOL']
415
+ * **trigger_value** (float): Alarm trigger value
416
+
417
+ """
418
+ message = ""
419
+ if alarm_type:
420
+
421
+ if alarm_type.value.upper() in ["HIGH-HIGH", "HIGH", "LOW", "LOW-LOW", "BOOL"]:
422
+
423
+ self.alarm_setpoint.type = alarm_type
424
+
425
+ message += f" alarm_type: {alarm_type.value}"
426
+
427
+ if trigger_value:
428
+
429
+ self.alarm_setpoint.value = float(trigger_value)
430
+ message += f" trigger value: {trigger_value}"
431
+
432
+ if name:
433
+
434
+ self._name = name
435
+ message += f" name: {name}"
436
+
437
+ if tag:
438
+
439
+ self._tag = tag
440
+ message += f" tag: {tag}"
441
+
442
+ if description:
443
+
444
+ self._description = description
445
+ message += f" description: {description}"
446
+
447
+ return self, message
448
+
449
+ def _get_active_transitions(self):
450
+ r"""
451
+ Gets allowed transitions based on the current state
452
+
453
+ **Returns**
454
+
455
+ * **(list)**
456
+ """
457
+ result = list()
458
+
459
+ current_state = self.current_state
460
+ transitions = self.transitions
461
+
462
+ for transition in transitions:
463
+
464
+ if transition.source == current_state:
465
+
466
+ result.append(transition)
467
+
468
+ return result
469
+
470
+ @logging_error_handler
471
+ def __transition(self, transition_name:str):
472
+
473
+ allowed_transitions = self._get_active_transitions()
474
+ for _transition in allowed_transitions:
475
+
476
+ if f"{_transition.source.name}_to_{_transition.target.name}"==transition_name:
477
+
478
+ self.send(transition_name)
479
+
480
+ @logging_error_handler
481
+ def __return_to_service(self):
482
+
483
+ current_state = self.current_state.name.lower()
484
+
485
+ if self.state.alarm_status.lower()=="active":
486
+
487
+ transition_name = f'{current_state}_to_unack_alarm'
488
+
489
+ else:
490
+
491
+ transition_name = f'{current_state}_to_normal'
492
+
493
+ self.__transition(transition_name=transition_name)
494
+
495
+ @logging_error_handler
496
+ def get_operator_actions(self)->list:
497
+
498
+ current_state = self.current_state.name.lower()
499
+
500
+ if current_state in ("unack_alarm", "rtn_unack"):
501
+
502
+ result = {
503
+ "Acknowledge": "acknowledge",
504
+ "Shelve": "shelve",
505
+ "Designed Suppression": "designed_suppression",
506
+ "Remove From Service": "remove_from_service"
507
+ }
508
+
509
+ elif current_state=="suppressed_by_design":
510
+
511
+ result = {
512
+ "Designed Unsuppression": "designed_unsuppression"
513
+ }
514
+
515
+ elif current_state=="out_of_service":
516
+
517
+ result = {
518
+ "Return To Service": "return_to_service"
519
+ }
520
+
521
+ else:
522
+
523
+ result = {
524
+ "Shelve": "shelve",
525
+ "Designed Suppression": "designed_suppression",
526
+ "Remove From Service": "remove_from_service"
527
+ }
528
+
529
+ return result
530
+
531
+ def serialize(self):
532
+ r"""
533
+ Allows you to serialize alarm to a dict jsonable
534
+
535
+ **Return**
536
+
537
+ * **alarm_info**: (dict) A jsonable dictionary
538
+ """
539
+ timestamp = self.timestamp
540
+ if timestamp:
541
+
542
+ timestamp = timestamp.strftime(self.tag_engine.DATETIME_FORMAT)
543
+
544
+ ack_timestamp = self.ack_timestamp
545
+ if ack_timestamp:
546
+
547
+ ack_timestamp = ack_timestamp.strftime(self.tag_engine.DATETIME_FORMAT)
548
+
549
+ return {
550
+ "identifier": self.identifier,
551
+ "segment": self.segment,
552
+ "manufacturer": self.manufacturer,
553
+ "timestamp": timestamp,
554
+ "name": self.name,
555
+ "tag": self.tag.name,
556
+ "state": self.state.serialize(),
557
+ "alarm_setpoint": self.alarm_setpoint.serialize(),
558
+ "ack_timestamp": ack_timestamp,
559
+ "description": self.description,
560
+ "actions": self.get_operator_actions()
561
+ }
562
+
563
+