C · recipe
Read a value from an OPC UA server in C
The high-level API gives you UA_Client_readValueAttribute for a bare value; use a full UA_ReadRequest when you need the status code and timestamps too. Always check the type before dereferencing the variant's data.
| Stack | open62541 |
|---|---|
| Version | 1.5.8 |
The code
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <stdio.h>
int main(void) {
UA_Client *client = UA_Client_new();
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
if (UA_Client_connect(client, "opc.tcp://opcua.umati.app:4840") != UA_STATUSCODE_GOOD) {
UA_Client_delete(client); return 1;
}
/* full read: value + status + both timestamps */
UA_ReadValueId rvi;
UA_ReadValueId_init(&rvi);
rvi.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
rvi.attributeId = UA_ATTRIBUTEID_VALUE;
UA_ReadRequest req;
UA_ReadRequest_init(&req);
req.nodesToRead = &rvi;
req.nodesToReadSize = 1;
req.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
UA_ReadResponse res = UA_Client_Service_read(client, req);
if (res.resultsSize == 1) {
UA_DataValue *dv = &res.results[0];
printf("status : %s\n", UA_StatusCode_name(dv->status));
printf("hasValue: %d sourceTs: %d\n",
dv->hasValue, dv->hasSourceTimestamp);
if (dv->hasValue && dv->value.type == &UA_TYPES[UA_TYPES_DATETIME]) {
UA_DateTimeStruct ts =
UA_DateTime_toStruct(*(UA_DateTime *)dv->value.data);
printf("value : %04u-%02u-%02u %02u:%02u:%02u\n",
ts.year, ts.month, ts.day, ts.hour, ts.min, ts.sec);
}
}
UA_ReadResponse_clear(&res);
UA_Client_disconnect(client);
UA_Client_delete(client);
return 0;
}
What it prints
status : Good
hasValue: 1 sourceTs: 1
value : 2026-09-08 03:44:59
Notes
- Always compare variant.type against the expected UA_TYPES entry before casting data. A type assumption here is a segfault, not an exception.
- The hasValue, hasStatus, hasSourceTimestamp flags on UA_DataValue exist because any of them may be absent. Check them.
- UA_Client_readValueAttribute is the convenient form when you only want the value. Use the service call when the status and timestamps matter, which for stored data is always.
- Batch multiple nodesToRead in one request. On a constrained device the round-trip saving is significant.
What breaks first
The process segfaults on a value that read fine yesterday
The node's data type changed, or you assumed a type without checking. Compare variant.type before every cast.
BadTypeMismatchThe node's data type changed, or you assumed a type without checking. Compare variant.type before every cast.
Other recipes in this stack
Concepts on this page
Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.