Simple C++ Client TutorialΒΆ
The current implementation of the OPC UA Server is based on Open62541 (Commit: 4038a31). Below is an example implementation of an OPC UA client, using the Open62541 library. This example client, along with a simple build system using CMAKE, can be downloaded here
.
#include <open62541/ua_client.h>
#include <open62541/ua_config_default.h>
#include <open62541/ua_client_highlevel.h>
#include <open62541/ua_log_stdout.h>
#include <opc_ua_service_types_generated.h>
#include <string>
#include <vector>
#include <stdlib.h>
UA_NodeId TranslateBrowsePathtoNodeId(UA_Client* client, std::vector<std::string> browse_path)
{
UA_BrowsePath ua_browse_path;
UA_BrowsePath_init(&ua_browse_path);
ua_browse_path.startingNode = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
ua_browse_path.relativePath.elements = (UA_RelativePathElement*)UA_Array_new(browse_path.size(), &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT]);
ua_browse_path.relativePath.elementsSize = browse_path.size();
for(size_t i = 0; i < browse_path.size(); i++) {
UA_RelativePathElement *elem = &ua_browse_path.relativePath.elements[i];
elem->targetName = UA_QUALIFIEDNAME_ALLOC(2, browse_path[i].c_str());
}
UA_TranslateBrowsePathsToNodeIdsRequest request;
UA_TranslateBrowsePathsToNodeIdsRequest_init(&request);
request.browsePaths = &ua_browse_path;
request.browsePathsSize = 1;
UA_TranslateBrowsePathsToNodeIdsResponse response = UA_Client_Service_translateBrowsePathsToNodeIds(client, request);
UA_NodeId node_id = response.results[0].targets[0].targetId.nodeId;
UA_BrowsePath_deleteMembers(&ua_browse_path);
UA_TranslateBrowsePathsToNodeIdsResponse_deleteMembers(&response);
return node_id;
}
void writeKeyIntPair(UA_Client* client, std::string key, int value) {
UA_NodeId object_id = TranslateBrowsePathtoNodeId(client, std::vector<std::string>{"Robot", "KeyValueMaps", "KeyIntMap"});
UA_NodeId replace_id = TranslateBrowsePathtoNodeId(client, std::vector<std::string>{"Robot", "KeyValueMaps", "KeyIntMap", "Replace"});
UA_String argString = UA_String_fromChars(const_cast<char*>(key.c_str()));
UA_KeyIntPair my_value;
my_value.key = argString;
my_value.value = value;
UA_ExtensionObject eo;
UA_ExtensionObject_init(&eo);
eo.encoding = UA_EXTENSIONOBJECT_DECODED;
eo.content.decoded.data = &my_value;
eo.content.decoded.type = &OPC_UA_SERVICE_TYPES[OPC_UA_SERVICE_TYPES_KEYINTPAIR];
UA_Variant input;
UA_Variant_init(&input);
UA_Variant_setScalarCopy(&input, &eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
UA_Variant *output;
size_t outputSize;
UA_StatusCode retval = UA_Client_call(client, object_id, replace_id, 1, &input, &outputSize, &output);
if (retval != UA_STATUSCODE_GOOD)
{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "[OPC UA Client] WriteKeyIntPair: Method call was unsuccessful!");
return;
}
UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]);
}
UA_Int32 readKeyIntPair(UA_Client* client, std::string key) {
UA_NodeId object_id = TranslateBrowsePathtoNodeId(client, std::vector<std::string>{"Robot", "KeyValueMaps", "KeyIntMap"});
UA_NodeId read_id = TranslateBrowsePathtoNodeId(client, std::vector<std::string>{"Robot", "KeyValueMaps", "KeyIntMap", "Read"});
UA_String argString = UA_String_fromChars(const_cast<char*>(key.c_str()));
UA_KeyIntPair ret;
UA_Variant input;
UA_Variant_init(&input);
UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
UA_Variant *output;
size_t outputSize;
UA_StatusCode retval = UA_Client_call(client, object_id, read_id, 1, &input, &outputSize, &output);
if (retval != UA_STATUSCODE_GOOD)
{
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "[OPC UA Client] WriteKeyIntPair: Method call was unsuccessful!");
return 0;
}
UA_Int32 value = *(static_cast<UA_Int32*>(output->data));
UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]);
return value;
}
int main(void) {
UA_Client* client = UA_Client_new();
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
UA_StatusCode retval = UA_Client_connect_username(client, "opc.tcp://<robot-ip>:4840", "<username>", "<password>");
if(retval != UA_STATUSCODE_GOOD) {
UA_Client_delete(client);
return (int)retval;
}
writeKeyIntPair(client, "Hello, World!", 123);
UA_Int32 val = readKeyIntPair(client, "Hello, World!");
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Value: %u.", val);
return EXIT_SUCCESS;
}
Building the sample client (please avoid white spaces in the project directory!):
$ cd dummy_client
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Debug ..
$ make
Running the sample client:
$ ./dummy_client
[2019-05-14 11:38:38.188 (UTC+0200)] info/client Connecting to endpoint opc.tcp://<robot-ip>:4840
[2019-05-14 11:38:38.188 (UTC+0200)] warn/securitypolicy No PKI plugin set. Accepting all certificates
[2019-05-14 11:38:38.189 (UTC+0200)] info/client TCP connection established
[2019-05-14 11:38:38.307 (UTC+0200)] info/client Opened SecureChannel with SecurityPolicy http://opcfoundation.org/UA/SecurityPolicy#None
[2019-05-14 11:38:38.307 (UTC+0200)] info/client Endpoint and UserTokenPolicy unconfigured, perform GetEndpoints
[2019-05-14 11:38:38.357 (UTC+0200)] info/client Selected Endpoint opc.tcp://<robot-ip>:4840 with SecurityMode None and SecurityPolicy http://opcfoundation.org/UA/SecurityPolicy#None
[2019-05-14 11:38:38.357 (UTC+0200)] info/client Selected UserTokenPolicy open62541-username-policy with UserTokenType UserName and SecurityPolicy http://opcfoundation.org/UA/SecurityPolicy#None
[2019-05-14 11:38:39.201 (UTC+0200)] info/userland Value: 123.