Build Sequential Function Charts as Python classes, then watch the visual editor update live.
The visual editor is fast for sketching. Python lets you do things drag-and-drop cannot: generate dozens of similar steps with a for loop, reuse logic with inheritance and mixins (see Object-Oriented Sequences), parametrise sequences from configuration, and track diffs in Git as readable text.
Both views stay in sync. Every .seq file has a Python source and a graphical representation, and AutomationView regenerates each from the other on save.
Switch with the command palette (Ctrl+Shift+P):
| Command | Effect |
|---|---|
AutomationView: Open Visual Editor |
Show the graphical SFC diagram |
AutomationView: Open Text Editor |
Show the Python source |
automation_machine ModuleEvery sequence file starts by importing what it needs from automation_machine. The most common imports:
from automation_machine import (
Sequence,
StepType,
ActionQualifier,
ActionInstruction,
)
| Name | Role |
|---|---|
Sequence |
Base class - your sequence inherits from this |
StepType |
Enum - INITIAL, NORMAL, MACRO, ENCLOSING |
ActionQualifier |
Enum - controls when an action runs (N, S, R, P, D, L, SD, DS, SL) |
ActionInstruction |
Enum - controls what an action does (TON, MOVE, CTU...) |
For the complete API surface, see the Python API reference.
A sequence is a class that inherits from Sequence and implements setup(). AutomationView calls setup() once when the file is parsed.
from automation_machine import Sequence, StepType
class MySequence(Sequence):
def setup(self):
# 1. Declare steps
# 2. Declare transitions
# 3. Attach actions to steps
pass
The
setup()method is the lifecycle hook AutomationView relies on. Do not put step or transition declarations in__init__- they belong insetup().
self.add_step() creates a step and returns a Step instance. Keep a reference to it so you can wire transitions and actions later.
s0 = self.add_step(StepType.INITIAL, name="Idle")
s1 = self.add_step(name="Extending")
s2 = self.add_step(name="Retracted")
| Parameter | Type | Notes |
|---|---|---|
step_type |
StepType |
Defaults to NORMAL. Exactly one step must be INITIAL. |
name |
str |
Displayed in the diagram. Optional but recommended. |
comment |
str |
Free-form documentation, shown on hover. |
Every sequence needs exactly one
StepType.INITIALstep. Forgetting it leaves the SFC with no entry point and the validator will flag the file.
A transition links a source step to a target step and crosses when its boolean condition is TRUE.
self.add_transition(s0, s1, condition="start_button AND NOT safety_fault")
self.add_transition(s1, s2, condition="sensor_extended")
self.add_transition(s2, s0, condition="sensor_retracted")
| Parameter | Type | Notes |
|---|---|---|
source_step |
Step or list[Step] |
Single step or list (for convergence) |
target_step |
Step or list[Step] |
Single step or list (for divergence) |
condition |
str |
Boolean expression - variables, operators, function outputs |
comment |
str |
Optional inline note |
Conditions are written in plain IEC 61131-3 text: AND, OR, NOT, =, <>, <, >, <=, >=. Reference variables by name and instruction outputs with the dot notation (timer_extend.Q, counter.CV).
Actions live on steps. They describe what the controller does while a step is active.
s1.add_action(
"cmd_extend",
description="Energize extend solenoid",
qualifier=ActionQualifier.N,
)
| Parameter | Type | Notes |
|---|---|---|
name |
str |
Variable or function block instance the action drives |
description |
str |
Human-readable label shown in the diagram |
qualifier |
ActionQualifier |
When the action fires - defaults to N (non-stored) |
instruction |
ActionInstruction |
What the action does - timer, math, counter, etc. |
duration |
float |
Required for timers and timed qualifiers (milliseconds) |
operands |
list[ActionOperand] |
Inputs for multi-operand instructions like ADD |
preset_value |
int |
Preset for counter instructions (CTU, CTD, ...) |
comment |
str |
Optional inline note on the action |
The shortest valid action just sets a boolean output:
s1.add_action("cmd_extend")
This uses the default N qualifier - the variable is TRUE while the step is active, FALSE otherwise.
See the qualifiers reference and instructions reference for every supported value.
A pneumatic cylinder extends on operator command, waits for confirmation from a front sensor, retracts after a one-second hold, then waits for the rear sensor before returning to idle.
from automation_machine import Sequence, StepType, ActionQualifier, ActionInstruction
class CylinderCycle(Sequence):
"""Single-cycle extend/retract for a pneumatic cylinder."""
def setup(self):
# --- Steps ---
s_idle = self.add_step(StepType.INITIAL, name="Idle")
s_extend = self.add_step(name="Extending")
s_hold = self.add_step(name="Hold")
s_retract = self.add_step(name="Retracting")
# --- Transitions ---
self.add_transition(
s_idle, s_extend,
condition="cmd_start AND NOT emergency_stop",
)
self.add_transition(
s_extend, s_hold,
condition="sensor_front",
)
self.add_transition(
s_hold, s_retract,
condition="hold_timer.Q",
)
self.add_transition(
s_retract, s_idle,
condition="sensor_rear",
)
# --- Actions ---
s_idle.add_action("ready_lamp", description="Cycle ready indicator")
s_extend.add_action("sol_extend", description="Extend solenoid")
s_hold.add_action(
"hold_timer",
description="One-second hold at end of stroke",
instruction=ActionInstruction.TON,
duration=1000,
)
s_retract.add_action("sol_retract", description="Retract solenoid")
Save the file. The visual editor immediately renders the four-step diagram with the wired transitions and actions. Press F5 to launch the PLC emulation and step through the cycle by forcing cmd_start, sensor_front, and sensor_rear in the Variables panel.
| Symptom | Cause | Fix |
|---|---|---|
| Sequence never starts | No StepType.INITIAL step |
Mark one step as initial |
| Step shown greyed out in diagram | Step has no incoming transition | Add a transition that targets it |
| Validator flags "unreachable step" | Step reachable from no path | Wire it up or delete it |
NameError: s1 is not defined in a method |
Steps stored as locals | Store them on self (self.s1 = ...) when reused in helper methods |
| Timer never fires | Forgot duration on a TON action |
Add duration=<ms> |
| Two sequences share a name | Class name collision across files | Rename one - AutomationView flags duplicates inline |