OPC-UA Driver
Overview
Industrial data standard protocol based on OPC Unified Architecture (IEC 62541).
| Item | Value |
|---|---|
opc_type | OPCUA |
| Implementation class | plantpulse.driver.protocol.opcua.OPCUA_34_Driver |
| Library | Eclipse Milo (milo-sdk-client) |
| read | ✅ |
| write | ❌ (Phase 3 / together with Sparkplug NCMD) |
| Security | Username/Password, Anonymous |
Compatible with most OPC-UA servers, including Kepware, Matrikon, and Prosys.
OPC Registration Form
| Field | Meaning | Example |
|---|---|---|
opc_agent_ip | OPC-UA server IP | 192.168.0.40 |
opc_agent_port | OPC-UA server TCP port | 49320 (Kepware default) |
timecycle | Polling interval (ms) | 1000 |
options.servername | Server name at the end of the endpoint | (leave blank for Kepware) |
options.username | Authentication user | kopens |
options.password | Authentication password | *** |
options.discovery | Whether to use the discovery endpoint | false (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:
| Notation | Meaning |
|---|---|
ns=2;s=Simulator.Sine1 | namespace 2, string identifier Simulator.Sine1 |
ns=2;i=1234 | numeric identifier 1234 |
ns=3;g=09087e75-8e5e-499b-954f-f2a8624db28a | GUID 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_type | Behavior |
|---|---|
Float / Double | Numeric value as-is |
Int / Integer / Int32 / Short / Long | Numeric value as-is |
Boolean / Bool | true/false string |
String / Text | UTF-8 string |
DateTime | ISO string |
format is not generally used with OPC-UA. If post-processing arithmetic is required, use fomula.
Common Errors and Fixes
| Message / Symptom | Cause | Fix |
|---|---|---|
connection refused | Server not running, port blocked | Verify communication with telnet <ip> <port> |
Bad_UserAccessDenied | Wrong username/password, anonymous access not allowed | Register the user on the server side, or enable anonymous access |
Bad_SecurityChecksFailed | Security policy mismatch | Check policies such as None / Basic256Sha256 on the server. Phase 1 prefers MessageSecurityMode.None |
endpointUrl mismatch | discovery=false is set but the server returns a different hostname | Leave it as discovery=true or map it in the hosts file |
| Value is always 0 / null | NodeId typo, namespace number mismatch | Verify 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
- Kepware Server → Project → add a channel (e.g.,
Simulator). - Add a device (e.g.,
Simulator) → model =16 Bit Device. - Add tags →
Sine1, typeFloat, scan rate100ms, etc. - Enable port
49320inProject Properties → OPC UA → Server Endpoint. - Enable Anonymous access or a user account.
→ Edge registration form:
| Field | Value |
|---|---|
| opc_agent_ip | Kepware server IP |
| opc_agent_port | 49320 |
| options.servername | (blank) |
| options.username/password | The account created above |
| plc_address | ns=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_type | plc_address example | Notes |
|---|---|---|
Boolean | ns=2;s=Simulator.Boolean1 | Boolean tag in Kepware Simulator |
Boolean | ns=2;s=PLC.Status.Running | Kepware Channel.Device.Tag |
Boolean | ns=2;i=1003 | numeric NodeId |
16/32-bit Integers
data_type | plc_address example | Notes |
|---|---|---|
Integer | ns=2;s=Simulator.Random1 | Random integer simulation |
Integer | ns=2;s=Simulator.Counter1 | Counter |
Integer | ns=2;s=PLC.D100 | Kepware MELSEC channel exposure |
64-bit Integers
data_type | plc_address example | Notes |
|---|---|---|
Long | ns=2;s=Simulator.LongCounter | UInt64 / Int64 node |
Long | ns=2;s=PLC.Cycle.Total | Cumulative counter |
Floating Point
data_type | plc_address example | Notes |
|---|---|---|
Float | ns=2;s=Simulator.Sine1 | Sine wave simulation |
Float | ns=2;s=Simulator.Ramp1 | Ramp wave |
Double | ns=2;s=PLC.Pressure | High-precision measurement |
Strings
data_type | plc_address example | Notes |
|---|---|---|
String | ns=2;s=Simulator.User1.Name | String node |
String | ns=2;s=PLC.Recipe.Active | Recipe name |
By NodeId Format
| identifier type | plc_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
| Purpose | data_type | fomula | Notes |
|---|---|---|---|
| Unit conversion | Float | ${VALUE}*0.001 | g → kg, etc. |
| Zero-point correction | Float | ${VALUE}-${TAG_ZERO} | Can reference other OPCUA tags |
| Type conversion | Float | ${VALUE}*1.0 | Force Integer → Float |
| Polynomial | Float | ${VALUE}*${VALUE}*0.0001 | Non-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"}
]
}'