Variables
The variable editor, card by card: identity and address, the Expression and Memory kinds, the output types, the live Value card, Set value, quality and retention, the commands, and what the editor refuses.
A variable is one typed value the station computes or holds, addressed under Variables by its folder path and sanitized name. Select a variable row in the Logic column (or create one with New… > New variable, or with New variable on a folder) to open its editor. The editor needs View logic to read, Configure logic to change any field, and Operate logic to write a memory value.
The panel header shows the row's mark (an expression or a memory mark), the name, and one line per kind: "A value this station computes from an expression over the address space, recalculated every sweep." or "A value this station holds: written by a script, a dashboard or you, and readable everywhere by its address." The form column holds the IDENTITY card and then the EXPRESSION editor or the MEMORY card; the rail on the right holds VALUE and, for an expression, REFERENCED POINTS.
Identity
| Field | What it is | Values / default | Effect |
|---|---|---|---|
| Name | The display name; its sanitized segment is the last level of the address. | Free text; a new variable is VariableN. |
Commits through the safe rename (below). A blank name is refused ("Variable name is required."). |
| Address line | The address the variable answers to, echoed under the name: the section root, the folder levels, the segment. | Read only. | Follows the name as you type; the folder part changes only through Move to in the tree. |
| Kind | How the value is produced. | Expression (default) or Memory. | Switching to Memory re-seeds the value from Initial value; switching to Expression clears it to a gap until the next sweep. |
| Output type | The category every result or write is coerced to. | Boolean, Integer, Decimal (default), Text, Date and time, Image, Icon, Color. | Changing it re-seeds a memory variable (and persists the seed when retentive) or clears an expression variable to a gap; the preview re-resolves under the new type. |
| Unit (optional) | The engineering unit drawn beside the value. | Free text, empty by default. | Shown in the VALUE card and readable in scripts as .EngineeringUnit. |
| Description (optional) | Free text. | Empty by default. | None on evaluation. |
Name and address
The Name field is a rename field: typing stays local, a line under the field previews the impact after a short pause ("Checking references…", then "Renaming updates the 3 locations that read this address.", "No references use the current address.", or "The effective address does not change; no references need updating." when the new name sanitizes to the same segment), and Enter or leaving the field commits. The commit renames the variable, rewrites every expression, script, condition and dashboard binding that used the old address, keeps the live value and the channel bindings (a channel binds by the variable's stable key, never by its name), and reports "Variable renamed and N references updated." A name that collides at its level is refused in place: "'X' already answers to 'Variables.X'. Names filed in one folder must sanitize to distinct segments." The rules of spelling and collision are on The address space.
Expression
Shown while the kind is Expression: the EXPRESSION editor with its Browse… button and the hint "A single JavaScript expression over the address space (e.g. Connector.Simulated.Pump.Flow.ValueToReal() * 0.1, Variables.Setpoint.Value). For an Image/Icon/Color output, return an Assets.Images, Assets.Icons or Assets.Colors address (e.g. Variables.Level.Value > 50 ? Assets.Colors.Red : Assets.Colors.Green). Type to autocomplete, or Browse… to pick one." The text autosaves per keystroke and is validated every half second; a problem shows in the VALUE card. The language, the read surface and every rule are on Expressions. The expression text is kept, but ignored, while the kind is Memory.
Memory
Shown while the kind is Memory.
| Field | What it is | Values / default | Effect |
|---|---|---|---|
| Initial value | The seed, as text. Under it: "Parsed per the output type at startup. Leave empty for no value." | Any text, empty by default. | Parsed per the output type when the variable is created, when the kind or the output type changes, and at every start of a non-retentive variable. Empty means no value: the variable starts as a gap. Text that does not parse is flagged in the VALUE card ("Initial value could not be parsed as decimal.") and seeds a gap. |
| Retentive: the last written value survives restarts | Whether writes are persisted. | Off by default. | A retentive variable is persisted about one second after writes pause and never later than five seconds after the first unpersisted write; stopping the runtime flushes what is pending. At the next start the retained text is parsed under the current output type; when it no longer parses, the initial value is used instead. A non-retentive variable resets to the initial value at boot. |
Set value
The Set value field and its Write button are drawn only for a role with Operate logic, and greyed with "Runtime stopped" while the station is read-only; the engineering lock does not touch them. Type a value and press Write: the text is parsed per the output type; text that does not parse is refused ("Could not parse 'abc' as integer.") and nothing is written; an empty field writes no value, which clears the variable back to a gap. The write rides the single funnel: it is refused while a running recipe or an interlock holds the variable ("'Variables.X' is write-protected by '<holder>'."), journaled as old to new under the source Operator, applied on the logic queue, and marked for retention when the variable is retentive. The feed says "Value written." The field is not a readout; the VALUE card is.
Output types
| Output type | Carries | Notes |
|---|---|---|
| Boolean | true or false | Recordable and plottable through a channel |
| Integer | a 64-bit integer | Recordable and plottable |
| Decimal | a double-precision real | Recordable and plottable; the readout shows two decimals |
| Text | free text | |
| Date and time | an instant | Shown in the station's date and time format |
| Image | an asset id, as text | Presentation output: the expression returns an Assets.Images.* address |
| Icon | a glyph or SVG markup, as text | Presentation output: return an Assets.Icons.* address |
| Color | a hex color, as text | Presentation output: return an Assets.Colors.* address |
Coercion is the same permissive conversion the rest of the app uses: text parses, numbers round or convert, and what cannot convert becomes no value. A memory variable of a presentation type holds the literal you write (an asset id, a glyph, a hex). The three presentation outputs exist for dashboards, where the bound Image, Icon or Symbol component draws whatever the variable currently resolves to; the addresses they return are listed under Assets.
The Value card
The VALUE rail shows the current value refreshed twice a second: for a scalar type the readout with the unit beside it, for Image the picture, for Icon the glyph at size, for Color the swatch with its hex. A gap is drawn as a dash. For an expression variable the card previews the draft you are typing, evaluated with the current values before the sweep picks it up; while the expression is invalid the readout stays a dash and the validation message appears in the card (a name collision is reported here too, though a bad name never stops the preview). Under a scalar readout the card says "Bind a channel to this variable on the Acquisition page to record it."; the binding is made on the Channels screen of a Process model.
For an expression variable the REFERENCED POINTS card lists every address the expression names with its current reading, "?" when the address no longer resolves, so a Bad input is visible at a glance.
Quality
A variable's value is either a typed value or no value at all (a gap). A point is Good only when its own value exists: a memory variable is Good once it holds a value, and an empty seed is a gap until the first real write; an expression variable carries the quality of its last evaluation, so when any referenced point is missing, Bad or value-less the expression is not evaluated and the variable becomes a Bad-quality gap. An empty reading never silently becomes zero. Scripts read the quality as .State(); a channel bound to the variable records the gap as a gap.
Commands
| Command | What it does | Greyed when | Not drawn when |
|---|---|---|---|
| Copy | Duplicates the variable to the Variables root under a free name (Name (2)…) and opens the copy; the copy has a fresh key, so no channel is bound to it yet. |
Station locked or read-only. | Role lacks Configure logic. |
| Delete variable | Asks "Delete 'X'? This removes the variable. References to its address will become unresolved. This cannot be undone." then deletes it with its retained value. | Station locked or read-only. | Role lacks Configure logic. |
| Move to (right-click) | Files the variable in another folder or at the root; the address and every reference follow. | Station locked or read-only. | Role lacks Configure logic. |
A variable has no Enable or Disable: it is always evaluated or always held.
What the editor refuses
- A blank name, or a name whose segment is already taken at its level.
- An expression that is not one read-only JavaScript expression, that references a point that does not exist or another expression variable, or that fails a trial evaluation (the exact messages are on Expressions).
- An initial value or a Set value that does not parse under the output type, and any value that is NaN or infinite.
- Any change while the station is locked by a run or stopped: the field reloads to what the station holds and the feed says why.
What the editor does not do
It does not plot or record (a channel does), does not write tags (a script or a dashboard control carries a memory value further), does not reference other expression variables, keeps no history of values, and does not persist a non-retentive value across a restart.