Actions
The action editor: identity and location, the script block, what a script may read and write, every validation message, the Run verb and its journal, Enable and Disable, Copy and Delete, and the run limits.
An action is a JavaScript statement block that reads the address space and writes memory variables and tags. Actions are the write path of Logic: they run on demand (Run), on a trigger, or from a dashboard Button wired to them. Select an action under the Actions section of the Logic column (or create one with New… > New action) to open its editor; reading needs View logic, editing Configure logic, running Operate logic.
The header shows the action mark, the name, the line "A script you run on demand, or that a trigger runs for you, writing variables and tags." and a Disabled pill while the action is off. The form column holds IDENTITY and SCRIPT; the rail holds LAST RUN.
Identity
| Field | What it is | Values / default | Effect |
|---|---|---|---|
| Name | The display name and the label a run is journaled under. | Free text; a new action is ActionN; a blank name saves as Action. |
Autosaves per keystroke. Actions are referenced by identity, so renaming rewrites nothing and breaks nothing. |
| Location line | Where the action is filed, in words: Actions / Startup / Walk setpoint. |
Read only. | An action has no address; the line is a place, never something to type into an expression. Change it with Move to in the tree. |
| Description (optional) | Free text. | Empty by default. | None. |
Script
The SCRIPT card is the script editor with the hint "JavaScript statements (let, if, for, functions). Write memory variables by assignment (Variables.Setpoint = 21.5;) and tags with Connector.Driver.Device.Tag.Write(value). Reads are not quality-gated: check .State() and guard gaps with ?? before arithmetic." The script autosaves per keystroke and is validated every half second; the message appears under the hint. Validation never executes the script.
A script is ordinary strict-mode JavaScript (locals, if, loops, functions, Math, Date, JSON) over the same address space and the same read surface as expressions, with two differences. Reads are not quality-gated: a gap reads as null, so check .State() and guard arithmetic with ??; handling a bad reading is what actions are for. And a script may read expression variables (their published value); only an expression may not reference them.
What an action may write
Exactly two constructs mutate the plant, and both go through the journaled write funnel:
| Write | Form | Target |
|---|---|---|
| Memory assignment | Variables.Setpoint = 21.5; or Variables.Forno.Setpoint = 21.5; |
A memory variable, folder levels included. The value is coerced to the variable's output type and marked for retention when the variable is retentive. |
| Tag write | Connector.Simulated.Pump.Cmd.Write(true); |
A live tag. The value is an engineering value: it travels backwards through the tag's conversion pipeline to the raw value the device takes. |
A write is write-through: what applied before a failure stays applied, and the journal shows each write as old to new under the source Action. A failed write throws, aborting that run with the reason in its outcome:
- "Write to 'X' rejected: the value is not finite." (NaN or infinity)
- "'Tag' is not materialized in the connector." (a disabled device, or a tag the embedded server does not carry)
- "'value' could not be converted for 'Tag'."
- "'X' is write-protected by '
<holder>'." (a recipe run or an interlock holds the source) - "Write to 'Tag' failed. Is the server running?"
- "Variable 'X' was not found." and "'Variables.X' is an expression variable: it is computed, never written."
What validation refuses
| Message | Cause |
|---|---|
| A script is required. | The editor is empty. |
| Script error: … | The text does not parse. |
| Addresses must be static: 'Root' is accessed with a computed segment. | Variables[name] or any non-literal segment. |
| Incomplete address '…'. | A reference too short to name a point. |
| 'X' was not found. | A read, or an assignment target, that resolves to nothing. |
| Assign to the variable itself: Variables.Name = value. | The left side of = names a member, or goes deeper than a variable's address can. |
| 'X' is an expression variable: it is computed, never written. | Assigning to an expression variable. |
| 'Connector' points are read-only. Write tags with Connector.Driver.Device.Tag.Write(value). | Assigning to any root other than Variables (Process has its own message). |
| Process points are read-only in Actions; run commands and staging writes are not supported by scripts. | Assigning to, or calling Write on, a Process point. |
| Process run commands cannot be called from Actions; command points expose read-only readiness values. | Calling Process.<Model>.<Unit>.Commands.Start() or any other command point; a Commands point only reads whether the command could execute now. |
| The ++ and -- operators are not supported on points. Use Variables.Name = Variables.Name.ValueToReal() + 1. | Variables.N++. |
| Write(value) is the tag write: Connector.Driver.Device.Tag.Write(value). | Write called on something that is not a tag address. |
JavaScript locals (let x = 1; x = x + 1;) are untouched by these rules.
Run
Run is the leading verb of the bar over an open action; it is drawn only for a role with Operate logic and greyed with "Runtime stopped" while the station is read-only (the engineering lock does not grey it: running is operating, not configuring). When the role also holds Configure logic, the draft in the editor is saved first and the run executes the saved definition; without it, the run executes the durable definition (the fields are read-only, so the two never differ).
Every run executes on the single logic queue with a fresh script engine, so no state leaks between runs and a run never interleaves a sweep, another action or an operator write. A run is aborted past 500 ms ("The script was aborted: it ran past the 500 ms time limit (infinite loop?)."), 100,000 statements or 4 MB of memory, each with a message naming the limit. A disabled action fails without running ("The action is disabled."); a stopped runtime answers "The logic runtime is not running." The feed reports "Run OK in 12 ms." or "Run failed: <reason>". Only the failure reaches the Events console, under the action's name together with what invoked it: Manual for the verb, the trigger's name for a scheduled run. It is journaled as a warning the first time, summarized while it keeps failing with the same cause, and noted once more when it recovers, and that recovery line is the one entry a successful run ever writes there. A run that simply succeeds, and every value it writes, is written only to the detailed capture: a script writing on every sweep produces values by the thousand, and a console filled with them is a console nobody can read the station's news in.
The LAST RUN rail shows when the action last ran (or "Never run."), "Duration: N ms", the last error in a caution note, and the reminder "Runs execute on the single logic queue. Only a failed run reaches the Events console; a run that succeeds, and every value it writes, is kept for the detailed capture. Triggers invoke actions on schedule." The rail belongs to the live action: an autosave never blanks it; a restart of the runtime does.
Commands
| Command | What it does | Greyed when | Not drawn when |
|---|---|---|---|
| Run | Saves the draft (with Configure logic) and queues one run. | Runtime stopped. | Role lacks Operate logic. |
| Enable / Disable | Flips Enabled; a disabled action refuses Run and idles every trigger bound to it. | Station locked or read-only. | Role lacks Configure logic. |
| Copy | Duplicates the action to the Actions root under a free name and opens the copy, which has no run recorded and no trigger bound to it. | Station locked or read-only. | Role lacks Configure logic. |
| Delete action | Asks "Delete 'X'? This removes the action. This cannot be undone." A trigger bound to it is left unbound, not deleted. | Station locked or read-only. | Role lacks Configure logic. |
The Actions root panel lists every action with its state in the Value column: "Enabled · last run <when>", with "· error" when the last run failed, or "Disabled".
What actions do not do
They do not dispatch Process run commands, stage a procedure or add a run comment (those points are read-only readiness and staging values); they do not acknowledge alarms; they do not run in parallel; they keep no state between runs and share no functions; and they are not fired by value changes or conditions, only by Run, a trigger's interval or a dashboard button.