Passed
Pull Request — master (#348)
by
unknown
02:44
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
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.instantiate_util import instantiate
26
27
class StateMachineTypeClass(object):
28
    '''
29
    Implementation of an StateMachineType (most basic type)
30
    '''
31
    def __init__(self, server=None, parent=None, idx=None, name=None):
32
        if not server: raise ValueError #FIXME change to check instance type
33
        if not parent: raise ValueError #FIXME change to check instance type
34
        if idx == None:
35
            idx = parent.nodeid.NamespaceIndex
36
        if name == None:
37
            name = "StateMachine"
38
        self._server = server
39
        self._parent = parent
40
        self._state_machine_node = None
41
        self._state_machine_type = ua.NodeId(2299, 0)
42
        self._name = name
43
        self._idx = idx
44
        self._optionals = False
45
        self._current_state_node = None
46
        self._current_state_id_node = None
47
        self._last_transition_node = None
48
        self._last_transition_id_node = None
49
50
    async def install(self, optionals=False):
51
        '''
52
        setup adressspace and initialize 
53
        '''
54
        self._optionals = optionals
55
        self._state_machine_node = await self._parent.add_object(
56
            self._idx, 
57
            self._name, 
58
            objecttype=self._state_machine_type, 
59
            instantiate_optional=optionals
60
            )
61
        self._current_state_node = await self._state_machine_node.get_child(["CurrentState"])
62
        self._current_state_id_node = await self._state_machine_node.get_child(["CurrentState","Id"])
63
        if self._optionals:
64
            self._last_transition_node = await self._state_machine_node.get_child(["LastTransition"])
65
            self._last_transition_id_node = await self._state_machine_node.get_child(["LastTransition","Id"])
66
67
        #FIXME initialise values
68
        '''
69
        maybe its smart to check parents children for a initial state instance (InitialStateType) 
70
        and initialize it with its id but if no state instance is provided ... i will log a 
71
        warning
72
        '''
73
74
    async def change_state(self, state_name, state_node, transition_name=None, transition_node=None):
75
        '''
76
        method to change the state of the statemachine
77
        state_name: ua.LocalizedText()
78
        state: ua.NodeId() <- StateType node
79
        transition_name: ua.LocalizedText()
80
        transition: ua.NodeId() <- TransitionType node
81
        '''
82
        #FIXME check StateType exist
83
        #FIXME check TransitionTypeType exist
84
        await self.write_state(state_name, state_node)
85
        if self._optionals and transition_name and transition_node:
86
            await self.write_transition(transition_name, transition_node)
87
        #FIXME trigger TransitionEventType
88
89
    async def write_state(self, state_name, state_node):
90
        #FIXME check types/class
91
        await self._current_state_node.write_value(state_name)
92
        await self._current_state_id_node.write_value(state_node)
93
94
    async def write_transition(self, transition_name, transition_node):
95
        #FIXME check types/class
96
        await self._last_transition_node.write_value(transition_name)
97
        await self._last_transition_id_node.write_value(transition_node)
98
    
99
    async def add_state(self, name, state_type=ua.NodeId(2307, 0), optionals=False):
100
        '''
101
        initial state -> ua.NodeId(2309, 0)
102
        state -> ua.NodeId(2307, 0)
103
        '''
104
        #FIXME check types/class
105
        return await self._state_machine_node.add_object(
106
            self._idx, 
107
            name, 
108
            objecttype=state_type, 
109
            instantiate_optional=optionals
110
            )
111
112
    async def add_transition(self, name, transition_type=ua.NodeId(2310, 0), optionals=False):
113
        #FIXME check types/class
114
        return await self._state_machine_node.add_object(
115
            self._idx, 
116
            name, 
117
            objecttype=transition_type, 
118
            instantiate_optional=optionals
119
            )
120
121
    # async def remove(self):
122
    #     #FIXME
123
    #     raise NotImplementedError
124
125
    # async def add_substate(self):
126
    #     #FIXME
127
    #     raise NotImplementedError
128
129
    # async def add_subtransition(self):
130
    #     #FIXME
131
    #     raise NotImplementedError
132
133
class FiniteStateMachineTypeClass(StateMachineTypeClass):
134
    '''
135
    Implementation of an FiniteStateMachineType a little more advanced than the basic one
136
    if you need to know the avalible states and transition from clientside
137
    '''
138
    def __init__(self, server=None, parent=None, idx=None, name=None):
139
        super().__init__(server, parent, idx, name)
140
        if name == None:
141
            name = "FiniteStateMachine"
142
        self._state_machine_type = ua.NodeId(2771, 0)
143
        self._avalible_states_node = None
144
        self._avalible_transitions_node = None
145
146
    async def install(self, avalible_states, avalible_transitions, optionals=False):
147
        '''
148
        setup adressspace and initialize 
149
        '''
150
        self._optionals = optionals
151
        self._state_machine_node = await self._parent.add_object(
152
            self._idx, 
153
            self._name, 
154
            objecttype=self._state_machine_type, 
155
            instantiate_optional=optionals
156
            )
157
        #FIXME get children and map children
158
        await self.set_avalible_states(avalible_states)
159
        await self.set_avalible_transitions(avalible_transitions)
160
161
    async def set_avalible_states(self, states):
162
        #check if its list
163
        await self._avalible_states_node.write_value(states, varianttype=ua.VariantType.NodeId)
164
165
    async def set_avalible_transitions(self, transitions):
166
        await self._avalible_transitions_node.write_value(transitions, varianttype=ua.VariantType.NodeId)
167
168
class ExclusiveLimitStateMachineTypeClass(FiniteStateMachineTypeClass):
169
    '''
170
    NOT IMPLEMENTED "ExclusiveLimitStateMachineType"
171
    '''
172
    def __init__(self, server=None, parent=None, idx=None, name=None):
173
        super().__init__(server, parent, idx, name)
174
        if name == None:
175
            name = "ExclusiveLimitStateMachine"
176
        self._state_machine_type = ua.NodeId(9318, 0)
177
        raise NotImplementedError
178
179
class FileTransferStateMachineTypeClass(FiniteStateMachineTypeClass):
180
    '''
181
    NOT IMPLEMENTED "FileTransferStateMachineType"
182
    '''
183
    def __init__(self, server=None, parent=None, idx=None, name=None):
184
        super().__init__(server, parent, idx, name)
185
        if name == None:
186
            name = "FileTransferStateMachine"
187
        self._state_machine_type = ua.NodeId(15803, 0)
188
        raise NotImplementedError
189
190
class ProgramStateMachineTypeClass(FiniteStateMachineTypeClass):
191
    '''
192
    https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.3/
193
    Implementation of an ProgramStateMachine its quite a complex statemachine with the 
194
    optional possibility to make the statchange from clientside via opcua-methods
195
    '''
196
    def __init__(self, server=None, parent=None, idx=None, name=None):
197
        super().__init__(server, parent, idx, name)
198
        if name == None:
199
            name = "ProgramStateMachine"
200
        self._state_machine_type = ua.NodeId(2391, 0)
201
202
        # 5.2.3.2 ProgramStateMachineType states
203
        self._ready_state_node = None #State node
204
        self._halted_state_node = None #State node
205
        self._running_state_node = None #State node
206
        self._suspended_state_node = None #State node
207
208
        # 5.2.3.3 ProgramStateMachineType transitions
209
        self._halted_to_ready_node = None #Transition node
210
        self._ready_to_running_node = None #Transition node
211
        self._running_to_halted_node = None #Transition node
212
        self._running_to_ready_node = None #Transition node
213
        self._running_to_suspended_node = None #Transition node
214
        self._suspended_to_running_node = None #Transition node
215
        self._suspended_to_halted_node = None #Transition node
216
        self._suspended_to_ready_node = None #Transition node
217
        self._ready_to_halted_node = None #Transition node
218
219
        # 5.2.3.2 ProgramStateMachineType states
220
        self._halted_state_id_node = None #State property (StateNumber value 11)
221
        self._ready_state_id_node = None #State property (StateNumber value 12)
222
        self._running_state_id_node = None #State property (StateNumber value 13)
223
        self._suspended_state_id_node = None #State property (StateNumber value 14)
224
225
        # 5.2.3.3 ProgramStateMachineType transitions
226
        self._halted_to_ready_id_node = None #Transition property (TransitionNumber value 1)
227
        self._ready_to_running_id_node = None #Transition property (TransitionNumber value 2)
228
        self._running_to_halted_id_node = None #Transition property (TransitionNumber value 3)
229
        self._running_to_ready_id_node = None #Transition property (TransitionNumber value 4)
230
        self._running_to_suspended_id_node = None #Transition property (TransitionNumber value 5)
231
        self._suspended_to_running_id_node = None #Transition property (TransitionNumber value 6)
232
        self._suspended_to_halted_id_node = None #Transition property (TransitionNumber value 7)
233
        self._suspended_to_ready_id_node = None #Transition property (TransitionNumber value 8)
234
        self._ready_to_halted_id_node = None #Transition property (TransitionNumber value 9)
235
236
        # 4.2.7 Program Control Methods (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.7/)
237
        self._halt_method_node = None #uamethod node
238
        self._reset_method_node = None #uamethod node
239
        self._resume_method_node = None #uamethod node
240
        self._start_method_node = None #uamethod node
241
        self._suspend_method_node = None #uamethod node
242
243
        #can be overwritten if you want a different language
244
        self.localizedtext_ready = ua.LocalizedText("Ready", "en-US")
245
        self.localizedtext_running = ua.LocalizedText("Running", "en-US")
246
        self.localizedtext_halted = ua.LocalizedText("Halted", "en-US")
247
        self.localizedtext_suspended= ua.LocalizedText("Suspended", "en-US")
248
        self.localizedtext_halted_to_ready = ua.LocalizedText("HaltedToReady", "en-US")
249
        self.localizedtext_ready_to_running = ua.LocalizedText("ReadyToRunning", "en-US")
250
        self.localizedtext_running_to_halted = ua.LocalizedText("RunningToHalted", "en-US")
251
        self.localizedtext_running_to_ready = ua.LocalizedText("RunningToReady", "en-US")
252
        self.localizedtext_running_to_suspended = ua.LocalizedText("RunningToSuspended", "en-US")
253
        self.localizedtext_suspended_to_running = ua.LocalizedText("SuspendedToRunning", "en-US")
254
        self.localizedtext_suspended_to_halted = ua.LocalizedText("SuspendedToHalted", "en-US")
255
        self.localizedtext_suspended_to_ready = ua.LocalizedText("SuspendedToReady", "en-US")
256
        self.localizedtext_ready_to_halted = ua.LocalizedText("ReadyToHalted", "en-US")
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
        #FIXME get children and map children
270
271
    #Transition
272
    async def HaltedToReady(self):
273
        await self._current_state.write_value(
274
            self.localizedtext_ready,
275
            varianttype=ua.VariantType.LocalizedText
276
            ) 
277
        await self._current_state_id.write_value(
278
            self._ready_state.nodeid, 
279
            varianttype=ua.VariantType.NodeId
280
            )
281
        await self._last_transition.write_value(
282
            self.localizedtext_halted_to_ready,
283
            varianttype=ua.VariantType.LocalizedText
284
            ) 
285
        await self._last_transition_id.write_value(
286
            self._halted_to_ready.nodeid,
287
            varianttype=ua.VariantType.NodeId
288
            )
289
        #FIXME 
290
        # trigger ProgramTransitionEventType and 
291
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
292
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
293
294
    #Transition
295
    async def ReadyToRunning(self):
296
        await self._current_state.write_value(
297
            self.localizedtext_running,
298
            varianttype=ua.VariantType.LocalizedText
299
            ) 
300
        await self._current_state_id.write_value(
301
            self._running_state.nodeid, 
302
            varianttype=ua.VariantType.NodeId
303
            )
304
        await self._last_transition.write_value(
305
            self.localizedtext_ready_to_running,
306
            varianttype=ua.VariantType.LocalizedText
307
            ) 
308
        await self._last_transition_id.write_value(
309
            self._ready_to_running.nodeid, 
310
            varianttype=ua.VariantType.NodeId
311
            )
312
        #FIXME 
313
        # trigger ProgramTransitionEventType and 
314
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
315
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
316
317
    #Transition
318
    async def RunningToHalted(self):
319
        await self._current_state.write_value(
320
            self.localizedtext_halted,
321
            varianttype=ua.VariantType.LocalizedText
322
            ) 
323
        await self._current_state_id.write_value(
324
            self._halted_state.nodeid, 
325
            varianttype=ua.VariantType.NodeId
326
            )
327
        await self._last_transition.write_value(
328
            self.localizedtext_running_to_halted,
329
            varianttype=ua.VariantType.LocalizedText
330
            ) 
331
        await self._last_transition_id.write_value(
332
            self._running_to_halted.nodeid, 
333
            varianttype=ua.VariantType.NodeId
334
            )
335
        #FIXME 
336
        # trigger ProgramTransitionEventType and 
337
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
338
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
339
340
    #Transition
341
    async def RunningToReady(self):
342
        await self._current_state.write_value(
343
            self.localizedtext_ready,
344
            varianttype=ua.VariantType.LocalizedText
345
            ) 
346
        await self._current_state_id.write_value(
347
            self._ready_state.nodeid, 
348
            varianttype=ua.VariantType.NodeId
349
            )
350
        await self._last_transition.write_value(
351
            self.localizedtext_running_to_ready,
352
            varianttype=ua.VariantType.LocalizedText
353
            ) 
354
        await self._last_transition_id.write_value(
355
            self._running_to_ready.nodeid, 
356
            varianttype=ua.VariantType.NodeId
357
            )
358
        #FIXME 
359
        # trigger ProgramTransitionEventType and 
360
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
361
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
362
363
    #Transition
364
    async def RunningToSuspended(self):
365
        await self._current_state.write_value(
366
            self.localizedtext_suspended,
367
            varianttype=ua.VariantType.LocalizedText
368
            ) 
369
        await self._current_state_id.write_value(
370
            self._suspended_state.nodeid, 
371
            varianttype=ua.VariantType.NodeId
372
            )
373
        await self._last_transition.write_value(
374
            self.localizedtext_running_to_suspended,
375
            varianttype=ua.VariantType.LocalizedText
376
            ) 
377
        await self._last_transition_id.write_value(
378
            self._running_to_suspended.nodeid, 
379
            varianttype=ua.VariantType.NodeId
380
            )
381
        #FIXME 
382
        # trigger ProgramTransitionEventType and 
383
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
384
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
385
386
    #Transition 
387
    async def SuspendedToRunning(self):
388
        await self._current_state.write_value(
389
            self.localizedtext_running,
390
            varianttype=ua.VariantType.LocalizedText
391
            ) 
392
        await self._current_state_id.write_value(
393
            self._running_state.nodeid, 
394
            varianttype=ua.VariantType.NodeId
395
            )
396
        await self._last_transition.write_value(
397
            self.localizedtext_suspended_to_running,
398
            varianttype=ua.VariantType.LocalizedText
399
            )
400
        await self._last_transition_id.write_value(
401
            self._suspended_to_running.nodeid, 
402
            varianttype=ua.VariantType.NodeId
403
            )
404
        #FIXME 
405
        # trigger ProgramTransitionEventType and 
406
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
407
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
408
409
    #Transition
410
    async def SuspendedToHalted(self):
411
        await self._current_state.write_value(
412
            self.localizedtext_halted,
413
            varianttype=ua.VariantType.LocalizedText
414
            ) 
415
        await self._current_state_id.write_value(
416
            self._halted_state.nodeid, 
417
            varianttype=ua.VariantType.NodeId
418
            )
419
        await self._last_transition.write_value(
420
            self.localizedtext_suspended_to_halted,
421
            varianttype=ua.VariantType.LocalizedText
422
            ) 
423
        await self._last_transition_id.write_value(
424
            self._suspended_to_halted.nodeid, 
425
            varianttype=ua.VariantType.NodeId
426
            )
427
        #FIXME 
428
        # trigger ProgramTransitionEventType and 
429
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
430
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
431
432
    #Transition
433
    async def SuspendedToReady(self):
434
        await self._current_state.write_value(
435
            self.localizedtext_ready,
436
            varianttype=ua.VariantType.LocalizedText
437
            ) 
438
        await self._current_state_id.write_value(
439
            self._ready_state.nodeid, 
440
            varianttype=ua.VariantType.NodeId
441
            )
442
        await self._last_transition.write_value(
443
            self.localizedtext_suspended_to_ready,
444
            varianttype=ua.VariantType.LocalizedText
445
            ) 
446
        await self._last_transition_id.write_value(
447
            self._suspended_to_ready.nodeid, 
448
            varianttype=ua.VariantType.NodeId
449
            )
450
        #FIXME 
451
        # trigger ProgramTransitionEventType and 
452
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
453
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
454
455
    #Transition 
456
    async def ReadyToHalted(self):
457
        await self._current_state.write_value(
458
            self.localizedtext_halted,
459
            varianttype=ua.VariantType.LocalizedText
460
            ) 
461
        await self._current_state_id.write_value(
462
            self._halted_state.nodeid, 
463
            varianttype=ua.VariantType.NodeId
464
            )
465
        await self._last_transition.write_value(
466
            self.localizedtext_ready_to_halted,
467
            varianttype=ua.VariantType.LocalizedText
468
            ) 
469
        await self._last_transition_id.write_value(
470
            self._ready_to_halted.nodeid, 
471
            varianttype=ua.VariantType.NodeId
472
            )
473
        #FIXME 
474
        # trigger ProgramTransitionEventType and 
475
        # AuditUpdateMethodEvents/AuditProgramTransitionEventType (https://reference.opcfoundation.org/v104/Core/docs/Part10/4.2.2/)
476
        return ua.StatusCode(ua.status_codes.StatusCodes.Good)
477
478
    #method to be linked to uamethod
479
    async def Start(self):
480
        if await self._current_state.read_value() == self.localizedtext_ready:
481
            return await ReadyToRunning()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ReadyToRunning does not seem to be defined.
Loading history...
482
        else:
483
            return ua.StatusCode(ua.status_codes.StatusCodes.BadNotExecutable)
484
485
    #method to be linked to uamethod
486
    async def Suspend(self):
487
        if await self._current_state.read_value() == self.localizedtext_running:
488
            return await RunningToSuspended()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable RunningToSuspended does not seem to be defined.
Loading history...
489
        else:
490
            return ua.StatusCode(ua.status_codes.StatusCodes.BadNotExecutable)
491
492
    #method to be linked to uamethod
493
    async def Resume(self):
494
        if await self._current_state.read_value() == self.localizedtext_suspended:
495
            return await SuspendedToRunning()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable SuspendedToRunning does not seem to be defined.
Loading history...
496
        else:
497
            return ua.StatusCode(ua.status_codes.StatusCodes.BadNotExecutable)
498
499
    #method to be linked to uamethod
500
    async def Halt(self):
501
        if await self._current_state.read_value() == self.localizedtext_ready:
502
            return await ReadyToHalted()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable ReadyToHalted does not seem to be defined.
Loading history...
503
        elif await self._current_state.read_value() == self.localizedtext_running:
504
            return await RunningToHalted()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable RunningToHalted does not seem to be defined.
Loading history...
505
        elif await self._current_state.read_value() == self.localizedtext_suspended:
506
            return await SuspendedToHalted()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable SuspendedToHalted does not seem to be defined.
Loading history...
507
        else:
508
            return ua.StatusCode(ua.status_codes.StatusCodes.BadNotExecutable)
509
510
    #method to be linked to uamethod
511
    async def Reset(self):
512
        if await self._current_state.read_value() == self.localizedtext_halted:
513
            return await HaltedToReady()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable HaltedToReady does not seem to be defined.
Loading history...
514
        else:
515
            return ua.StatusCode(ua.status_codes.StatusCodes.BadNotExecutable)
516
517
class ShelvedStateMachineTypeClass(FiniteStateMachineTypeClass):
518
    '''
519
    NOT IMPLEMENTED "ShelvedStateMachineType"
520
    '''
521
    def __init__(self, server=None, parent=None, idx=None, name=None):
522
        super().__init__(server, parent, idx, name)
523
        if name == None:
524
            name = "ShelvedStateMachine"
525
        self._state_machine_type = ua.NodeId(2929, 0)
526
        raise NotImplementedError
527
528
529
530
#FIXME REMOVE BEFOR MERGE
531
#Devtest / Workbench
532
if __name__ == "__main__":
533
    async def main():
534
        logging.basicConfig(level=logging.INFO)
535
        _logger = logging.getLogger('asyncua')
536
537
        server = Server()
538
        await server.init()
539
540
        sm = StateMachineTypeClass(server, server.nodes.objects, 0, "StateMachine")
541
        await sm.install(True)
542
        await sm.add_state("Initstate", ua.NodeId(2309, 0))
543
        await sm.add_state("State1")
544
        await sm.add_state("State2")
545
        await sm.add_state("State3")
546
        await sm.add_state("State4")
547
        await sm.add_transition("Transition1")
548
        await sm.add_transition("Transition2")
549
        await sm.add_transition("Transition3")
550
        await sm.add_transition("Transition4")
551
        await sm.add_transition("Transition5")
552
        await sm.change_state(
553
            ua.LocalizedText("Test3", "en-US"), 
554
            server.get_node("ns=0;i=2253").nodeid,
555
            ua.LocalizedText("Test4", "en-US"), 
556
            server.get_node("ns=0;i=2253").nodeid
557
            )
558
559
        # fsm = FiniteStateMachineTypeClass(server, server.nodes.objects, 0, "FiniteStateMachine")
560
        # await fsm.install(True)
561
        # pfsm = ProgramStateMachineTypeClass(server, server.nodes.objects, 0, "ProgramStateMachine")
562
        # await pfsm.install(True)
563
564
        async with server:
565
            while 1:
566
                await asyncio.sleep(0)
567
568
    asyncio.run(main())
569