Passed
Pull Request — master (#348)
by
unknown
02:32
created

asyncua.common.statemachine   F

Complexity

Total Complexity 64

Size/Duplication

Total Lines 633
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 400
dl 0
loc 633
rs 3.28
c 0
b 0
f 0
wmc 64

37 Methods

Rating   Name   Duplication   Size   Complexity  
A FiniteStateMachineTypeClass.__init__() 0 7 2
A ProgramStateMachineTypeClass.install() 0 10 1
A TransitionTypeClass.__init__() 0 5 1
A StateMachineTypeClass.init() 0 11 2
A ProgramStateMachineTypeClass.Resume() 0 5 2
A FiniteStateMachineTypeClass.set_avalible_states() 0 3 1
A StateMachineTypeClass.add_transition() 0 16 2
A ProgramStateMachineTypeClass.SuspendedToRunning() 0 21 1
A ShelvedStateMachineTypeClass.__init__() 0 6 2
A FiniteStateMachineTypeClass.find_all_states() 0 2 1
A FiniteStateMachineTypeClass.init() 0 6 1
B StateMachineTypeClass.__init__() 0 22 5
A ProgramStateMachineTypeClass.SuspendedToHalted() 0 21 1
A ProgramStateMachineTypeClass.ReadyToRunning() 0 21 1
A StateMachineTypeClass.change_state() 0 25 4
A ExclusiveLimitStateMachineTypeClass.__init__() 0 6 2
A ProgramStateMachineTypeClass.RunningToHalted() 0 21 1
A ProgramStateMachineTypeClass.HaltedToReady() 0 21 1
B ProgramStateMachineTypeClass.__init__() 0 61 2
A StateMachineTypeClass._write_state() 0 4 2
A ProgramStateMachineTypeClass.SuspendedToReady() 0 21 1
A StateMachineTypeClass._write_transition() 0 4 2
A ProgramStateMachineTypeClass.Start() 0 5 2
A StateMachineTypeClass.install() 0 12 1
A ProgramStateMachineTypeClass.Reset() 0 5 2
A ProgramStateMachineTypeClass.Suspend() 0 5 2
A StateMachineTypeClass.add_state() 0 18 2
A ProgramStateMachineTypeClass.ReadyToHalted() 0 21 1
A StateMachineTypeClass.remove() 0 3 1
A FiniteStateMachineTypeClass.find_all_transitions() 0 2 1
A ProgramStateMachineTypeClass.RunningToReady() 0 21 1
A FiniteStateMachineTypeClass.set_avalible_transitions() 0 3 1
A ProgramStateMachineTypeClass.RunningToSuspended() 0 21 1
A StateTypeClass.__init__() 0 5 1
A ProgramStateMachineTypeClass.Halt() 0 9 4
A FileTransferStateMachineTypeClass.__init__() 0 6 2
A FiniteStateMachineTypeClass.install() 0 10 1

1 Function

Rating   Name   Duplication   Size   Complexity  
B main() 0 47 3

How to fix   Complexity   

Complexity

Complex classes like asyncua.common.statemachine often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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