Completed
Pull Request — master (#348)
by
unknown
03:10
created

ProgramStateMachineTypeClass.Resume()   A

Complexity

Conditions 2

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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