Subscriptions
- Open a client session to the simulator’s server and subscribe to two variables.
- Change a value and receive data change notifications with Publish.
- Review the received notifications and delete the subscription.
What you need
Section titled “What you need”- The
appspackage and theOPCUA_APPSvariable from the lab setup. - One terminal.
In this tutorial you type JSON commands into the headless simulator, one per line. The simulator’s server and client run together in one process. Each reply is one line too: success has "ok":true and a result, failure has "ok":false and an error. Ports, timestamps and session IDs differ on every run.
1. Start the simulator and connect
Section titled “1. Start the simulator and connect”Start the headless simulator:
"$OPCUA_APPS/bin/pdcomm-opcua-headless"Start the server. By default it listens on a free port of 127.0.0.1.
{"action":"server_start"}{"ok":true,"result":{"audit":[],"endpoint":"opc.tcp://localhost:58927/pdcomm/simulator","error":null,"running":true,"secure":true,"sessions":0}}Connect the simulator’s client to that server. Without a URL, the client connects to its own simulator’s server; the default security policy is None.
{"action":"connect"}{"ok":true,"result":{"connected":true,"identity":"anonymous","items":[],"mode":"None","pending_cancelled":0,"policy":"None","session":"ns=1;s=pdcomm.diagnostics/session/2bce1a9ad4fba143f97f8aad9fe8327a","subscription":null,"url":"opc.tcp://localhost:58927/pdcomm/simulator"}}2. Create the subscription
Section titled “2. Create the subscription”Subscribe to Simulator.Double and Simulator.Counter with a 250 ms publishing interval:
{"action":"subscribe","nodes":["ns=2;s=Simulator.Double","ns=2;s=Simulator.Counter"],"interval_ms":250}{"ok":true,"result":{"items":[{"good":true,"handle":1,"monitored_item":1,"node":"ns=2;s=Simulator.Double","status":"Good (0x00000000)","subscription":1},{"good":true,"handle":2,"monitored_item":2,"node":"ns=2;s=Simulator.Counter","status":"Good (0x00000000)","subscription":1}],"subscription":1}}The simulator created subscription 1 with CreateSubscription and added a monitored item per node with CreateMonitoredItems. handle is the clientHandle and monitored_item the ID the server assigned. Another subscribe in the same session adds items to the same subscription.
3. Change a value and receive notifications
Section titled “3. Change a value and receive notifications”Write 12.5 to Simulator.Double:
{"action":"write","node":"ns=2;s=Simulator.Double","type":"Double","value":12.5}{"ok":true,"result":{"good":true,"node":"ns=2;s=Simulator.Double","status":"Good (0x00000000)"}}Send two Publish requests:
{"action":"publish","count":2}{"ok":true,"result":{"dropped":0,"notifications":[{"good":true,"handle":1,"kind":"data","node":"ns=2;s=Simulator.Double","sequence":1,"server_time":1791997609191,"source_time":1791997609053,"status":"Good (0x00000000)","type":"Double","value":0.0},{"good":true,"handle":2,"kind":"data","node":"ns=2;s=Simulator.Counter","sequence":1,"server_time":1791997609194,"source_time":1791997609055,"status":"Good (0x00000000)","type":"UInt32","value":1},{"good":true,"handle":1,"kind":"data","node":"ns=2;s=Simulator.Double","sequence":2,"server_time":1791997609441,"source_time":1791997609196,"status":"Good (0x00000000)","type":"Double","value":12.5}],"queued":3}}- The first notification message (
"sequence":1) holds the values at the moment you subscribed: a new monitored item reports the current value once. - The second message (
"sequence":2) holds the new value, 12.5. source_timeandserver_timeare Unix milliseconds.queuedis how many notifications the simulator keeps.
Simulator.Counter grows by one on every simulation tick (500 ms by default). Wait a moment and publish again:
{"action":"publish"}{"ok":true,"result":{"dropped":0,"notifications":[{"good":true,"handle":2,"kind":"data","node":"ns=2;s=Simulator.Counter","sequence":3,"server_time":1791997609697,"source_time":1791997609555,"status":"Good (0x00000000)","type":"UInt32","value":2}],"queued":4}}A Publish response arrives at the next publishing interval with changes, or within the keep-alive period (three publishing intervals) without them. A keep-alive response carries no notifications.
4. Review the notifications
Section titled “4. Review the notifications”See every notification the simulator kept:
{"action":"notifications"}{"ok":true,"result":{"dropped":0,"entries":[{"good":true,"handle":1,"kind":"data","node":"ns=2;s=Simulator.Double","sequence":1,"server_time":1791997609191,"source_time":1791997609053,"status":"Good (0x00000000)","type":"Double","value":0.0},{"good":true,"handle":2,"kind":"data","node":"ns=2;s=Simulator.Counter","sequence":1,"server_time":1791997609194,"source_time":1791997609055,"status":"Good (0x00000000)","type":"UInt32","value":1},{"good":true,"handle":1,"kind":"data","node":"ns=2;s=Simulator.Double","sequence":2,"server_time":1791997609441,"source_time":1791997609196,"status":"Good (0x00000000)","type":"Double","value":12.5},{"good":true,"handle":2,"kind":"data","node":"ns=2;s=Simulator.Counter","sequence":3,"server_time":1791997609697,"source_time":1791997609555,"status":"Good (0x00000000)","type":"UInt32","value":2}],"limit":1000}}The store keeps up to 1000 notifications (limit). Beyond that, the oldest are dropped and dropped grows. Empty it with {"action":"notifications_clear"}.
5. Delete the subscription
Section titled “5. Delete the subscription”{"action":"unsubscribe"}{"ok":true,"result":{"deleted":1,"status":"Good (0x00000000)"}}Without a subscription, you can’t publish:
{"action":"publish"}{"error":"No subscription exists","ok":false}6. Clean up
Section titled “6. Clean up”Disconnect and end the program:
{"action":"disconnect"}{"action":"shutdown"}{"ok":true,"result":{"client_closed":null,"pubsub_stopped":false,"server_stopped":true}}If any command failed, the headless simulator exits with code 1. This tutorial has a deliberately failed Publish, so its exit code is 1.
Common errors
Section titled “Common errors”| Reply | Cause and fix |
|---|---|
Publishing interval must be 50 to 10000 ms and three intervals below the timeout |
Three publishing intervals exceed the client timeout (5000 ms by default), so "interval_ms":2000, for example, is refused. Use a shorter interval or a larger client.timeout_ms. |
No subscription exists |
You sent publish before subscribing or after deleting the subscription. |
The client is not connected |
You sent a command before connect. |
Stop the endpoint before changing its configuration |
You tried to change the client configuration with configure while connected. Disconnect first. |
In the GUI, you do the same on the Subscriptions tab; see Simulator GUI.