Skip to content

The Engineering Model

Every device type in Consystence ultimately resolves to physical I/O. The engineering model is the vendor-neutral hierarchy that describes that hardware: a controller owns modules, modules expose channels, and channels populate a tag register of data points. Device types reference tags from the register; an instance binds those references to concrete data points through subscriptions at commissioning time.

The vocabulary is deliberately generic. We say controller, not “PLC” — a Rockwell ControlLogix, a Phoenix Contact PLCnext, or a soft controller are all controllers in this model. Vendor-specific structure is confined to a thin mapping layer; everything above it speaks one shared language. See the type system for how types, libraries, and instances build on this foundation.

flowchart TD
  C[Controller<br/>backplane, scan cycle, root of I/O ownership] --> M[Module<br/>passive hardware, slot-addressed]
  M --> CH[Channel<br/>individual I/O point]
  CH --> TR[Tag Register<br/>authoritative flat namespace]
  TR --> DT[Device Type<br/>references tags, owns the state machine]
  DT --> DI[Device Instance<br/>commissioned at a site]

The controller is the root of all I/O ownership. It owns the backplane and the scan cycle, and it is the unit the platform connects to first. In the target connect sequence, the platform reads the controller’s identity, firmware, and backplane slot map before anything else is enumerated. Automatic discovery is not yet implemented: today the controller’s identity and connection path (including its backplane slot) are supplied via configuration.

Every controller also exposes a standard system-status surface: a scan-counter heartbeat historised on a fixed cadence, plus scan time, comms health, and a fault summary. These are System-role tags produced by the controller runtime itself (see physicalRole below), and they are what lets the platform distinguish an idle plant from a dead acquisition chain.

A module is passive hardware, addressed by its slot on the backplane. A module profile is purely a schema — channels, their data types, ranges, and metadata. Modules deliberately have no state machine (see Module passivity below). Classifications include:

  • Digital Input / Digital Output
  • Analogue Input / Analogue Output
  • Communications (EtherNet/IP adapters, DeviceNet scanners)
  • Power supply
  • Safety modules
  • PLCnext compute modules

A channel is an individual I/O point on a module — one digital point, one 4–20 mA analogue input, and so on. Channels are what give the tag register physical context: a tag is no longer just a float in a flat namespace, but a value that originates from a known module and channel.

The tag register is the authoritative, flat namespace of every data point the controller exposes — each a typed, classified tag with value, quality and timestamp. Quality is a five-state value — good, uncertain, cached, stale, or bad — where bad marks invalid or failed data, distinct from stale (old but was valid), and is never collapsed into good or stale; it is surfaced in the UI and enforced by command precondition guards. Today the register is populated from a full tag browse of the controller. The second planned source — a deterministic module/channel schema derived from hardware identity — is roadmap; it will give every data point its physical origin (controller → module → channel), enabling module-replacement impact analysis and richer diagnostics.

Each tag in the register is described by a small set of attributes. Device-type signals, alarms, commands, and UI bindings all reference tags by name.

AttributeValuesNotes
dataTypeBool, Int, DInt, Real, StringScalar type of the tag value.
accessRead, Write, ReadWriteDirection permitted to platform clients.
physicalRoleInput, Output, Internal, System (PascalCase)Role in the simulator ↔ controller data flow.
rangeMin / rangeMaxnumericEngineering range for analogue tags.
unite.g. %, AEngineering unit, surfaced with read values.

For a deeper treatment of tag definitions, ranges, and bindings, see Tags.

physicalRole classifies how a tag participates in the data flow between the simulator, the controller, and the device. It governs which side is allowed to write the tag.

ValueMeaningExamples
Input (default)A sensor — or, in simulation, the physical model — writes the tag. The controller’s scan loop reads it as if it came from a switch or external signal.MotorCurrent, BearingTemp, FlowRate, SpeedSetpoint, Interlock
OutputThe controller writes the tag as an output of its compiled control logic. The simulator never writes outputs; the device grain reads them back and merges them into its tag cache.Running, Speed, Fault, FaultCode
InternalA simulator-only tag for the physical model’s internal consistency. It never reaches the controller and must not appear in component bindings, alarms, commands, or AI tool surfaces.WearAccumulator, InternalEnergy
SystemA controller-intrinsic tag produced by the controller runtime itself — the standard system-status surface. Read-only, and never simulator-written.System.ScanCount, System.ScanTimeMs, System.CommsHealth

A System tag may additionally carry systemRole: Heartbeat, which marks the fixed-cadence chain-liveness heartbeat tag (the scan counter); every other tag defaults to systemRole: None.

If physicalRole is omitted, it defaults to Input. The manifest validator enforces a few consistency rules:

  • An Output tag must not be the target of any simulation effect — the simulator cannot write outputs.
  • An Internal tag must not appear in component bindings, alarm conditions, command tag-writes, or AI tool surfaces.
  • Output + Write/ReadWrite is an advisory warning (legitimate for setpoint-echo patterns — an operator write reaches the tag table but is recalculated by the control logic on the next scan, so runtime authority stays with the controller); Input + Write is likewise an advisory warning (legitimate but rare, for tunable parameters).

Four constraints keep the engineering model tractable. Where a constraint is not yet enforced by the platform, that is called out below.

A device-type signal should reference a data point that exists in the controller’s tag register. Validating mappings this way prevents broken references and makes dependency tracking — which device signals depend on which physical channels — a solvable problem.

Modules never carry state machines. A module is a schema: channels, types, ranges, metadata. Forcing a state machine onto passive hardware would add complexity without value. State lives in device types, not modules.

A device instance’s signal surface is not stable until an engineer commissions it. Everything that builds on instances — alarms, P&ID bindings, AI context, historian — is designed to build on commissioned instances, never on proposals. See Instances and commissioning.

The platform’s state-machine shadow is advisory. Hard safety interlocks remain in I/O-module hardware or safety relays — never in a soft controller.

A device type runs in two distinct runtimes: control logic executing on a controller (real or virtual), and an advisory state shadow in the platform. This is what lets a type be authored and exercised against a simulator, then deployed against live hardware.

Simulated runtime. A deterministic physical model drives the Input tags; a virtual controller (vPLC) executes the control logic and produces the Output tags. The simulator owns inputs, the vPLC owns outputs, and Internal tags stay inside the model. This is the runtime used for type development and testing — see Simulation.

Live runtime. Real sensors drive the inputs, a physical controller executes the logic, and the platform reads outputs back through the edge. Tag values flow from the field through the PLC communication layer; physicalRole determines who is authoritative for each tag exactly as it does in simulation.

The split between control and shadow is what makes the dual runtime possible:

TargetRole
Controller / edgeDeterministic execution; owns control. Expressed per controller target today: the PLCnext runtime’s managed (eCLR) expression of the standard control blocks, a Rockwell L5X AOI, or the grain-modelled vPLC port.
Consystence shadowMirrors state from live tag values via the manifest’s states: conditions; advisory only, fed to AI, the P&ID renderer, and operator UI.

The shadow lets the platform say “Pump 1 is in AwaitingPermissives because DischargePressure is above threshold” rather than inferring state by pattern-matching raw boolean tags.