22 #include "open62541/plugin/log_stdout.h"
32 UA_StatusCode
get_child_variables(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId,
void* handle) {
33 if(isInverse)
return UA_STATUSCODE_GOOD;
35 UA_NodeId organizes = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
37 if(UA_NodeId_equal(&referenceTypeId, &organizes)) {
40 UA_NodeClass outNodeClass;
41 UA_NodeClass_init(&outNodeClass);
42 UA_Server_readNodeClass(handler->server, childId, &outNodeClass);
43 if(outNodeClass == UA_NODECLASS_VARIABLE) {
44 UA_NodeId* temp = UA_NodeId_new();
45 UA_NodeId_copy(&childId, temp);
46 handler->historizing_nodes->insert(handler->historizing_nodes->end(), *temp);
47 handler->historizing_setup->insert(handler->historizing_setup->end(), handler->history);
49 return UA_STATUSCODE_GOOD;
53 vector<AdapterFolderHistorySetup> historyfolders, UA_Server* mappedServer, UA_ServerConfig* server_config) {
54 for(
size_t i = 0; i < historyfolders.size(); i++) {
55 UA_NodeId* temp = UA_NodeId_new();
56 UA_StatusCode retval = UA_Server_readNodeId(mappedServer, historyfolders[i].folder_id, temp);
57 UA_NodeId_clear(temp);
58 if(retval == UA_STATUSCODE_GOOD) {
60 handle.
server = mappedServer;
61 handle.
history = historyfolders[i].folder_historizing;
64 UA_Server_forEachChildNodeCall(mappedServer, historyfolders[i].folder_id,
get_child_variables, &handle);
67 UA_LOG_WARNING(server_config->logging, UA_LOGCATEGORY_USERLAND,
68 "Warning! Folder is not mapped in the server. StatusCode: %s ", UA_StatusCode_name(retval));
74 vector<AdapterPVHistorySetup> historyvariables, UA_Server* mappedServer, UA_ServerConfig* server_config) {
75 for(
size_t i = 0; i < historyvariables.size(); i++) {
76 UA_NodeId* temp = UA_NodeId_new();
77 UA_NodeId
id = historyvariables[i].variable_id;
78 UA_StatusCode retval = UA_Server_readNodeId(mappedServer,
id, temp);
79 if(retval == UA_STATUSCODE_GOOD) {
80 UA_String out = UA_STRING_NULL;
81 UA_print(&
id, &UA_TYPES[UA_TYPES_NODEID], &out);
82 UA_LOG_INFO(server_config->logging, UA_LOGCATEGORY_USERLAND,
"add Node %.*s ", (
int)out.length, out.data);
83 UA_String_clear(&out);
84 historizing_nodes->insert(historizing_nodes->end(), historyvariables[i].variable_id);
85 historizing_setup->insert(historizing_setup->end(), historyvariables[i].variable_historizing);
88 UA_String out = UA_STRING_NULL;
89 UA_print(&
id, &UA_TYPES[UA_TYPES_NODEID], &out);
90 UA_LOG_WARNING(server_config->logging, UA_LOGCATEGORY_USERLAND,
91 "Warning! Node %.*s has a history configuration but is not mapped to the server. StatusCode: %s ",
92 (
int)out.length, out.data, UA_StatusCode_name(retval));
93 UA_String_clear(&out);
95 UA_NodeId_clear(temp);
102 UA_Server_readAccessLevel(mappedServer,
id, &temp);
103 if(temp & UA_ACCESSLEVELMASK_READ) {
104 temp |= UA_ACCESSLEVELMASK_HISTORYREAD;
105 UA_Server_writeAccessLevel(mappedServer,
id, temp);
107 UA_Server_writeHistorizing(mappedServer,
id,
true);
108 UA_Byte_clear(&temp);
112 vector<UA_NodeId>& historizing_nodes, vector<string>& historizing_setup, UA_ServerConfig* server_config) {
117 for(
size_t i = 0; i < historizing_nodes.size(); i++) {
118 for(
size_t j = i + 1; j < historizing_nodes.size(); j++) {
119 if(UA_NodeId_equal(
reinterpret_cast<UA_NodeId*
>(&historizing_nodes[i]),
120 reinterpret_cast<UA_NodeId*
>(&historizing_nodes[j]))) {
121 UA_String out = UA_STRING_NULL;
122 UA_print(
reinterpret_cast<UA_NodeId*
>(&historizing_nodes[j]), &UA_TYPES[UA_TYPES_NODEID], &out);
123 UA_LOG_INFO(server_config->logging, UA_LOGCATEGORY_USERLAND,
124 "Node %.*s has multiple history settings. The first folder/process_variable setting in the mapping "
125 "file is considered if multiple exists/overlap. "
126 "process_variable settings are preferred over folder settings.",
127 (
int)out.length, out.data);
128 UA_String_clear(&out);
129 UA_NodeId_clear(
reinterpret_cast<UA_NodeId*
>(&historizing_nodes[j]));
130 historizing_nodes.erase(historizing_nodes.begin() + j);
131 historizing_setup.erase(historizing_setup.begin() + j);
142 vector<string>& historizing_setup, UA_ServerConfig* server_config, vector<AdapterHistorySetup> history) {
147 for(
size_t i = position; i < historizing_nodes.size(); i++) {
149 for(
auto& j : history) {
150 if(historizing_setup[i] == j.name) {
156 UA_String out = UA_STRING_NULL;
157 UA_print(
reinterpret_cast<UA_NodeId*
>(&historizing_nodes[i]), &UA_TYPES[UA_TYPES_NODEID], &out);
158 UA_LOG_WARNING(server_config->logging, UA_LOGCATEGORY_USERLAND,
159 "Warning! Remove node %.*s from historizing because the setup %s is missing.", (
int)out.length, out.data,
160 historizing_setup[i].c_str());
161 UA_String_clear(&out);
163 historizing_nodes.erase(historizing_nodes.begin() + i);
164 historizing_setup.erase(historizing_setup.begin() + i);
173 UA_HistoryDataGathering
add_historizing_nodes(vector<UA_NodeId>& historizing_nodes, vector<string>& historizing_setup,
174 UA_Server* mappedServer, UA_ServerConfig* server_config, vector<AdapterHistorySetup> history,
175 vector<AdapterFolderHistorySetup> historyfolders, vector<AdapterPVHistorySetup> historyvariables) {
177 add_folder_historizing(&historizing_nodes, &historizing_setup, historyfolders, mappedServer, server_config);
181 UA_HistoryDataGathering gathering = UA_HistoryDataGathering_Default(historizing_nodes.size());
182 server_config->historyDatabase = UA_HistoryDatabase_default(gathering);
183 for(
size_t i = 0; i < historizing_nodes.size(); i++) {
184 UA_HistorizingNodeIdSettings setting;
185 setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_POLL;
187 for(
auto& j : history) {
188 if(historizing_setup[i] == j.name) {
193 setting.historizingBackend = UA_HistoryDataBackend_Memory_Circular(historizing_nodes.size(), hist.
buffer_length);
195 setting.pollingInterval = hist.
interval;
196 UA_StatusCode retval = gathering.registerNodeId(mappedServer, gathering.context, &historizing_nodes[i], setting);
197 if(retval != UA_STATUSCODE_GOOD) {
198 UA_String out = UA_STRING_NULL;
199 UA_print(&historizing_nodes[i], &UA_TYPES[UA_TYPES_NODEID], &out);
200 UA_LOG_WARNING(server_config->logging, UA_LOGCATEGORY_USERLAND,
201 "Failed to add historizing for Node %.*s with StatusCode %s", (
int)out.length, out.data,
202 UA_StatusCode_name(retval));
203 UA_String_clear(&out);
205 retval = gathering.startPoll(mappedServer, gathering.context, &historizing_nodes[i]);
206 if(retval != UA_STATUSCODE_GOOD) {
207 UA_String out = UA_STRING_NULL;
208 UA_print(&historizing_nodes[i], &UA_TYPES[UA_TYPES_NODEID], &out);
209 UA_LOG_WARNING(server_config->logging, UA_LOGCATEGORY_USERLAND,
210 "Failed to start the poll for Node %.*s with StatusCode %s", (
int)out.length, out.data,
211 UA_StatusCode_name(retval));
212 UA_String_clear(&out);
218 void clear_history(UA_HistoryDataGathering gathering, vector<UA_NodeId>& historizing_nodes,
219 vector<string>& historizing_setup, UA_Server* mappedServer, vector<AdapterFolderHistorySetup> historyfolders,
220 vector<AdapterPVHistorySetup> historyvariables, UA_ServerConfig* server_config) {
222 for(
auto& historizing_node : historizing_nodes) {
223 UA_StatusCode retval = gathering.stopPoll(mappedServer, gathering.context, &historizing_node);
224 UA_LOG_INFO(server_config->logging, UA_LOGCATEGORY_SERVER,
225 "Stopping polling thread used by the historizing -> %s", UA_StatusCode_name(retval));
228 historizing_nodes.clear();
229 historizing_setup.clear();
231 for(
auto& historyfolder : historyfolders) {
232 UA_NodeId_clear(&historyfolder.folder_id);
234 for(
auto& historyvariable : historyvariables) {
235 UA_NodeId_clear(&historyvariable.variable_id);