State Machines

Core concepts for using state-machines in rules and alerts.

Components

Machines

A collection of States, Transitions and Actions. At the end of any given step each serial-sub-state within a machine will contain exactly one active state.

States

A state encapsulates a set of logic to be evaluated when active. States can be hierarchical. A parent state is active if any of its child-states are active. Each state has three phases of execution, entry, during, and exit. When a State changes from inactive to active, its entry actions are evaluated. When a State starts active and ends active (in a given step), its during actions are evaluated. When a State changes from active to inactive, its exit actions are evaluated.

Actions

Actions define processing within various scopes. Actions can be used to update the Machine local variables, set global variables, or make call-outs to external web services.

Transitions

The Transition defines a path between two states, the From-State and the To-State. Once a transition is executed, the From-State becomes inactive and the To-State becomes active. Transitions can include Actions which are evaluated once the transition is executed

Events

An alternate input-scheme which can be used instead-of or alongside local variables. Events can be useful if your approach includes combining several calculations ahead of evaluating the state-machine. The catch is that only a single Event can be handled by the state-machine for any given step.

Execution

State Machine Execution

State Machine Execution

Initialization

Once a Machine is created, it will sit in an uninitialized state, whereby no state is active and no transitions have been evaluated. If the first call to myMachine.step() happens before the machine is initialized, it will automatically initialize the Machine. It’s best practice to explicitly initialize the Machine, once construction is complete by calling myMachine.initialize().

During initialization, at each level in the hierarchy, the initial state is determined during construction by explicitly specifying {initial: true} in the desired state

if two states at the same level are specified as initial, the last one specified wins

From the top of the hierarchy down, each initial-transition is identified and evaluated. The machine is fully initialized once every state has the appropriate number of active states as defined by it’s Decomposition (serial vs parallel).

Step

Once a Machine is initialized, it can be “stepped” through time. Each step represents a discrete point in time (in our specific case, the machine is “stepped” upon receipt of each IoT Message).

During the step, all Transitions from the active state hierarchy are evaluated from the top, down. That is to say, given active state, B.B.B, all Transitions out of the top state B are evaluated in priority order, executing the first Transition who’s condition expression evaluates to true or who’s condition doesn’t exists (i.e. an Unconditional Transition). If no Transitions at level B are to be executed, all Transitions at the B.B level are evaluated in the same manor until either a Transition is identified to evaluate, or no Transitions are to be taken.

If a Transition is identified to evaluate, first the exit actions in the lowest level From-State are evaluated, then the exit actions are evaluated up the hierarchy until the lowest-common State between From-State and To-State. Meaning in a transition from B.B.B to B.B.A, only the exit actions from B.B.B are evaluated (since B.B is never exited during the transition). Whereas if transitioning from B.B.B to A.B, the exit actions at B.B.B, B.B, and B are evaluated.

If no Transitions are to be evaluated, the during actions of the current active state are evaluated from the top, down.

Examples

Full Example

Illustrative (not functional) State Machine containing all possible features of the State Machine library.

Initialization:

  1. The initial transition into B is evaluated and the local variable, time0 is set to now.
  2. B is activated.
  3. B entry actions are evaluated, incrementing the machine variable, bEntry
  4. States B.A and B.B run in parallel (indicated by the dashed border). B.A and B.B are activated.
  5. So, the initial transitions into B.A.B and B.B.B are executed.
  6. Both B.A.B and B.B.B are activated.

Step 1:

  1. Both B.A.B and B.B.B are active.
  2. First there exists a transition at the top level, somethingElse < 50. If this evaluates to true, then all active children of B are exited and deactivated from the bottom up. For this example let’s assume somethingElse = 100, so this transition will not be executed.
  3. Since the transition from B.B.B to B.B.A is unconditional, it is marked for evaluation.
  4. B.B.B exit actions are evaluated (local variable, bbbExit is incremented)
  5. B.B.B is deactivated
  6. If there were any actions defined on this transition, they’d be evaluated here.
  7. B.B.A is activated
  8. B.B.A entry actions are evaluated (local variable, bba is now true)
  9. B during actions are evaluated (bDuring is incremented)

Step 2:

  1. Both B.A.B and B.B.A are active.
  2. There are two transitions out of B.B.A (priority can be set on transitions to handle this case). If something < 10, then transition 1 would be marked for evaluation, otherwise, transition 2 is unconditional, so it will be marked for evaluation by default. For this example, let’s say something = 6, so transition 1 is marked for evaluation.
  3. B.B.A is deactivated
  4. B.A.B is deactivated
  5. B.A is deactivated
  6. B.B is deactivated
  7. B.B exit actions are evaluated (bbExit is incremented)
  8. B is deactivated
  9. If there were any actions defined on this transition, they’d be evaluated here.
  10. A is activated
  11. A.A is activated

Advanced Topics

State-Decomposition

At any given level in the state-hierarchy, there are two possible modes of execution: Serial (default) and Parallel. Serial decomposition defines that at a given level, there is only ever a single active state at the end of any give step. Contrary, Parallel decomposition defines that all states at a given level are active. In the examples below, the Serial State Machine will only ever have a single active state (e.g. 'A.B' or 'B.A.B'), whereas the Parallel State Machine will have 3 active states at any given time (e.g. ['A.A', 'B.A.B', 'B.B.A'] etc.)

Serial State Machine

Serial State Machine

Parallel State Machine

Parallel State Machine