Skip to content

How-to guide

State machines

Define finite state machines in the server with enumerations and attributes, and change their states at runtime.

This content was machine translated and may contain errors. Read in German

How-to guide

State machines ​

Types usedOpcFiniteStateMachineNodeOpcStateMachineStatesAttributeOpcStateMachineTransitionAttributeOpcStateMachineTransitionsAttributeOpcStateMachineInitialStateAttribute

Many information models describe the state of a machine or a process with a finite state machine (FiniteStateMachineType as defined in OPC UA Part 16). Such a state machine has a fixed set of states and the allowed transitions between them. It provides its current state through the child nodes CurrentState and LastTransition, which clients can read and subscribe to. In the server, you define such a state machine with the OpcFiniteStateMachineNode<T> class.

Define the states ​

You define the states with an enumeration. The value of an entry is the number of the state, and its name is the name of the state:

csharp
public enum MachineState : uint
{
    Stopped = 0,
    Starting = 1,
    Running = 2,
    Stopping = 3
}
vbnet
Public Enum MachineState As UInteger
    Stopped = 0
    Starting = 1
    Running = 2
    Stopping = 3
End Enum

Define the state machine class ​

You define the state machine itself as a subclass of the OpcFiniteStateMachineNode<T> class and describe it with attributes:

  • OpcStateMachineStates defines the enumeration of the states.
  • OpcStateMachineTransition defines one allowed transition from one state to another.
  • OpcStateMachineInitialState defines the state that the state machine takes when it is created in the address space. Without this attribute, it takes the first of its states.
csharp
[OpcStateMachineStates(typeof(MachineState))]
[OpcStateMachineTransition(MachineState.Stopped, MachineState.Starting)]
[OpcStateMachineTransition(MachineState.Starting, MachineState.Running)]
[OpcStateMachineTransition(MachineState.Running, MachineState.Stopping)]
[OpcStateMachineTransition(MachineState.Stopping, MachineState.Stopped)]
[OpcStateMachineInitialState(MachineState.Stopped)]
public class MachineStateMachineNode : OpcFiniteStateMachineNode<MachineState>
{
    public MachineStateMachineNode(IOpcNode parent, OpcName name)
        : base(parent, name)
    {
    }
}
vbnet
<OpcStateMachineStates(GetType(MachineState))>
<OpcStateMachineTransition(MachineState.Stopped, MachineState.Starting)>
<OpcStateMachineTransition(MachineState.Starting, MachineState.Running)>
<OpcStateMachineTransition(MachineState.Running, MachineState.Stopping)>
<OpcStateMachineTransition(MachineState.Stopping, MachineState.Stopped)>
<OpcStateMachineInitialState(MachineState.Stopped)>
Public Class MachineStateMachineNode
    Inherits OpcFiniteStateMachineNode(Of MachineState)

    Public Sub New(ByVal parent As IOpcNode, ByVal name As OpcName)
        MyBase.New(parent, name)
    End Sub
End Class

If the states follow each other in the order of the enumeration, the OpcStateMachineTransitions attribute is enough instead of the individual transitions. It defines the transitions from each state to the next one and, with IsLoop, also the transition from the last state to the first one:

csharp
// Transitions from each state to the next one and from the last state to the first one.
[OpcStateMachineStates(typeof(MachineState))]
[OpcStateMachineTransitions(typeof(MachineState), IsLoop = true)]
public class MachineCycleNode : OpcFiniteStateMachineNode<MachineState>
{
    public MachineCycleNode(IOpcNode parent, OpcName name)
        : base(parent, name)
    {
    }
}
vbnet
'Transitions from each state to the next one and from the last state to the first one.
<OpcStateMachineStates(GetType(MachineState))>
<OpcStateMachineTransitions(GetType(MachineState), IsLoop:=True)>
Public Class MachineCycleNode
    Inherits OpcFiniteStateMachineNode(Of MachineState)

    Public Sub New(ByVal parent As IOpcNode, ByVal name As OpcName)
        MyBase.New(parent, name)
    End Sub
End Class

Create the state machine in the address space ​

You create the state machine in the node manager like any other node, for example as a child node of the machine whose state it describes:

csharp
// MyNodeManager.CreateNodes(...)
var machineNode = new OpcObjectNode(new OpcName("Machine", this.DefaultNamespaceIndex));
var machineStateNode = new MachineStateMachineNode(machineNode, "State");
vbnet
'MyNodeManager.CreateNodes(...)
Dim machineNode = New OpcObjectNode(New OpcName("Machine", Me.DefaultNamespaceIndex))
Dim machineStateNode = New MachineStateMachineNode(machineNode, "State")

Change the state ​

You change the state with the ChangeStateTo method. It applies the change and notifies all clients that subscribe to the state. If there is no transition from the current state to the requested state, the method throws an InvalidOperationException. The CanChangeStateTo method determines beforehand whether a change is allowed. If the state machine is already in the requested state, the call has no effect:

csharp
if (machineStateNode.CanChangeStateTo(server.SystemContext, MachineState.Starting))
    machineStateNode.ChangeStateTo(server.SystemContext, MachineState.Starting);
 
// Throws an InvalidOperationException, because there is no transition
// from the state Starting to the state Stopped.
machineStateNode.ChangeStateTo(server.SystemContext, MachineState.Stopped);
vbnet
If machineStateNode.CanChangeStateTo(server.SystemContext, MachineState.Starting) Then
    machineStateNode.ChangeStateTo(server.SystemContext, MachineState.Starting)
End If

'Throws an InvalidOperationException, because there is no transition
'from the state Starting to the state Stopped.
machineStateNode.ChangeStateTo(server.SystemContext, MachineState.Stopped)

The CurrentState property returns the current state, and the LastTransition property returns the most recent transition. If a state machine from an information model does not support the CurrentState child node, a subclass can indicate this with the SupportsCurrentState property. State changes then have no effect.