Skip to content
Start free evaluation

Headless simulator

pdcomm-opcua-headless is the OPC UA simulator without a window. It runs the server, client and PubSub with the same engine as the GUI, for scripts, automated tests and CI. You find it in bin/ of the apps package.

Usage: pdcomm-opcua-headless [--advertised-host host] [--scenario path]

Without arguments it runs in interactive mode; with --scenario it runs a scenario. --advertised-host sets server.advertised_host of the initial configuration (see Configuration). Any other argument prints the usage, and a host name it can’t use prints Advertised host must be a host name or an IP address; both exit with code 2.

The program reads one JSON object per line from standard input and writes one reply per line to standard output:

{"action":"read","nodes":["ns=2;s=Simulator.Double"]}
  • A request is an object with an action and the action’s arguments.
  • A successful reply is {"ok":true,"result":...}; a failed one is {"ok":false,"error":"..."}. Error texts are in English.
  • A line that isn’t JSON gets a parse error such as {"error":"expected ident at line 1 column 2","ok":false}. An unknown action gets Unknown service action.
  • A line can be up to 1 MiB. A longer line gets Input exceeds one MiB and the program ends.
  • Standard output carries replies only; diagnostics go to standard error or the configured log file.
  • The simulator keeps servicing its client connection while it waits for commands.

Two requests are special:

Request Effect
{"action":"cancel"} Cancels the action that is running. The cancelled action ends with {"error":"Cancelled","ok":false}, and this request returns {"ok":true,"result":{"cancel_requested":true}}. When nothing is running, cancel_requested is false.
{"action":"shutdown"} Cleans up the client, PubSub and the server in turn and exits. The end of standard input (EOF) does the same.

The exit code is 1 if any command failed and 0 otherwise.

A scenario file is a JSON array of steps. The apps package ships a scenario that visits every workspace:

examples/opcua/scenarios/simulator-tour.json
[
{"command": {"action": "server_start"}, "expect": {"running": true}},
{"command": {"action": "connect"}, "expect": {"connected": true, "policy": "None"}},
{"command": {"action": "browse", "node": "ns=2;s=Simulator"}, "expect": {"good": true, "more": false}},
{"command": {"action": "write", "node": "ns=2;s=Simulator.Double", "type": "Double", "value": 2.5},
"expect": {"good": true}},
{"command": {"action": "write", "node": "ns=2;s=Simulator.Counter", "type": "UInt32", "value": 1},
"expect": {"good": false, "status": "BadNotWritable (0x803B0000)"}},
{"command": {"action": "read", "nodes": ["ns=2;s=Simulator.Double", "ns=2;s=Simulator.Protected"]}},
{"command": {"action": "call", "method": "ns=2;s=Simulator.Add",
"arguments": [{"type": "Double", "value": 1.5}, {"type": "Double", "value": 2}]},
"expect": {"good": true, "outputs": [{"type": "Double", "value": 3.5}]}},
{"command": {"action": "subscribe", "nodes": ["ns=2;s=Simulator.Double"], "interval_ms": 250},
"expect": {"subscription": 1}},
{"command": {"action": "publish", "count": 2}},
{"command": {"action": "event_subscribe"}, "expect": {"good": true}},
{"command": {"action": "alarm_set", "active": true}, "expect": {"good": true}},
{"command": {"action": "publish", "count": 2}},
{"command": {"action": "condition_refresh"}, "expect": {"good": true}},
{"command": {"action": "history_read", "node": "ns=2;s=Simulator.Double"}, "expect": {"good": true}},
{"command": {"action": "pubsub_start"}, "expect": {"running": true, "transport": "udp"}},
{"command": {"action": "pubsub_publish"}, "expect": {"sequence": 1}},
{"command": {"action": "pubsub_stop"}, "expect": {"running": false}},
{"command": {"action": "connect"}, "expect_error": true},
{"command": {"action": "disconnect"}, "expect": {"connected": false}},
{"command": {"action": "server_stop"}, "expect": {"running": false}}
]
Field Meaning
command The request to run, the same as one line in interactive mode.
expect Fields and values to check in the result object; only the listed fields are compared.
expect_error When true, the step must fail.

Run it:

터미널 창
"$OPCUA_APPS/bin/pdcomm-opcua-headless" --scenario "$OPCUA_APPS/examples/opcua/scenarios/simulator-tour.json"

Each step prints one line, {"result":...,"step":N}. The beginning and the end look like this (long lines omitted):

{"result":{"audit":[],"endpoint":"opc.tcp://localhost:63408/pdcomm/simulator","error":null,"running":true,"secure":true,"sessions":0},"step":1}
...
{"result":{"good":false,"node":"ns=2;s=Simulator.Counter","status":"BadNotWritable (0x803B0000)"},"step":5}
...
{"result":{"error":"The client is already connected"},"step":18}
{"result":{"connected":false},"step":19}
{"result":{"running":false},"step":20}

When every step meets its expectations, the exit code is 0. Otherwise the run stops at that step, writes the reason to standard error and exits with code 1:

Standard error Meaning
Scenario step 2 field policy did not match A field in expect differs from the result.
Scenario step 1 failed: The client is not connected A step that should succeed failed.
Scenario step 1 succeeded unexpectedly A step marked expect_error succeeded.

Scenario files can’t exceed 1 MiB or 10000 steps. Scenario mode doesn’t wait between steps, so check results that take time, such as received PubSub messages, in interactive mode.

configure takes a configuration object. You can pass only some sections or fields, but every field you leave out gets its default value, not its current one. To change a few fields, get the current configuration with state, edit it and pass it back. You can change the section of a running server, client or PubSub only after stopping it; otherwise you get Stop the endpoint before changing its configuration. Check the current configuration with {"action":"state"}.

{"action":"configure","config":{"server":{"address":"127.0.0.1:4841"},"client":{"policy":"Basic256Sha256","mode":"SignAndEncrypt"}}}

server

Field Default Description
address 127.0.0.1:0 Listen socket address; port 0 picks a free port.
path pdcomm/simulator Path of the endpoint URL
advertised_host Empty The host name (HostName) the server puts in the URLs of GetEndpoints, FindServers and CreateSession responses. When empty, each client gets back the host and port it used to connect. Set a name or an IP address (IPv6 without brackets) to always return that name; the status endpoint uses it too.
application_uri urn:pdcomm:opcua:server ApplicationUri; must start with urn:.
allow_none true Advertises the None endpoint.
secure true Advertises signed and encrypted endpoints; it and allow_none can’t both be false.
allow_anonymous true Allows anonymous users.
user_name operator The user name to accept; the password goes to server_start.
certificate, private_key Empty Server certificate and private key files (PEM or DER). When empty, a self-signed certificate is created in memory; it lists localhost, the listen IP address (except 0.0.0.0) and advertised_host.
trust [] Client certificate files to trust (up to 64)
simulation_interval_ms 500 The Simulator.Counter interval: 0, or 50 to 60000
max_sessions 8 Maximum sessions (1 to 32)

client

Field Default Description
url Empty The opc.tcp URL to connect to; empty means this simulator’s server.
policy, mode None, None Security policy and mode; None only when both are None.
identity anonymous anonymous or username
user_name operator User name; the password goes to connect.
application_uri urn:pdcomm:opcua:client ApplicationUri
certificate, private_key Empty Client certificate and private key files; created in memory when empty.
trust [] Server certificate files to trust. The certificate of this simulator’s own server is trusted automatically.
timeout_ms 5000 Timeout (100 to 60000 ms)

pubsub

Field Default Description
transport udp udp or mqtt
role both both, publisher or subscriber
listen 127.0.0.1:0 UDP subscriber listen address
destination Empty UDP publisher destination; empty means the subscriber in the same process
broker 127.0.0.1:1883 MQTT broker IP address and port
topic pdcomm/opcua/simulator MQTT topic, without wildcards
publisher_id, writer_group_id, dataset_writer_id 77, 1, 17 PubSub identifiers; must not be 0

limits: notification_queue (notifications kept) and trace_entries (action records kept), each 1 to 1000, default 1000.

Arguments that carry values (write, server_write, the arguments of call and the fields of pubsub_publish) take a type and a value:

{"type":"Double","value":12.5}
Type Value format
Boolean true or false
SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64 An integer within range
Float, Double A number
String Text up to 64 KiB
LocalizedText Text
DateTime Unix milliseconds
ByteString A hexadecimal string
NodeId NodeId text such as ns=2;s=Name

NodeId text accepts numeric (i=) and string (s=) identifiers. All timestamps in results are Unix milliseconds.

Workspace Action Arguments
connection capabilities None. Returns the supported features and limits.
connection state None. The configuration and the state of server, client and PubSub
connection configure config
connection server_start password (optional, up to 256 bytes). With a password, the user name token is advertised.
connection server_stop, server_status None. server_status returns the session count and the audit record.
connection discover url (optional)
connection connect url (optional), password (when identity is username)
connection disconnect None
connection project_export, project_import project_import takes project; server, client and PubSub must all be stopped.
address_space browse node (default i=85), direction (forward or inverse)
address_space server_nodes None. The current values of the server’s variables
read_write_methods read node or nodes (up to 100), attribute (1 to 27, default 13)
read_write_methods write, server_write node, type, value
read_write_methods call object (default ns=2;s=Simulator), method, arguments (up to 32)
subscriptions subscribe node or nodes (up to 100), interval_ms (50 to 10000, default 250)
subscriptions publish count (1 to 10, default 1)
subscriptions notifications, notifications_clear, unsubscribe None
events event_subscribe notifier (default i=2253), interval_ms
events alarm_set active
events condition condition (default ns=2;s=Simulator.Alarm), method (acknowledge, confirm, add_comment, enable, disable), event_id (hex), comment (up to 1024 bytes)
events condition_refresh None
history history_read node, start, end, max, continuation, release
pubsub pubsub_start, pubsub_status, pubsub_received, pubsub_stop None
pubsub pubsub_publish fields (1 to 64, optional)
trace trace, trace_clear None
trace logging_configure config
trace logging_status, logging_flush None

Passwords are passed per action and never kept in the configuration, projects, replies or logs.

project_export returns the current configuration and the values of the server’s writable public variables. The GUI’s Project menu opens and saves the same files.

{"action":"project_export"}
{"ok":true,"result":{"config":{"client":{"application_uri":"urn:pdcomm:opcua:client","certificate":"","identity":"anonymous","mode":"None","policy":"None","private_key":"","timeout_ms":5000,"trust":[],"url":"","user_name":"operator"},"limits":{"notification_queue":1000,"trace_entries":1000},"pubsub":{"broker":"127.0.0.1:1883","dataset_writer_id":17,"destination":"","listen":"127.0.0.1:0","publisher_id":77,"role":"both","topic":"pdcomm/opcua/simulator","transport":"udp","writer_group_id":1},"server":{"address":"127.0.0.1:0","advertised_host":"","allow_anonymous":true,"allow_none":true,"application_uri":"urn:pdcomm:opcua:server","certificate":"","max_sessions":8,"path":"pdcomm/simulator","private_key":"","secure":true,"simulation_interval_ms":500,"trust":[],"user_name":"operator"}},"kind":"pdcomm.opcua.project","model":[],"version":1}}

Save the result object to a file and load it with {"action":"project_import","project":{...}}. kind must be pdcomm.opcua.project and version 1.

  • MCP server: use the same actions from AI tools.
  • Tutorials: subscriptions, events, history and PubSub