Skip to main content

OPC-UA Driver

Overview

Industrial data standard protocol based on OPC Unified Architecture (IEC 62541).

ItemValue
opc_typeOPCUA
Implementation classplantpulse.driver.protocol.opcua.OPCUA_34_Driver
LibraryEclipse Milo (milo-sdk-client)
read
write❌ (Phase 3 / together with Sparkplug NCMD)
SecurityUsername/Password, Anonymous

Compatible with most OPC-UA servers, including Kepware, Matrikon, and Prosys.


OPC Registration Form

FieldMeaningExample
opc_agent_ipOPC-UA server IP192.168.0.40
opc_agent_portOPC-UA server TCP port49320 (Kepware default)
timecyclePolling interval (ms)1000
options.servernameServer name at the end of the endpoint(leave blank for Kepware)
options.usernameAuthentication userkopens
options.passwordAuthentication password***
options.discoveryWhether to use the discovery endpointfalse (if true, endpoints are discovered automatically)

Format of the generated endpoint URL:

opc.tcp://<opc_agent_ip>:<opc_agent_port>/<servername>

If both username and password are present, UsernameProvider is used; otherwise AnonymousProvider is used.


Tag plc_address Format

Standard OPC-UA NodeId notation. Examples:

NotationMeaning
ns=2;s=Simulator.Sine1namespace 2, string identifier Simulator.Sine1
ns=2;i=1234numeric identifier 1234
ns=3;g=09087e75-8e5e-499b-954f-f2a8624db28aGUID identifier
ns=2;b=Mb=opaque (bytestring) identifier

For Kepware, the ns=2;s=<Channel>.<Device>.<Tag> format is typical.


data_type / format Mapping

The Value of the OPC-UA variable node is cast to String before being returned. data_type is used for casting by later stages (PLCValueFomula, Sparkplug publishing, etc.).

data_typeBehavior
Float / DoubleNumeric value as-is
Int / Integer / Int32 / Short / LongNumeric value as-is
Boolean / Booltrue/false string
String / TextUTF-8 string
DateTimeISO string

format is not generally used with OPC-UA. If post-processing arithmetic is required, use fomula.


Common Errors and Fixes

Message / SymptomCauseFix
connection refusedServer not running, port blockedVerify communication with telnet <ip> <port>
Bad_UserAccessDeniedWrong username/password, anonymous access not allowedRegister the user on the server side, or enable anonymous access
Bad_SecurityChecksFailedSecurity policy mismatchCheck policies such as None / Basic256Sha256 on the server. Phase 1 prefers MessageSecurityMode.None
endpointUrl mismatchdiscovery=false is set but the server returns a different hostnameLeave it as discovery=true or map it in the hosts file
Value is always 0 / nullNodeId typo, namespace number mismatchVerify by reading the same NodeId with a client such as UA Expert

curl Registration Example

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_UA_Kepware",
"opc_type": "OPCUA",
"opc_name": "Kepware",
"opc_agent_ip": "192.168.0.40",
"opc_agent_port": "49320",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": {
"username": "kopens",
"password": "***",
"discovery": "false"
},
"tag_list": [
{
"tag_id": "OPC_UA_Kepware_TAG_00001",
"tag_name": "Sine1",
"plc_address": "ns=2;s=Simulator.Sine1",
"data_type": "Float",
"description": "Sine wave"
},
{
"tag_id": "OPC_UA_Kepware_TAG_00002",
"tag_name": "Random1",
"plc_address": "ns=2;s=Simulator.Random1",
"data_type": "Integer"
}
]
}'

Reading a value:

curl -s http://<edge-host>/api/v1/tag/OPC_UA_Kepware_TAG_00001/value | jq

Reference: Kepware Quick Setup Guide

  1. Kepware Server → Project → add a channel (e.g., Simulator).
  2. Add a device (e.g., Simulator) → model = 16 Bit Device.
  3. Add tags → Sine1, type Float, scan rate 100ms, etc.
  4. Enable port 49320 in Project Properties → OPC UA → Server Endpoint.
  5. Enable Anonymous access or a user account.

→ Edge registration form:

FieldValue
opc_agent_ipKepware server IP
opc_agent_port49320
options.servername(blank)
options.username/passwordThe account created above
plc_addressns=2;s=Simulator.Simulator.Sine1

Example Collection (by Data Type)

OPC-UA casts the variable node's value (Variant) to String before returning it. data_type is used for casting during post-processing (PLCValueFomula, Sparkplug DataTypeMapper). format is not generally used.

Boolean

data_typeplc_address exampleNotes
Booleanns=2;s=Simulator.Boolean1Boolean tag in Kepware Simulator
Booleanns=2;s=PLC.Status.RunningKepware Channel.Device.Tag
Booleanns=2;i=1003numeric NodeId

16/32-bit Integers

data_typeplc_address exampleNotes
Integerns=2;s=Simulator.Random1Random integer simulation
Integerns=2;s=Simulator.Counter1Counter
Integerns=2;s=PLC.D100Kepware MELSEC channel exposure

64-bit Integers

data_typeplc_address exampleNotes
Longns=2;s=Simulator.LongCounterUInt64 / Int64 node
Longns=2;s=PLC.Cycle.TotalCumulative counter

Floating Point

data_typeplc_address exampleNotes
Floatns=2;s=Simulator.Sine1Sine wave simulation
Floatns=2;s=Simulator.Ramp1Ramp wave
Doublens=2;s=PLC.PressureHigh-precision measurement

Strings

data_typeplc_address exampleNotes
Stringns=2;s=Simulator.User1.NameString node
Stringns=2;s=PLC.Recipe.ActiveRecipe name

By NodeId Format

identifier typeplc_address example
String (s=)ns=2;s=Simulator.Sine1
Numeric (i=)ns=2;i=1234
GUID (g=)ns=3;g=09087e75-8e5e-499b-954f-f2a8624db28a
Opaque (b=)ns=2;b=Mb=

Using Formulas

Purposedata_typefomulaNotes
Unit conversionFloat${VALUE}*0.001g → kg, etc.
Zero-point correctionFloat${VALUE}-${TAG_ZERO}Can reference other OPCUA tags
Type conversionFloat${VALUE}*1.0Force Integer → Float
PolynomialFloat${VALUE}*${VALUE}*0.0001Non-linear

Comprehensive curl Example (All Types)

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_UA_FULL",
"opc_type": "OPCUA",
"opc_name": "Kepware Full",
"opc_agent_ip": "192.168.0.40",
"opc_agent_port": "49320",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": { "discovery": "false" },
"tag_list": [
{"tag_id":"OPC_UA_FULL_T01", "tag_name":"BoolTag", "plc_address":"ns=2;s=Simulator.Boolean1", "data_type":"Boolean"},
{"tag_id":"OPC_UA_FULL_T02", "tag_name":"IntTag", "plc_address":"ns=2;s=Simulator.Random1", "data_type":"Integer"},
{"tag_id":"OPC_UA_FULL_T03", "tag_name":"LongTag", "plc_address":"ns=2;s=Simulator.LongCounter", "data_type":"Long"},
{"tag_id":"OPC_UA_FULL_T04", "tag_name":"FloatTag", "plc_address":"ns=2;s=Simulator.Sine1", "data_type":"Float"},
{"tag_id":"OPC_UA_FULL_T05", "tag_name":"DoubleTag", "plc_address":"ns=2;s=PLC.Pressure", "data_type":"Double"},
{"tag_id":"OPC_UA_FULL_T06", "tag_name":"StringTag", "plc_address":"ns=2;s=Simulator.User1.Name", "data_type":"String"},
{"tag_id":"OPC_UA_FULL_T07", "tag_name":"NumIdTag", "plc_address":"ns=2;i=1234", "data_type":"Integer"},
{"tag_id":"OPC_UA_FULL_T08", "tag_name":"ScaledTag", "plc_address":"ns=2;s=Simulator.Sine1", "data_type":"Float", "fomula":"${VALUE}*100"}
]
}'