Passed
Pull Request — master (#348)
by
unknown
03:21 queued 01:00
created

ProgramStateMachine.RunningToHalted()   A

Complexity

Conditions 1

Size

Total Lines 21
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 14
nop 1
dl 0
loc 21
rs 9.7
c 0
b 0
f 0
1
'''
2
https://reference.opcfoundation.org/v104/Core/docs/Part10/
3
https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.1/
4
Basic statemachines described in OPC UA Spec.:
5
StateMachineType
6
FiniteStateMachineType
7
ExclusiveLimitStateMachineType
8
FileTransferStateMachineType
9
ProgramStateMachineType
10
ShelvedStateMachineType
11
Relevant information:
12
Overview - https://reference.opcfoundation.org/v104/Core/docs/Part10/5.2.3/#5.2.3.1
13
States - https://reference.opcfoundation.org/v104/Core/docs/Part10/5.2.3/#5.2.3.2
14
Transitions - https://reference.opcfoundation.org/v104/Core/docs/Part10/5.2.3/#5.2.3.3
15
Events - https://reference.opcfoundation.org/v104/Core/docs/Part10/5.2.5/
16
'''
17
import asyncio, logging, datetime
18
19
#FIXME 
20
# -change to relativ imports!
21
# -remove unused imports
22
from asyncua import Server, ua, Node
23
from asyncua.common.event_objects import TransitionEvent, ProgramTransitionEvent
24
25
_logger = logging.getLogger(__name__)
26
27
class StateMachine(object):
28
    '''
29
    Implementation of an StateMachineType (most basic type)
30
    CurrentState: Mandatory "StateVariableType"
31
    LastTransition: Optional "TransitionVariableType"
32
    Generates TransitionEvent's
33
    '''
34
    def __init__(self, server=None, parent=None, idx=None, name=None):
35
        if not isinstance(server, Server): 
36
            raise ValueError
37
        if not isinstance(parent, Node): 
38
            raise ValueError
39
        if idx == None:
40
            idx = parent.nodeid.NamespaceIndex
41
        if name == None:
42
            name = "StateMachine"
43
        self.locale = "en-US"
44
        self._server = server
45
        self._parent = parent
46
        self._state_machine_node = None
47
        self._state_machine_type = ua.NodeId(2299, 0) #StateMachineType
48
        self._name = name
49
        self._idx = idx
50
        self._optionals = False
51
        self._current_state_node = None
52
        self._current_state_id_node = None
53
        self._current_state_name_node = None
54
        self._current_state_number_node = None
55
        self._last_transition_node = None
56
        self._last_transition_id_node = None
57
        self._last_transition_name_node = None
58
        self._last_transition_number_node = None
59
        self._last_transition_transitiontime_node = None
60
        self._last_transition_effectivetransitiontime_node = None
61
        self._evgen = None
62
        self.evtype = TransitionEvent()
63
64
    class State(object):
65
        '''
66
        Helperclass for States (StateVariableType)
67
        https://reference.opcfoundation.org/v104/Core/docs/Part5/B.4.3/
68
        name: type string will be converted automatically to qualifiedname 
69
            -> Name is a QualifiedName which uniquely identifies the current state within the StateMachineType.
70
        id: Id is a name which uniquely identifies the current state within the StateMachineType. A subtype may restrict the DataType.
71
        number: Number is an integer which uniquely identifies the current state within the StateMachineType.
72
        '''
73
        def __init__(self, name, id=0, node=None, issub=False):
74
            self.name = name
75
            self.id = str(id)
76
            self.number = id
77
            self.node = node #will be written from statemachine.add_state() or you need to overwrite it if the state is part of xml
78
            self.issub = issub #true if it is a substate
79
80
    class Transition(object):
81
        '''
82
        Helperclass for Transitions (TransitionVariableType)
83
        https://reference.opcfoundation.org/v104/Core/docs/Part5/B.4.4/
84
        name: type string will be converted automatically to qualifiedname 
85
            -> Name is a QualifiedName which uniquely identifies a transition within the StateMachineType.
86
        id: Id is a name which uniquely identifies a Transition within the StateMachineType. A subtype may restrict the DataType.
87
        number: Number is an integer which uniquely identifies the current state within the StateMachineType.
88
        transitiontime: TransitionTime specifies when the transition occurred.
89
        effectivetransitiontime: EffectiveTransitionTime specifies the time when the current state or one of its substates was entered. 
90
        If, for example, a StateA is active and – while active – switches several times between its substates SubA and SubB, 
91
        then the TransitionTime stays at the point in time where StateA became active whereas the EffectiveTransitionTime changes 
92
        with each change of a substate.
93
        '''
94
        def __init__(self, name, id=0, node=None, issub=False):
95
            self.name = name
96
            self.id = str(id)
97
            self.number = id
98
            self._transitiontime = datetime.datetime.utcnow() #will be overwritten from _write_transition()
99
            self._effectivetransitiontime = datetime.datetime.utcnow() #will be overwritten from _write_transition()
100
            self.node = node #will be written from statemachine.add_state() or you need to overwrite it if the state is part of xml
101
            self.issub = issub #true if it is a transition between substates
102
103
    async def install(self, optionals=False):
104
        '''
105
        setup adressspace
106
        '''
107
        self._optionals = optionals
108
        self._state_machine_node = await self._parent.add_object(
109
            self._idx, 
110
            self._name, 
111
            objecttype=self._state_machine_type, 
112
            instantiate_optional=optionals
113
            )
114
        if self._optionals:
115
            #FIXME somehow propertys dont get added if i instantiate with optionals
116
            self._last_transition_node = await self._state_machine_node.get_child(["LastTransition"])
117
            self._last_transition_transitiontime_node = await self._last_transition_node.add_property(
118
                0, 
119
                "TransitionTime", 
120
                ua.Variant(datetime.datetime.utcnow(), varianttype=ua.VariantType.DateTime)
121
                )
122
            self._last_transition_effectivetransitiontime_node = await self._last_transition_node.add_property(
123
                0, 
124
                "EffectiveTransitionTime", 
125
                ua.Variant(datetime.datetime.utcnow(), varianttype=ua.VariantType.DateTime)
126
                )
127
        await self.init(self._state_machine_node)
128
    
129
    async def init(self, statemachine):
130
        '''
131
        initialize and get subnodes
132
        '''
133
        self._current_state_node = await statemachine.get_child(["CurrentState"])
134
        current_state_props = await self._current_state_node.get_properties()
135
        for prop in current_state_props:
136
            dn = await prop.read_display_name()
137
            if dn.Text == "Id":
138
                self._current_state_id_node = await self._current_state_node.get_child(["Id"])
139
            elif dn.Text == "Name":
140
                self._current_state_name_node = await self._current_state_node.get_child(["Name"])
141
            elif dn.Text == "Number":
142
                self._current_state_number_node = await self._current_state_node.get_child(["Number"])
143
            else:
144
                _logger.warning(f"{await statemachine.read_browse_name()} CurrentState Unknown propertie: {dn.Text}")
145
        if self._optionals:
146
            self._last_transition_node = await statemachine.get_child(["LastTransition"])
147
            last_transition_props = await self._last_transition_node.get_properties()
148
            for prop in last_transition_props:
149
                dn = await prop.read_display_name()
150
                if dn.Text == "Id":
151
                    self._last_transition_id_node = await self._last_transition_node.get_child(["Id"])
152
                elif dn.Text == "Name":
153
                    self._last_transition_name_node = await self._last_transition_node.get_child(["Name"])
154
                elif dn.Text == "Number":
155
                    self._last_transition_number_node = await self._last_transition_node.get_child(["Number"])
156
                elif dn.Text == "TransitionTime":
157
                    self._last_transition_transitiontime_node = await self._last_transition_node.get_child(["TransitionTime"])
158
                elif dn.Text == "EffectiveTransitionTime":
159
                    self._last_transition_effectivetransitiontime_node = await self._last_transition_node.get_child(["EffectiveTransitionTime"])
160
                else:
161
                    _logger.warning(f"{await statemachine.read_browse_name()} LastTransition Unknown propertie: {dn.Text}")
162
        self._evgen = await self._server.get_event_generator(self.evtype, self._state_machine_node)
163
164
    async def change_state(self, state, transition=None, event_msg=None, severity=500):
165
        '''
166
        method to change the state of the statemachine
167
        state: "self.State" mandatory
168
        transition: "self.Transition" optional
169
        event_msg: "string/LocalizedText" optional
170
        severity: "Int" optional
171
        '''
172
        await self._write_state(state)
173
        if transition:
174
            await self._write_transition(transition)
175
        if event_msg:
176
            if isinstance(event_msg, str):
177
                event_msg = ua.LocalizedText(event_msg, self.locale)
178
            self._evgen.event.Message = event_msg
179
            self._evgen.event.Severity = severity
180
            await self._evgen.trigger()
181
182
    async def _write_state(self, state):
183
        if not isinstance(state, self.State):
184
            raise ValueError
185
        await self._current_state_node.write_value(ua.LocalizedText(state.name, self.locale), ua.VariantType.LocalizedText)
186
        if state.node:
187
            if self._current_state_id_node:
188
                await self._current_state_id_node.write_value(state.node.nodeid, ua.VariantType.NodeId)
189
            if self._current_state_name_node:
190
                await self._current_state_name_node.write_value(state.name, ua.VariantType.QualifiedName)
191
            if self._current_state_number_node:
192
                await self._current_state_number_node.write_value(state.number, ua.VariantType.UInt32)
193
194
    async def _write_transition(self, transition):
195
        '''
196
        transition: self.Transition
197
        issub: boolean (true if it is a transition between substates)
198
        '''
199
        if not isinstance(transition, self.Transition):
200
            raise ValueError
201
        if transition.issub == False:
202
            transition._transitiontime = datetime.datetime.utcnow()
203
        transition._effectivetransitiontime = datetime.datetime.utcnow()
204
        await self._last_transition_node.write_value(ua.LocalizedText(transition.name, self.locale), ua.VariantType.LocalizedText)
205
        if self._optionals:
206
            if self._last_transition_id_node:
207
                await self._last_transition_id_node.write_value(transition.node.nodeid, ua.VariantType.NodeId)
208
            if self._last_transition_name_node:
209
                await self._last_transition_name_node.write_value(ua.QualifiedName(transition.name, self._idx), ua.VariantType.QualifiedName)
210
            if self._last_transition_number_node:
211
                await self._last_transition_number_node.write_value(transition.number, ua.VariantType.UInt32)
212
            if self._last_transition_transitiontime_node:
213
                await self._last_transition_transitiontime_node.write_value(transition._transitiontime, ua.VariantType.DateTime)
214
            if self._last_transition_effectivetransitiontime_node:
215
                await self._last_transition_effectivetransitiontime_node.write_value(transition._effectivetransitiontime, ua.VariantType.DateTime)
216
            
217
    async def add_state(self, state, state_type=ua.NodeId(2307, 0), optionals=False):
218
        '''
219
        this method adds a state object to the statemachines address space
220
        state: self.State,
221
        InitialStateType: ua.NodeId(2309, 0),
222
        StateType: ua.NodeId(2307, 0),
223
        ChoiceStateType: ua.NodeId(15109,0),
224
        '''
225
        if not isinstance(state, self.State):
226
            raise ValueError
227
        state.node = await self._state_machine_node.add_object(
228
            self._idx, 
229
            state.name, 
230
            objecttype=state_type, 
231
            instantiate_optional=optionals
232
            )
233
        state_number = await state.node.get_child(["StateNumber"])
234
        await state_number.write_value(state.number, ua.VariantType.UInt32)
235
        return state.node
236
237
    async def add_transition(self, transition, transition_type=ua.NodeId(2310, 0), optionals=False):
238
        '''
239
        this method adds a transition object to the statemachines address space
240
        transition: self.Transition,
241
        transition_type: ua.NodeId(2310, 0),
242
        '''
243
        if not isinstance(transition, self.Transition):
244
            raise ValueError
245
        transition.node = await self._state_machine_node.add_object(
246
            self._idx, 
247
            transition.name, 
248
            objecttype=transition_type, 
249
            instantiate_optional=optionals
250
            )
251
        transition_number = await transition.node.get_child(["TransitionNumber"])
252
        await transition_number.write_value(transition.number, ua.VariantType.UInt32)
253
        return transition.node
254
255
    async def remove(self, nodes):
256
        #FIXME Is it wise to remove a part of a program/statemachine dynamically? at this point i am not sure
257
        raise NotImplementedError
258
259
class FiniteStateMachine(StateMachine):
260
    '''
261
    Implementation of an FiniteStateMachineType a little more advanced than the basic one
262
    if you need to know the available states and transition from clientside
263
    '''
264
    def __init__(self, server=None, parent=None, idx=None, name=None):
265
        super().__init__(server, parent, idx, name)
266
        if name == None:
267
            name = "FiniteStateMachine"
268
        self._state_machine_type = ua.NodeId(2771, 0)
269
        self._available_states_node = None
270
        self._available_transitions_node = None
271
272
    async def set_available_states(self, states):
273
        if not self._available_states_node:
274
            self._available_states_node = await self._state_machine_node.get_child(["AvailableStates"])
275
        if isinstance(states, list):
276
            return await self._available_states_node.write_value(states, varianttype=ua.VariantType.NodeId)
277
        return ValueError
278
279
    async def set_available_transitions(self, transitions):
280
        if self._optionals:
281
            if not self._available_transitions_node:
282
                self._available_transitions_node = await self._state_machine_node.get_child(["AvailableTransitions"])
283
            if isinstance(transitions, list):
284
                await self._available_transitions_node.write_value(transitions, varianttype=ua.VariantType.NodeId)
285
            return ValueError
286
287
    async def find_all_states(self):
288
        return NotImplementedError
289
    
290
    async def find_all_transitions(self):
291
        return NotImplementedError
292
293
class ExclusiveLimitStateMachine(FiniteStateMachine):
294
    '''
295
    NOT IMPLEMENTED "ExclusiveLimitStateMachineType"
296
    '''
297
    def __init__(self, server=None, parent=None, idx=None, name=None):
298
        super().__init__(server, parent, idx, name)
299
        if name == None:
300
            name = "ExclusiveLimitStateMachine"
301
        self._state_machine_type = ua.NodeId(9318, 0)
302
        raise NotImplementedError
303
304
class FileTransferStateMachine(FiniteStateMachine):
305
    '''
306
    NOT IMPLEMENTED "FileTransferStateMachineType"
307
    '''
308
    def __init__(self, server=None, parent=None, idx=None, name=None):
309
        super().__init__(server, parent, idx, name)
310
        if name == None:
311
            name = "FileTransferStateMachine"
312
        self._state_machine_type = ua.NodeId(15803, 0)
313
        raise NotImplementedError
314
315
class ProgramStateMachine(FiniteStateMachine):
316
    '''
317
    https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.3/
318
    Implementation of an ProgramStateMachine its quite a complex statemachine with the 
319
    optional possibility to make the statchange from clientside via opcua-methods
320
    '''
321
    def __init__(self, server=None, parent=None, idx=None, name=None):
322
        super().__init__(server, parent, idx, name)
323
        if name == None:
324
            name = "ProgramStateMachine"
325
        self._state_machine_type = ua.NodeId(2391, 0)
326
        self.evtype = ProgramTransitionEvent()
327
328
        # 5.2.3.2 ProgramStateMachineType states
329
        self._ready_state_node = None #State node
330
        self._halted_state_node = None #State node
331
        self._running_state_node = None #State node
332
        self._suspended_state_node = None #State node
333
334
        # 5.2.3.3 ProgramStateMachineType transitions
335
        self._halted_to_ready_node = None #Transition node
336
        self._ready_to_running_node = None #Transition node
337
        self._running_to_halted_node = None #Transition node
338
        self._running_to_ready_node = None #Transition node
339
        self._running_to_suspended_node = None #Transition node
340
        self._suspended_to_running_node = None #Transition node
341
        self._suspended_to_halted_node = None #Transition node
342
        self._suspended_to_ready_node = None #Transition node
343
        self._ready_to_halted_node = None #Transition node
344
345
        # 5.2.3.2 ProgramStateMachineType states
346
        self._halted_state_id_node = None #State property (StateNumber value 11)
347
        self._ready_state_id_node = None #State property (StateNumber value 12)
348
        self._running_state_id_node = None #State property (StateNumber value 13)
349
        self._suspended_state_id_node = None #State property (StateNumber value 14)
350
351
        # 5.2.3.3 ProgramStateMachineType transitions
352
        self._halted_to_ready_id_node = None #Transition property (TransitionNumber value 1)
353
        self._ready_to_running_id_node = None #Transition property (TransitionNumber value 2)
354
        self._running_to_halted_id_node = None #Transition property (TransitionNumber value 3)
355
        self._running_to_ready_id_node = None #Transition property (TransitionNumber value 4)
356
        self._running_to_suspended_id_node = None #Transition property (TransitionNumber value 5)
357
        self._suspended_to_running_id_node = None #Transition property (TransitionNumber value 6)
358
        self._suspended_to_halted_id_node = None #Transition property (TransitionNumber value 7)
359
        self._suspended_to_ready_id_node = None #Transition property (TransitionNumber value 8)
360
        self._ready_to_halted_id_node = None #Transition property (TransitionNumber value 9)
361
362
        # 4.2.7 Program Control Methods (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.7/)
363
        self._halt_method_node = None #uamethod node
364
        self._reset_method_node = None #uamethod node
365
        self._resume_method_node = None #uamethod node
366
        self._start_method_node = None #uamethod node
367
        self._suspend_method_node = None #uamethod node
368
369
        #can be overwritten if you want a different language
370
        self.localizedtext_ready = ua.LocalizedText("Ready", "en-US")
371
        self.localizedtext_running = ua.LocalizedText("Running", "en-US")
372
        self.localizedtext_halted = ua.LocalizedText("Halted", "en-US")
373
        self.localizedtext_suspended= ua.LocalizedText("Suspended", "en-US")
374
        self.localizedtext_halted_to_ready = ua.LocalizedText("HaltedToReady", "en-US")
375
        self.localizedtext_ready_to_running = ua.LocalizedText("ReadyToRunning", "en-US")
376
        self.localizedtext_running_to_halted = ua.LocalizedText("RunningToHalted", "en-US")
377
        self.localizedtext_running_to_ready = ua.LocalizedText("RunningToReady", "en-US")
378
        self.localizedtext_running_to_suspended = ua.LocalizedText("RunningToSuspended", "en-US")
379
        self.localizedtext_suspended_to_running = ua.LocalizedText("SuspendedToRunning", "en-US")
380
        self.localizedtext_suspended_to_halted = ua.LocalizedText("SuspendedToHalted", "en-US")
381
        self.localizedtext_suspended_to_ready = ua.LocalizedText("SuspendedToReady", "en-US")
382
        self.localizedtext_ready_to_halted = ua.LocalizedText("ReadyToHalted", "en-US")
383
384
    async def install(self, optionals=False):
385
        '''
386
        setup adressspace and initialize 
387
        '''
388
        self._optionals = optionals
389
        self._state_machine_node = await self._parent.add_object(
390
            self._idx, 
391
            self._name, 
392
            objecttype=self._state_machine_type, 
393
            instantiate_optional=optionals
394
            )
395
        #FIXME get children and map children
396
397
    #Transition
398
    async def HaltedToReady(self):
399
        await self._current_state.write_value(
400
            self.localizedtext_ready,
401
            varianttype=ua.VariantType.LocalizedText
402
            ) 
403
        await self._current_state_id.write_value(
404
            self._ready_state.nodeid, 
405
            varianttype=ua.VariantType.NodeId
406
            )
407
        await self._last_transition.write_value(
408
            self.localizedtext_halted_to_ready,
409
            varianttype=ua.VariantType.LocalizedText
410
            ) 
411
        await self._last_transition_id.write_value(
412
            self._halted_to_ready.nodeid,
413
            varianttype=ua.VariantType.NodeId
414
            )
415
        #FIXME 
416
        # trigger ProgramTransitionEventType and 
417
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
418
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
419
420
    #Transition
421
    async def ReadyToRunning(self):
422
        await self._current_state.write_value(
423
            self.localizedtext_running,
424
            varianttype=ua.VariantType.LocalizedText
425
            ) 
426
        await self._current_state_id.write_value(
427
            self._running_state.nodeid, 
428
            varianttype=ua.VariantType.NodeId
429
            )
430
        await self._last_transition.write_value(
431
            self.localizedtext_ready_to_running,
432
            varianttype=ua.VariantType.LocalizedText
433
            ) 
434
        await self._last_transition_id.write_value(
435
            self._ready_to_running.nodeid, 
436
            varianttype=ua.VariantType.NodeId
437
            )
438
        #FIXME 
439
        # trigger ProgramTransitionEventType and 
440
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
441
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
442
443
    #Transition
444
    async def RunningToHalted(self):
445
        await self._current_state.write_value(
446
            self.localizedtext_halted,
447
            varianttype=ua.VariantType.LocalizedText
448
            ) 
449
        await self._current_state_id.write_value(
450
            self._halted_state.nodeid, 
451
            varianttype=ua.VariantType.NodeId
452
            )
453
        await self._last_transition.write_value(
454
            self.localizedtext_running_to_halted,
455
            varianttype=ua.VariantType.LocalizedText
456
            ) 
457
        await self._last_transition_id.write_value(
458
            self._running_to_halted.nodeid, 
459
            varianttype=ua.VariantType.NodeId
460
            )
461
        #FIXME 
462
        # trigger ProgramTransitionEventType and 
463
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
464
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
465
466
    #Transition
467
    async def RunningToReady(self):
468
        await self._current_state.write_value(
469
            self.localizedtext_ready,
470
            varianttype=ua.VariantType.LocalizedText
471
            ) 
472
        await self._current_state_id.write_value(
473
            self._ready_state.nodeid, 
474
            varianttype=ua.VariantType.NodeId
475
            )
476
        await self._last_transition.write_value(
477
            self.localizedtext_running_to_ready,
478
            varianttype=ua.VariantType.LocalizedText
479
            ) 
480
        await self._last_transition_id.write_value(
481
            self._running_to_ready.nodeid, 
482
            varianttype=ua.VariantType.NodeId
483
            )
484
        #FIXME 
485
        # trigger ProgramTransitionEventType and 
486
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
487
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
488
489
    #Transition
490
    async def RunningToSuspended(self):
491
        await self._current_state.write_value(
492
            self.localizedtext_suspended,
493
            varianttype=ua.VariantType.LocalizedText
494
            ) 
495
        await self._current_state_id.write_value(
496
            self._suspended_state.nodeid, 
497
            varianttype=ua.VariantType.NodeId
498
            )
499
        await self._last_transition.write_value(
500
            self.localizedtext_running_to_suspended,
501
            varianttype=ua.VariantType.LocalizedText
502
            ) 
503
        await self._last_transition_id.write_value(
504
            self._running_to_suspended.nodeid, 
505
            varianttype=ua.VariantType.NodeId
506
            )
507
        #FIXME 
508
        # trigger ProgramTransitionEventType and 
509
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
510
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
511
512
    #Transition 
513
    async def SuspendedToRunning(self):
514
        await self._current_state.write_value(
515
            self.localizedtext_running,
516
            varianttype=ua.VariantType.LocalizedText
517
            ) 
518
        await self._current_state_id.write_value(
519
            self._running_state.nodeid, 
520
            varianttype=ua.VariantType.NodeId
521
            )
522
        await self._last_transition.write_value(
523
            self.localizedtext_suspended_to_running,
524
            varianttype=ua.VariantType.LocalizedText
525
            )
526
        await self._last_transition_id.write_value(
527
            self._suspended_to_running.nodeid, 
528
            varianttype=ua.VariantType.NodeId
529
            )
530
        #FIXME 
531
        # trigger ProgramTransitionEventType and 
532
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
533
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
534
535
    #Transition
536
    async def SuspendedToHalted(self):
537
        await self._current_state.write_value(
538
            self.localizedtext_halted,
539
            varianttype=ua.VariantType.LocalizedText
540
            ) 
541
        await self._current_state_id.write_value(
542
            self._halted_state.nodeid, 
543
            varianttype=ua.VariantType.NodeId
544
            )
545
        await self._last_transition.write_value(
546
            self.localizedtext_suspended_to_halted,
547
            varianttype=ua.VariantType.LocalizedText
548
            ) 
549
        await self._last_transition_id.write_value(
550
            self._suspended_to_halted.nodeid, 
551
            varianttype=ua.VariantType.NodeId
552
            )
553
        #FIXME 
554
        # trigger ProgramTransitionEventType and 
555
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
556
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
557
558
    #Transition
559
    async def SuspendedToReady(self):
560
        await self._current_state.write_value(
561
            self.localizedtext_ready,
562
            varianttype=ua.VariantType.LocalizedText
563
            ) 
564
        await self._current_state_id.write_value(
565
            self._ready_state.nodeid, 
566
            varianttype=ua.VariantType.NodeId
567
            )
568
        await self._last_transition.write_value(
569
            self.localizedtext_suspended_to_ready,
570
            varianttype=ua.VariantType.LocalizedText
571
            ) 
572
        await self._last_transition_id.write_value(
573
            self._suspended_to_ready.nodeid, 
574
            varianttype=ua.VariantType.NodeId
575
            )
576
        #FIXME 
577
        # trigger ProgramTransitionEventType and 
578
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
579
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
580
581
    #Transition 
582
    async def ReadyToHalted(self):
583
        await self._current_state.write_value(
584
            self.localizedtext_halted,
585
            varianttype=ua.VariantType.LocalizedText
586
            ) 
587
        await self._current_state_id.write_value(
588
            self._halted_state.nodeid, 
589
            varianttype=ua.VariantType.NodeId
590
            )
591
        await self._last_transition.write_value(
592
            self.localizedtext_ready_to_halted,
593
            varianttype=ua.VariantType.LocalizedText
594
            ) 
595
        await self._last_transition_id.write_value(
596
            self._ready_to_halted.nodeid, 
597
            varianttype=ua.VariantType.NodeId
598
            )
599
        #FIXME 
600
        # trigger ProgramTransitionEventType and 
601
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
602
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
603
604
    #method to be linked to uamethod
605
    async def Start(self):
606
        if await self._current_state.read_value() == self.localizedtext_ready:
607
            return await ReadyToRunning()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ReadyToRunning does not seem to be defined.
Loading history...
608
        else:
609
            return ua.StatusCode(ua.status_codes.StatusCodes.BadNotExecutable)
610
611
    #method to be linked to uamethod
612
    async def Suspend(self):
613
        if await self._current_state.read_value() == self.localizedtext_running:
614
            return await RunningToSuspended()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable RunningToSuspended does not seem to be defined.
Loading history...
615
        else:
616
            return ua.StatusCode(ua.status_codes.StatusCodes.BadNotExecutable)
617
618
    #method to be linked to uamethod
619
    async def Resume(self):
620
        if await self._current_state.read_value() == self.localizedtext_suspended:
621
            return await SuspendedToRunning()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable SuspendedToRunning does not seem to be defined.
Loading history...
622
        else:
623
            return ua.StatusCode(ua.status_codes.StatusCodes.BadNotExecutable)
624
625
    #method to be linked to uamethod
626
    async def Halt(self):
627
        if await self._current_state.read_value() == self.localizedtext_ready:
628
            return await ReadyToHalted()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ReadyToHalted does not seem to be defined.
Loading history...
629
        elif await self._current_state.read_value() == self.localizedtext_running:
630
            return await RunningToHalted()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable RunningToHalted does not seem to be defined.
Loading history...
631
        elif await self._current_state.read_value() == self.localizedtext_suspended:
632
            return await SuspendedToHalted()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable SuspendedToHalted does not seem to be defined.
Loading history...
633
        else:
634
            return ua.StatusCode(ua.status_codes.StatusCodes.BadNotExecutable)
635
636
    #method to be linked to uamethod
637
    async def Reset(self):
638
        if await self._current_state.read_value() == self.localizedtext_halted:
639
            return await HaltedToReady()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable HaltedToReady does not seem to be defined.
Loading history...
640
        else:
641
            return ua.StatusCode(ua.status_codes.StatusCodes.BadNotExecutable)
642
643
class ShelvedStateMachine(FiniteStateMachine):
644
    '''
645
    NOT IMPLEMENTED "ShelvedStateMachineType"
646
    '''
647
    def __init__(self, server=None, parent=None, idx=None, name=None):
648
        super().__init__(server, parent, idx, name)
649
        if name == None:
650
            name = "ShelvedStateMachine"
651
        self._state_machine_type = ua.NodeId(2929, 0)
652
        raise NotImplementedError
653