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

ProgramStateMachine.__init__()   B

Complexity

Conditions 2

Size

Total Lines 62
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 50
nop 5
dl 0
loc 62
rs 8.6363
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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