C · recipe
Write a value to an OPC UA server in C
Build a variant with the scalar type the node declares and write it. Read the DataType attribute first rather than assuming, and check the returned status, a write that is refused returns a code, not a crash.
| Stack | open62541 |
|---|---|
| Version | 1.5.8 |
The code
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <stdio.h>
/* umati is read-only. Run a local server:
./examples/server_ctt (from an open62541 build) */
int main(void) {
UA_Client *client = UA_Client_new();
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
if (UA_Client_connect(client, "opc.tcp://localhost:4840") != UA_STATUSCODE_GOOD) {
UA_Client_delete(client); return 1;
}
UA_NodeId target = UA_NODEID_STRING(1, "the.answer");
/* check what the node expects before writing */
UA_NodeId dataType;
UA_NodeId_init(&dataType);
UA_StatusCode rc = UA_Client_readDataTypeAttribute(client, target, &dataType);
if (rc == UA_STATUSCODE_GOOD)
printf("declared datatype: ns=%d;i=%d\n",
dataType.namespaceIndex, dataType.identifier.numeric);
UA_NodeId_clear(&dataType);
UA_Int32 value = 42;
UA_Variant v;
UA_Variant_init(&v);
UA_Variant_setScalar(&v, &value, &UA_TYPES[UA_TYPES_INT32]);
rc = UA_Client_writeValueAttribute(client, target, &v);
printf("write: %s\n", UA_StatusCode_name(rc));
/* read back - a Good status does not prove the value stuck */
UA_Variant back;
UA_Variant_init(&back);
if (UA_Client_readValueAttribute(client, target, &back) == UA_STATUSCODE_GOOD &&
back.type == &UA_TYPES[UA_TYPES_INT32])
printf("read back: %d\n", *(UA_Int32 *)back.data);
UA_Variant_clear(&back);
UA_Client_disconnect(client);
UA_Client_delete(client);
return 0;
}
What it prints
declared datatype: ns=0;i=6
write: Good
read back: 42
Notes
- UA_Variant_setScalar does not copy: the variant points at your stack variable. Keep it alive until the write returns, or use UA_Variant_setScalarCopy.
- Read the DataType attribute. UA_TYPES_INT32 is not UA_TYPES_INT16, and the server will refuse the mismatch.
- Read back in tests. Some servers, including the umati sample server, accept writes and discard them.
- For arrays use UA_Variant_setArray and match ValueRank. A scalar into an array node is a type mismatch.
What breaks first
The write returns Good but the value never changes
Either the server clamped your value into range, or it accepted and discarded the write. Read back, and check AccessLevel and EURange.
GoodClampedEither the server clamped your value into range, or it accepted and discarded the write. Read back, and check AccessLevel and EURange.
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.