sondahub

sondahub / OPC UA test server

OPC UA test server

A public OPC UA server with a bottling line behind it — values that move with the plant, methods that start the pump, events when the conveyor jams, seven days of history — over the WebSocket mapping of OPC UA, free and open.

SecurityPolicy None, anonymous or any user. One connection, one server: nothing you write reaches anyone else.

Connect

Endpoint
opc.wss://api.sondahub.com/opcua
Transport
WebSocket, subprotocol opcua+uacp (OPC UA Part 6)
Security
SecurityPolicy None, MessageSecurityMode None
Sign-in
anonymous, or any user name and password (viewer: read-only; denied: refused)
Namespaces
0 http://opcfoundation.org/UA/
1 urn:sondahub:opcua:server
2 http://sondahub.com/UA/Plant/
Node ids
ns=2;s=Line1.Tank101.Level — the path, readable

Each WebSocket message carries one UA Connection Protocol chunk — HEL, OPN, MSG, CLO — exactly as they travel over TCP. Chunks up to 64 KB, messages up to 4 MB, and answers chunked to the buffer your client announced in its Hello. One connection, one server: the plant, your writes and your subscriptions live as long as the connection does.

The plant

Under Objects/Plant: bottling line 1 — a mixing tank that fills and drains on a 25-minute cycle, a transfer pump that runs about 70 % of every 15 minutes, a twelve-head filler, a conveyor that jams for 40 seconds every 20 minutes — the utilities, and a Simulation folder for testing a client’s handling of every type. Analog variables are AnalogItems with EURange and EngineeringUnits (UNECE codes); valves are TwoStateDiscretes; the conveyor state is a MultiStateDiscrete.

Line 1

Bottling line 1: mix, pump, fill, convey.

ns=2;s=Access
Line1.Tank101
Object
Mixing tank, 5 m tall.
Line1.Tank101.Level
Double
read, history
Fills while the inlet valve is open, drains through the outlet. Write the valves and it follows them.
Line1.Tank101.Temperature
Double
read, history
Line1.Tank101.Pressure
Double
read
Line1.Tank101.InletValve
Boolean
read, write
Write true to open, false to close. Once you touch a valve, the tank is yours: the level follows the two valves from then on.
Line1.Tank101.OutletValve
Boolean
read, write
Write true to open, false to close. Once you touch a valve, the tank is yours: the level follows the two valves from then on.
Line1.Tank101.HighLevelAlarm
Boolean
read
Above 4.5 m. Raises an event on the Server object.
Line1.Tank101.Agitator
Object
Line1.Tank101.Agitator.Running
Boolean
read
Line1.Tank101.Agitator.Speed
Double
read
Line1.Tank101.Agitator.SpeedSetpoint
Double
read, write
0–300 rpm; outside that, BadOutOfRange.
Line1.Tank101.Agitator.Start
Method
call ()
Line1.Tank101.Agitator.Stop
Method
call ()
Line1.Pump101
Object
Transfer pump, tank to filler. Runs about 70 % of every 15 minutes on its own.
Line1.Pump101.Running
Boolean
read
Line1.Pump101.Speed
Double
read, history
Ramps over six seconds after a start or a stop.
Line1.Pump101.SpeedSetpoint
Double
read, write
0–1800 rpm. Flow, current and vibration follow the speed.
Line1.Pump101.Flow
Double
read, history
Line1.Pump101.MotorCurrent
Double
read
Line1.Pump101.Vibration
Double
read
Spikes above 5 mm/s for a minute every hour while running — an event says so.
Line1.Pump101.RunHours
Double
read
Line1.Pump101.Starts
UInt32
read
Line1.Pump101.Start
Method
call ()
Starts the pump and keeps it running: from now on the pump is yours, not the schedule’s.
Line1.Pump101.Stop
Method
call ()
Line1.Pump101.SetSpeed
Method
call (Speed: Double) → Accepted: Boolean
Sets the speed setpoint, the way a method does it: arguments checked one by one.
Line1.Filler
Object
Twelve-head filler.
Line1.Filler.FillSetpoint
Double
read, write
100–2000 mL.
Line1.Filler.ActualFill
Double
read
Line1.Filler.Heads
Double[]
read
What each of the twelve heads filled last, in mL.
Line1.Filler.Recipe
String
read, write
Line1.Filler.BottlesFilled
UInt32
read
Line1.Filler.Rejects
UInt32
read
Line1.Conveyor
Object
Jams for 40 seconds every 20 minutes.
Line1.Conveyor.State
UInt32
read, write
0 Stopped, 1 Running, 2 Jammed, 3 Maintenance. Write 0, 1 or 3; a jam is not something you can ask for.
Line1.Conveyor.Speed
Double
read
Line1.Conveyor.BottlesPerMinute
Double
read
Line1.Conveyor.JamDetected
Boolean
read
Line1.Conveyor.ResetCounters
Method
call ()
Zeroes the filler’s BottlesFilled and Rejects.

Utilities

ns=2;s=Access
Utilities.PowerMeter
Object
Utilities.PowerMeter.ActivePower
Double
read, history
Utilities.PowerMeter.Energy
Double
read
Utilities.PowerMeter.PowerFactor
Double
read
Utilities.PowerMeter.Frequency
Double
read
Utilities.PowerMeter.Voltages
Double[]
read
L1–L2, L2–L3, L3–L1 in volts.
Utilities.PowerMeter.Currents
Double[]
read
L1, L2, L3 in amperes.
Utilities.CompressedAir
Object
Utilities.CompressedAir.Pressure
Double
read
Utilities.CompressedAir.CompressorRunning
Boolean
read
Utilities.CompressedAir.DewPoint
Double
read

Simulation

Test variables: signals, every built-in type to read and write, arrays, methods.

ns=2;s=Access
Simulation.Dynamic
Object
Simulation.Dynamic.Sinusoid
Double
read, history
±100, one cycle a minute.
Simulation.Dynamic.Sawtooth
Double
read, history
0 to 100 every 30 seconds.
Simulation.Dynamic.Triangle
Double
read
0 to 100 and back every 40 seconds.
Simulation.Dynamic.Square
Boolean
read
Flips every 10 seconds.
Simulation.Dynamic.Random
Double
read
A new value every second.
Simulation.Dynamic.RandomInt32
Int32
read
Simulation.Dynamic.Counter
UInt32
read
Seconds since 1970: one more every second.
Simulation.Dynamic.StepUp
Int32
read
Simulation.Dynamic.Timestamp
UtcTime
read
Simulation.Static
Object
One writable variable per built-in type. What you write is yours for the connection.
Simulation.Static.Boolean
Boolean
read, write
Simulation.Static.SByte
SByte
read, write
Simulation.Static.Byte
Byte
read, write
Simulation.Static.Int16
Int16
read, write
Simulation.Static.UInt16
UInt16
read, write
Simulation.Static.Int32
Int32
read, write
Simulation.Static.UInt32
UInt32
read, write
Simulation.Static.Int64
Int64
read, write
Simulation.Static.UInt64
UInt64
read, write
Simulation.Static.Float
Float
read, write
Simulation.Static.Double
Double
read, write
Simulation.Static.String
String
read, write
Simulation.Static.DateTime
DateTime
read, write
Simulation.Static.Guid
Guid
read, write
Simulation.Static.ByteString
ByteString
read, write
Simulation.Static.XmlElement
XmlElement
read, write
Simulation.Static.NodeId
NodeId
read, write
Simulation.Static.StatusCode
StatusCode
read, write
Simulation.Static.QualifiedName
QualifiedName
read, write
Simulation.Static.LocalizedText
LocalizedText
read, write
Simulation.Arrays
Object
Writable arrays, and a 2 × 3 matrix.
Simulation.Arrays.BooleanArray
Boolean[]
read, write
Simulation.Arrays.ByteArray
Byte[]
read, write
Simulation.Arrays.Int32Array
Int32[]
read, write
Simulation.Arrays.UInt32Array
UInt32[]
read, write
Simulation.Arrays.DoubleArray
Double[]
read, write
Simulation.Arrays.StringArray
String[]
read, write
Simulation.Arrays.Matrix
Int32[,]
read, write
Simulation.Methods
Object
Methods to call: arguments checked one by one, failures on purpose, a slow one.
Simulation.Methods.Add
Method
call (A: Double, B: Double) → Sum: Double
A + B, two Doubles.
Simulation.Methods.Echo
Method
call (Text: String) → Text: String
Simulation.Methods.Fail
Method
call ()
Always fails with BadInternalError, for testing how a client reports it.
Simulation.Methods.Sleep
Method
call (Milliseconds: UInt32) → Slept: UInt32
Answers after the time you give: for testing timeouts and requests that overlap.

The Server object (ns=0;i=2253) has ServerStatus, NamespaceArray, ServerArray, ServiceLevel and ServerCapabilities, and the type trees under Types hold the object, variable, data and reference types the address space uses.

Services

Service setWhat answers
DiscoveryGetEndpoints and FindServers, before or after a session; the endpoint offers anonymous and user name tokens.
SessionCreateSession, ActivateSession, CloseSession, Cancel. Up to ten sessions per connection, timeouts from 10 seconds to an hour.
ViewBrowse with every direction, reference type filter (with subtypes), node class mask and result mask; continuation points (ten per session) and BrowseNext; TranslateBrowsePathsToNodeIds; RegisterNodes and UnregisterNodes.
AttributeRead of every attribute a node class has, with IndexRange on arrays and strings and the timestamps you ask for. Write of Value, type-checked strictly: a Double variable takes a Double. HistoryRead, raw and at-time.
MethodCall, with arguments checked one by one: inputArgumentResults say which one was wrong.
SubscriptionCreateSubscription, ModifySubscription, SetPublishingMode, Publish, Republish, TransferSubscriptions (between sessions of one connection), DeleteSubscriptions.
MonitoredItemCreateMonitoredItems, ModifyMonitoredItems, SetMonitoringMode, SetTriggering, DeleteMonitoredItems.

Anything else — Query, AddNodes, HistoryUpdate — answers BadServiceUnsupported.

Subscriptions and events

Publishing intervals from 100 ms to a minute, sampling from 100 ms, queues up to 1,000 values. DataChangeFilter with the status, value and timestamp triggers and absolute or percent deadbands (percent on AnalogItems, against their EURange). Keep-alives, lifetimes, late publish requests, 32 messages kept for Republish, triggering links between items.

The Server object is an event notifier. Monitor its EventNotifier attribute with an EventFilter and the plant reports on its own: a conveyor jam and its end, the tank above 4.5 m and back, pump vibration above 5 mm/s (a minute every hour, while it runs), the pump starting and stopping, and a quality check every 30 seconds. Select clauses take the BaseEventType fields — EventId, EventType, SourceNode, SourceName, Time, ReceiveTime, Message, Severity; a where clause is accepted and not applied.

History

Variables marked history above keep seven days: Sinusoid and Sawtooth one value a second, the tank, the pump and the active power one every five or ten seconds. ReadRawModifiedDetails forward or backward (start after end), with numValuesPerNode as the page size and continuation points between pages — at most 1,000 values per call; ReadAtTimeDetails answers for each time asked. Processed and event history answer BadHistoryOperationUnsupported.

From a tool that only speaks TCP

UaExpert, asyncua, node-opcua, open62541 and most OPC UA tools speak opc.tcp:// only. The bridge is a small Node script that runs on your computer, listens on the usual TCP port and carries each message to the hub over WebSocket — nothing else happens in it, and nothing is installed:

Run the bridge
curl -O https://sondahub.com/industrial/bridge.mjs
node bridge.mjs opcua

# then point the tool at opc.tcp://localhost:4840

Errors to test against

BadTypeMismatchWrite an Int64 to Simulation.Static.Int32.
BadOutOfRangeWrite 5000 to Line1.Pump101.SpeedSetpoint (0–1800).
BadNotWritableWrite to Line1.Pump101.Speed.
BadUserAccessDeniedWrite or call as the user viewer.
BadInvalidArgumentCall Add with a String: the second input argument result is BadTypeMismatch.
BadInternalErrorCall Simulation.Methods.Fail.
(your timeout)Call Simulation.Methods.Sleep with up to 10,000 ms: the answer comes that late, and your client’s own timeout is what gets tested.
BadIdentityTokenRejectedSign in as denied.

Questions

Which OPC UA clients can connect?

Any client with the WebSocket transport of OPC UA Part 6 (opc.wss://, subprotocol opcua+uacp) connects with the address alone. Most desktop tools and libraries — UaExpert, asyncua, node-opcua, open62541 — speak only opc.tcp://; run the bridge and point them at opc.tcp://localhost:4840.

Is there security?

SecurityPolicy None only: no certificates, no signing, no encryption — it is a public playground, and the endpoint says so. Sign in anonymously, or with any user name and password; the user viewer may only read, and the user denied is refused, so both paths of a client can be tried.

What happens to what I write?

It belongs to your connection: setpoints, valves, the pump you started, the static variables, your subscriptions. A second connection starts from the same plant you started from, and a reconnect starts fresh — a client that tries to re-activate its old session gets BadSessionIdInvalid and creates a new one, which is what a server restart looks like.

How far back does history go?

Seven days, for the variables marked history below: the plant’s own signals, replayed for any moment you ask. Raw reads go forward or backward with continuation points (at most 1,000 values per call), and reads at given times answer for each time. Writes do not enter history: it is the plant as it runs on its own.