Skip to main content

The OPC UA FX vocabulary

An OPC UA FX model repeats the same structure many times: the InputData, OutputData and ConfigurationData folders of each FunctionalEntity, the FunctionalEntities and Assets folders of each AutomationComponent, the ListToRestrict references of each ControlGroup. The fx: block says what an entry is in OPC UA FX, and the modeler writes that structure for you.

An fx: block is a shorthand, not a new model: before compiling, the modeler expands it into the plain DSL it stands for, and the NodeSet2 is the same as if you had written that DSL by hand. You can mix both freely, and add any plain key beside fx:. The vocabulary comes with the FX extension of the modeler, available in the CLI, the VS Code extension and the online editor.

The examples share this header:

namespaceUri: http://sterfive.com/UA/FX/Vocabulary/
version: 1.0.0
publicationDate: "2026-10-09T00:00:00Z"
namespaces:
- di
- fxData
- fxAc
- fxCm

An fx: block holds one of three kinds: functionalEntity and asset on an ObjectType, automationComponent on an ObjectType or an instance.

functionalEntity: data, author and ControlGroups​

A FunctionalEntityType
objectTypes:
- browseName: TemperatureMonitorType
fx:
functionalEntity:
author: { uri: http://acme.com, identifier: TempMon01, version: 1.0.0.0 }
outputs:
Temperature: ua:Float
configuration:
EngineeringUnit: { dataType: ua:EUInformation, accessLevel: CurrentRead | CurrentWrite }
controlGroups:
MonitorControl: { restrict: [EngineeringUnit], related: [Temperature] }

The type becomes a subtype of fxAc:FunctionalEntityType, unless it states its own subtypeOf.

KeyWrites
inputs, outputs, configurationthe Variables of InputData, OutputData, ConfigurationData. A value is a DataType, or a variable as you would write it under components:
{ group: { ... } }a nested folder of the same kind, holding its own Variables
authorthe AuthorUri, AuthorAssignedIdentifier and AuthorAssignedVersion properties; the version is Major.Minor.Build.SubBuild
publisherCapabilities, subscriberCapabilitiesthe optionals of OutputData/PublisherCapabilities and InputData/SubscriberCapabilities
controlGroupsa ControlGroupType member per name; restrict, block and related fill its ListToRestrict, ListToBlock and ListOfRelated

A name in restrict, block or related is one of the entity's own inputs, outputs, configuration variables or methods: the modeler finds the folder it lives in. A name that names nothing is reported as DSL-E-FX-102.

Groups and capabilities
objectTypes:
- browseName: AnalogueInput8FunctionalEntityType
fx:
functionalEntity:
outputs:
Int16Channels: { group: { Channel1: ua:Int16, Channel2: ua:Int16 } }
FloatChannels: { group: { Channel3: ua:Float, Channel4: ua:Float } }
publisherCapabilities: [PreconfiguredDataSetOnly]

asset: nameplate, built-in assets and connectors​

An FxAssetType
objectTypes:
- browseName: SystemOnChipType
- browseName: MyRaspberryPiType
fx:
asset:
nameplate: [Manufacturer, Model, SerialNumber]
builtIn:
SystemOnChip: SystemOnChipType
connectors:
USB1: fxAc:AssetConnectorType

The type becomes a subtype of fxAc:FxAssetType. nameplate makes those di properties Mandatory, builtIn declares each built-in asset through HasBuiltInAsset, and connectors fills the Connectors folder.

On an ObjectType, the members are declared in the type's FunctionalEntities and Assets folders:

An AutomationComponentType
objectTypes:
- browseName: DriveFunctionalEntityType
subtypeOf: fxAc:FunctionalEntityType
- browseName: DriveAutomationComponentType
fx:
automationComponent:
functionalEntities:
DriveControl: { type: DriveFunctionalEntityType, hostedBy: DriveAsset }
assets:
DriveAsset: { type: fxAc:FxAssetType, optionals: [di:Manufacturer] }

On an instance, the AutomationComponent is placed under FxRoot unless it states its own placement, and each member becomes an instance in its folder:

An AutomationComponent under FxRoot
objectTypes:
- browseName: EngineType
subtypeOf: fxAc:FunctionalEntityType
instances:
- browseName: Board1
fx:
automationComponent:
assets:
Pi: fxAc:FxAssetType
functionalEntities:
Engine: { type: EngineType, hostedBy: Pi }

A member is a type, or { type, ... } with any key of an instance (optionals, propertyValues, initializers, ...). hostedBy and executingOn name assets of the same block, one or a list; each becomes an IsHostedBy or IsExecutingOn reference from the entity.

hostedBy and executingOn on any instance​

An instance that is not a member of an automationComponent block, a sub-FunctionalEntity for example, states its links in its own fx: block. A target is a path, usually a $Symbol, and a link takes one target or a list: an entity may need several environments to run (OPC 10000-23 §4.11), not all of them assets.

Links of a sub-FunctionalEntity
objectTypes:
- browseName: EngineType
subtypeOf: fxAc:FunctionalEntityType
instances:
- browseName: Board1
fx:
automationComponent:
assets:
Pi: fxAc:FxAssetType
functionalEntities:
Engine: { type: EngineType, hostedBy: Pi }
- browseName: Program
typeDefinition: fxAc:FunctionalEntityType
componentOf: $Engine
fx:
executingOn: $Pi

Reversing an FX NodeSet​

Reversing a NodeSet2.xml that uses OPC UA FX gives the model back in this vocabulary wherever it says the same thing: FunctionalEntity data folders, groups, ControlGroup lists and publisher capabilities, asset nameplates and connectors, the members of an AutomationComponent and their hostedBy links. The reverse keeps each rewrite only after checking that it compiles to the same NodeSet as the plain model; anything the vocabulary cannot say, such as a built-in asset with its own description, stays in plain DSL beside the fx: block.

Mistakes​

The vocabulary reports its mistakes on the fx: block, before compiling:

  • DSL-E-FX-101: a key the block does not know, or a kind in the wrong place (functionalEntity on an instance).
  • DSL-E-FX-102: a name that names nothing.
  • DSL-E-FX-103: an author version that is not Major.Minor.Build.SubBuild.

The expanded model is then checked by the FX conformance rules, like any other FX model. The full samples of OPC 10000-81 Annex D, written in plain DSL, are on OPC UA FX samples.