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

asyncua.common.statemachine.main()   B

Complexity

Conditions 3

Size

Total Lines 54
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

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