Skip to main content

Property Values

propertyValues sets values on an instance's members by nesting, mirroring the shape of the type. It is the alternative to initializers, which addresses the same variables by path — use whichever reads better for the model at hand, or both.


Nesting mirrors the type

Each key is a member browse name, alias-qualified like everywhere else in the DSL. A value is either the value to assign, or a nested mapping addressing that member's own children:

Values by nesting
instances:
- browseName: Pump1
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
di:Manufacturer: Sterfive
ParameterSet:
Pressure: 4.2
Flow: 120.0

A key that names no member of the enclosing node is an error, not a new node — so a misspelling is reported rather than silently creating something the type never declared.


$value — a variable that also has children

A variable with sub-properties of its own needs a way to say "this one, not a child of it". The reserved key $value does that:

A value alongside its own sub-properties
instances:
- browseName: Pump2
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
Level:
# the variable's OWN value, alongside its sub-properties
$value: 42.0
ua:EngineeringUnits: "%"
ua:EURange:
low: 0.0
high: 100.0

$value is rejected on an Object — only a Variable has a value to set.


Value literals

Because a mapping normally means "recurse into children", the two structures models most often write inline would be ambiguous. Two shapes are therefore read as values:

ShapeWhen
{text, locale?}the variable's DataType is LocalizedText
{low, high}the variable's DataType is Range
Inline LocalizedText and Range
instances:
- browseName: Pump3
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
# {text, locale?} on a LocalizedText is a VALUE, not a child named "text"
di:Manufacturer:
text: Sterfive
locale: en
# {low, high} on a Range is likewise a value
Level:
ua:EURange:
low: 0.0
high: 250.0

The match is exact and deliberate: {txt: "Sterfive"} is not a LocalizedText with a typo, it is a reference to a child named txt, and you get the usual "cannot find child" error. That is what keeps a typo from being silently swallowed as a value.


Optional members

Assigning a value implies presence here too, at any depth of the tree — the instance does not need to repeat the member under optionals::

An Optional member needs no optionals: entry
instances:
- browseName: Pump4
typeDefinition: PumpType
organizedBy: /ua:Objects
# no `optionals:` — assigning a value opts MaintenanceNote in
propertyValues:
MaintenanceNote: "replace seal at 5000 h"

See Initializing an optional member for the same rule as it applies to initializers:.


Choosing between propertyValues and initializers

Both write values to existing variables; they differ only in how the target is named.

propertyValuesinitializers
Addressingnested, mirrors the typea browse path per entry
Placementon the instanceon the instance, or at the document root
Reads well whensetting many values under one parentsetting a few scattered values, or grouping every value in one section
📄 Full working example — property-values.model.yaml
# yaml-language-server: $schema=../../../../schemas/nodeset2.schema.json
#
# Living documentation example for: s67_property-values.md
# Validate: opcua-modeler generate --input property-values.model.yaml
#
namespaceUri: http://example.com/doc-examples/property-values/
namespaces:
- di
version: 1.0.0

objectTypes:
- browseName: PumpType
subtypeOf: di:DeviceType
components:
- browseName: ParameterSet
typeDefinition: ua:FolderType
components:
- browseName: Pressure
dataType: ua:Double
- browseName: Flow
dataType: ua:Double
- browseName: Level
dataType: ua:Double
typeDefinition: ua:AnalogUnitRangeType
- browseName: MaintenanceNote
dataType: ua:String
modellingRule: Optional

instances:
- browseName: Pump1
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
di:Manufacturer: Sterfive
ParameterSet:
Pressure: 4.2
Flow: 120.0

- browseName: Pump2
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
Level:
# the variable's OWN value, alongside its sub-properties
$value: 42.0
ua:EngineeringUnits: "%"
ua:EURange:
low: 0.0
high: 100.0

- browseName: Pump3
typeDefinition: PumpType
organizedBy: /ua:Objects
propertyValues:
# {text, locale?} on a LocalizedText is a VALUE, not a child named "text"
di:Manufacturer:
text: Sterfive
locale: en
# {low, high} on a Range is likewise a value
Level:
ua:EURange:
low: 0.0
high: 250.0

- browseName: Pump4
typeDefinition: PumpType
organizedBy: /ua:Objects
# no `optionals:` — assigning a value opts MaintenanceNote in
propertyValues:
MaintenanceNote: "replace seal at 5000 h"