OpcUa/ServerClientInteraction
1 // ----------------------------------------------------------------------------
24 // ----------------------------------------------------------------------------
25 
26 
27 #include <iostream>
28 #include <memory>
29 #include <locale>
30 #include <codecvt>
31 #include <thread>
32 
33 #include <cvb/opcua/server.hpp>
34 #include <cvb/opcua/client.hpp>
35 
36 #if defined _WIN32 && defined(UNICODE)
37 #define STDOUT std::wcout
38 #else
39 #define STDOUT std::cout
40 #endif
41 
42 int main(int, char*[])
43 {
44  try
45  {
46  // shared between server and client
47  bool started = false;
48  bool stopped = false;
49  auto nodeName = CVB_LIT("TestFloatNode");
50  std::thread th; // server thread
51 
52  // setup a server
53  auto server = [&]()
54  {
55  try
56  {
57  // create actual server object
58  auto server = Cvb::OpcUa::Server::Create(4840);
59 
60  // add a custom namespace (these are used for filtering/sorting data, but are optional, Namespace "0" always exists).
61  auto nsIndex = server->AddNameSpace("My Custom Namespace");
62 
63  // create a nodeId to the "objects" folder, this folder exists/should exist in all server implementations.
64  auto root = Cvb::OpcUa::NodeID::Create(Cvb::OpcUa::Namespace0NodeID::OBJECTSFOLDER);
65  // create a nodeId of a "folder" type. This is needed to create a folder.
66  auto type = Cvb::OpcUa::NodeID::Create(Cvb::OpcUa::Namespace0NodeID::FOLDERTYPE);
67  // create a folder node with the previous namespace and nodeId.
68  auto folder = Cvb::OpcUa::ObjectNode::CreateFromType(nsIndex, "My Custom Folder", *root, *type);
69  // add the node
70  server->AddNode(*folder);
71 
72  // create a "float" node.
73  auto node = Cvb::OpcUa::FloatNode::Create(nsIndex, nodeName, *folder->NodeID(), 5.5);
74 
75  // add the float node.
76  server->AddNode(*node);
77 
78  // register a callback to the float node.
79  auto callbackCookieWrite = node->RegisterWriteCallback([&node]()
80  {
81  STDOUT << CVB_LIT("write to ") << node->DisplayName() << std::endl;
82  });
83 
84  // start the server
85  server->Start();
86 
87  // this simply tells the client thread that the server is ready and can be connected on.
88  started = true;
89 
90  // wait until end of the test.
91  while (!stopped)
93 
94  // stop the server.
95  server->Stop();
96 
97  // unregister the callback.
98  node->UnregisterCallback(callbackCookieWrite);
99  }
100  catch (Cvb::OpcUa::OpcUaException e1)
101  {
102  started = true; // to ignore waiting
103  stopped = true;
104  std::cout << e1.what() << std::endl;
105  }
106  catch (const std::exception & ex)
107  {
108  started = true; // to ignore waiting
109  stopped = true;
110  std::cout << ex.what() << std::endl;
111  }
112 
113  };
114  // start server
115  th = std::thread(server);
116 
117  // wait until server is ready
118  while (!started)
120 
121  if (stopped)
122  throw std::runtime_error("server creation failed");
123 
124  try
125  {
126  // create and connect client (client stops/disconnects at the end of its livetime, hence the extra scope)
127  auto client = Cvb::OpcUa::Client::Create(CVB_LIT("opc.tcp://127.0.0.1:4840"));
128 
129  // get server objectsfolder nodeid
130  auto obj = client->Node(*Cvb::OpcUa::NodeID::Create(Cvb::OpcUa::Namespace0NodeID::OBJECTSFOLDER));
131 
132  // defining our browsefilter
134  // apply the browsefilter. the result is a vector of nodeIds.
135  auto result = obj->Browse(*bf);
136 
137  // iterate results
138  for (const auto & element : result)
139  {
140  // get generic node (and node properties)
141  auto node = client->Node<Cvb::OpcUa::BaseNode>(*element);
142 
143  // print node displayname and expandedtext (nodeid/namespace)
144  auto name = node->DisplayName();
145  auto ns = node->NodeID()->ExpandedText();
146  std::cout << ns << " " << name << std::endl;
147 
148  // read and write the value of all FloatNodes
149  if (node->NodeClass() == Cvb::OpcUa::NodeClass::Variable)
150  {
151  // get the node again as a variable node (this way we can get a specific type extracted)
152  auto vnode = client->Node<Cvb::OpcUa::VariableNode>(*element);
153  if (vnode->DataType() == Cvb::OpcUa::DataType::Double || vnode->DataType() == Cvb::OpcUa::DataType::Float)
154  {
155  // now get the node a float
156  auto fnode = client->Node<Cvb::OpcUa::FloatNode>(*element);
157 
158  // read -> write -> read
159  auto tmp = fnode->Value();
160  std::cout << "node value before change " << tmp << std::endl;
161  fnode->SetValue(tmp + 1.1);
162  std::cout << "node value after change" << fnode->Value() << std::endl;
163  }
164  }
165  }
166  // the end of the scope will disconnect the client from the server
167 
168  // stop the server
169  stopped = true;
170  }
171  catch (Cvb::OpcUa::OpcUaException e1)
172  {
173  std::cout << "client: " << e1.what() << std::endl;
174  stopped = true;
175  }
176  catch (const std::exception & ex)
177  {
178  std::cout << "client: " << ex.what() << std::endl;
179  stopped = true;
180  }
181  th.join();
182  }
183  catch (Cvb::OpcUa::OpcUaException e1)
184  {
185  std::cout << e1.what() << std::endl;
186  return e1.ErrorCode();
187  }
188  catch (const std::exception & ex)
189  {
190  std::cout << ex.what() << std::endl;
191  return -1;
192  }
193  return 0;
194 }
static OpcUa::ClientPtr Create(const Cvb::String &Url)
Creates an OPCUA Client object. And connect it to a given server. There is no disconnect/connect func...
Definition: detail_client.hpp:24
double Value() const
Returns the saved value of the node.
Definition: float_node.hpp:66
Variable BaseNode Class.
static ServerPtr Create(const std::uint16_t port)
Creates an OPCUA server with the specified port number.
Definition: detail_server.hpp:23
single precision floating point number
String DisplayName() const
Returns the humanreadable name of a node.
Definition: decl_base_node.hpp:91
T sleep_for(T... args)
int ErrorCode()
Retuns the error code. See Cvb::ErrorCodes.
Definition: exception.hpp:50
double precision floating point number
A FloatNode object provides an interface for storage and manipulation of floating point numbers.
Definition: float_node.hpp:23
static NodeIDPtr Create(Namespace0NodeID id)
Creates an id based on a predefined Namespace0 node id.
Definition: node_id.hpp:48
STL class.
Special runtime exception to carry a native error code.
Definition: exception.hpp:24
static FloatNodePtr Create(std::uint16_t namespaceIndex, const Cvb::String &name, const OpcUa::NodeID &parentNodeID, double value)
Creates an OPCUA Variable with the specified parameter, data type and set its value as double.
Definition: float_node.hpp:45
static BrowseFilterPtr Create()
Creates an even simpler BrowseFilter for browsing the OPCUA client.
Definition: browse_filter.hpp:76
An OPCUA VariableNode object. It handles the data modeling acording to the OPCUA specification.
Definition: variable_node.hpp:25
static ObjectNodePtr CreateFromType(const std::uint16_t NameSpaceIndex, const Cvb::String &Name, const OpcUa::NodeID &Parent, const OpcUa::NodeID &TypeDefinition)
Creates a OPCUA object node with a given type definition.
Definition: object_node.hpp:49
STL class.
An OPCUA BaseNode. This is the base for all other node classes. For instantiation of a specific node ...
Definition: decl_base_node.hpp:34