{"id":988,"date":"2019-02-15T13:40:52","date_gmt":"2019-02-15T12:40:52","guid":{"rendered":"https:\/\/blog2.basyskom.com\/?p=988"},"modified":"2024-07-30T14:14:46","modified_gmt":"2024-07-30T12:14:46","slug":"initial-support-for-servers-with-historical-data-access-in-open62541","status":"publish","type":"post","link":"https:\/\/www.basyskom.de\/en\/initial-support-for-servers-with-historical-data-access-in-open62541\/","title":{"rendered":"Initial support for servers with historical data access in open62541"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"988\" class=\"elementor elementor-988\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-7543eaf3 elementor-section-boxed elementor-section-height-default elementor-section-height-default wpr-particle-no wpr-jarallax-no wpr-parallax-no wpr-sticky-section-no wpr-column-slider-no wpr-equal-height-no\" data-id=\"7543eaf3\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-619f976b\" data-id=\"619f976b\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-496abe13 elementor-widget elementor-widget-text-editor\" data-id=\"496abe13\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p><\/p>\n<p><\/p>\n<h3 class=\"wp-block-heading\" id=\"Initialsupportforserverswithhistoricaldataaccessinopen62541-Overview\">Overview about the open62541 historical data access<\/h3>\n<p><\/p>\n<p>Most of the new functionality is contained within a plugin called UA_HistoryDatabase. This plugin contains three main API elements.<\/p>\n<p><\/p>\n<ul class=\"wp-block-list\">\n<li>UA_HistoryDatabase (same name as the plugin) which contains the main interface between the server itself and the plugin.<\/li>\n<li>UA_HistoryDataBackend which implements the integration with a specific database. A sample implementation based on a simple in-memory database is provided.<\/li>\n<li>UA_HistoryDataGathering which encapsulates the gathering and storage of data.\u00a0<\/li>\n<\/ul>\n<p><\/p>\n<p>The following diagram gives an overview how\u00a0these API elements interact.<\/p>\n<p><\/p>\n<figure class=\"wp-block-image\"><img fetchpriority=\"high\" decoding=\"async\" class=\"alignnone wp-image-999\" src=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/image2019-1-31_10-44-25.png\" alt=\"open62541 - historical data access\" width=\"1986\" height=\"932\" srcset=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/image2019-1-31_10-44-25.png 1986w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/image2019-1-31_10-44-25-300x141.png 300w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/image2019-1-31_10-44-25-1024x481.png 1024w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/image2019-1-31_10-44-25-768x360.png 768w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/image2019-1-31_10-44-25-1536x721.png 1536w\" sizes=\"(max-width: 1986px) 100vw, 1986px\" \/><\/figure>\n<p><\/p>\n<h3 class=\"wp-block-heading\" id=\"Initialsupportforserverswithhistoricaldataaccessinopen62541-Tutorial\">Tutorial<\/h3>\n<p><\/p>\n<p>The following tutorial will first demonstrate how to create a simple server, hosting a single variable node. We will extend this server to store this value in an in-memory database each time it changes.<\/p>\n<p><\/p>\n<p>Let&#8217;s start with a server:<\/p>\n<p><\/p>\n<pre class=\"wp-block-code\"><code>#include \"open62541.h\"\n#include \n \nstatic UA_Boolean running = true;\nstatic void stopHandler(int sign) {\n    (void)sign;\n    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, \"received ctrl-c\");\n    running = false;\n}\n \n \nint main(void) {\n    signal(SIGINT, stopHandler);\n    signal(SIGTERM, stopHandler);\n \n    UA_ServerConfig *config = UA_ServerConfig_new_default();\n    UA_Server *server = UA_Server_new(config);\n    \/* Define the attribute of the uint32 variable node *\/\n    UA_VariableAttributes attr = UA_VariableAttributes_default;\n    UA_UInt32 myUint32 = 40;\n    UA_Variant_setScalar(&amp;attr.value, &amp;myUint32, &amp;UA_TYPES[UA_TYPES_UINT32]);\n    attr.description = UA_LOCALIZEDTEXT(\"en-US\",\"myUintValue\");\n    attr.displayName = UA_LOCALIZEDTEXT(\"en-US\",\"myUintValue\");\n    attr.dataType = UA_TYPES[UA_TYPES_UINT32].typeId;\n    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;\n \n    \/* Add the variable node to the information model *\/\n    UA_NodeId uint32NodeId = UA_NODEID_STRING(1, \"myUintValue\");\n    UA_QualifiedName uint32Name = UA_QUALIFIEDNAME(1, \"myUintValue\");\n    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);\n    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);\n    UA_NodeId outNodeId;\n    UA_NodeId_init(&amp;outNodeId);\n    UA_StatusCode retval = UA_Server_addVariableNode(server,\n                                                     uint32NodeId,\n                                                     parentNodeId,\n                                                     parentReferenceNodeId,\n                                                     uint32Name,\n                                                     UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),\n                                                     attr,\n                                                     NULL,\n                                                     &amp;outNodeId);\n    fprintf(stderr, \"UA_Server_addVariableNode %s\\n\", UA_StatusCode_name(retval));\n    retval = UA_Server_run(server, &amp;running);\n    fprintf(stderr, \"UA_Server_run %s\\n\", UA_StatusCode_name(retval));\n    UA_Server_run_shutdown(server);\n    UA_Server_delete(server);\n    UA_ServerConfig_delete(config);\n    return (int)retval;\n}<\/code><\/pre>\n<p><\/p>\n<p>The resulting server can be browsed and the variable can be read. We use UAExpert for this tasks.\u00a0<\/p>\n<p><\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" width=\"1600\" height=\"835\" class=\"wp-image-1000\" src=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_151851.png\" alt=\"basysKom, HMI Dienstleistung, Qt, Cloud, Azure\" srcset=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_151851.png 1600w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_151851-300x157.png 300w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_151851-1024x534.png 1024w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_151851-768x401.png 768w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_151851-1536x802.png 1536w\" sizes=\"(max-width: 1600px) 100vw, 1600px\" \/><\/figure>\n<p><\/p>\n<p>We now extend this example so that the server will be able to handle request for historical values for this node. Each of the following snippets contains enough context so it is clear where to add the code into the initial server code.<\/p>\n<p><\/p>\n<pre class=\"wp-block-code\"><code>[...]\nUA_ServerConfig *config = UA_ServerConfig_new_default();\n \n \n\/\/ Instanciate a UA_HistoryDataGathering with an initial node id store size of 1.\n \n\/\/ The store will grow if additional nodes are registered, but this is expensive.\nUA_HistoryDataGathering gathering = UA_HistoryDataGathering_Default(1);\n\/\/ configure the server with an instance of the UA_HistoryDatabase plugin\nconfig-&gt;historyDatabase = UA_HistoryDatabase_default(gathering);\nUA_Server *server = UA_Server_new(config);\nUA_VariableAttributes attr = UA_VariableAttributes_default;\nUA_UInt32 myUint32 = 40;\nUA_Variant_setScalar(&amp;attr.value, &amp;myUint32, &amp;UA_TYPES[UA_TYPES_UINT32]);\nattr.description = UA_LOCALIZEDTEXT(\"en-US\",\"myUintValue\");\nattr.displayName = UA_LOCALIZEDTEXT(\"en-US\",\"myUintValue\");\nattr.dataType = UA_TYPES[UA_TYPES_UINT32].typeId;\n \n\/\/ announce support for history read to clients\nattr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD;\n\/\/ tell the server to enable historizing for this node\nattr.historizing = true;\n \nUA_NodeId uint32NodeId = UA_NODEID_STRING(1, \"myUintValue\");\nUA_QualifiedName uint32Name = UA_QUALIFIEDNAME(1, \"myUintValue\");\n[...]<\/code><\/pre>\n<p><\/p>\n<p>Next we configure the node to update the database each time the nodes value is set.<\/p>\n<p><\/p>\n<pre class=\"wp-block-code\"><code>[...]\n                                                 NULL,\n                                                 &amp;outNodeId);\nfprintf(stderr, \"UA_Server_addVariableNode %s\\n\", UA_StatusCode_name(retval));\n \nUA_HistorizingNodeIdSettings setting;\n\/* Use the default sample in-memory database. Reserve space for 3 nodes with an initial room of 100 values each.\n * This will also automaticaly grow if needed. *\/\nsetting.historizingBackend = UA_HistoryDataBackend_Memory(3, 100);\n \n\/* We want the server to serve a maximum of 100 values per request.\n * This value depends on the platform you are running the server on - a big\n * server can serve more values in a single request. *\/\nsetting.maxHistoryDataResponseSize = 100;\n\/\/ update the database each time the node value is set\nsetting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_VALUESET;\n\/\/ register the node for gathering data in the database\nretval = gathering.registerNodeId(server, gathering.context, &amp;outNodeId, setting);\nfprintf(stderr, \"registerNodeId %s\\n\", UA_StatusCode_name(retval));\nretval = UA_Server_run(server, &amp;running);\nfprintf(stderr, \"UA_Server_run %s\\n\", UA_StatusCode_name(retval));\n[...]<\/code><\/pre>\n<p><\/p>\n<p>Again we rely on the UAExpert to validate the server. First update the variable a few times (so we actually have some historical values). Next we want to read them.\u00a0 For that we use the &#8220;History Trend View&#8221; which is available via Document\u00a0\u2192 Add\u00a0\u2192 Document Type. The resulting view shows either a graph or (in a second tab) a list of your historical values. If no values are plotted or the list is empty make sure that the right time interval is used in the request.<\/p>\n<p><\/p>\n<figure class=\"wp-block-image\"><img decoding=\"async\" width=\"1600\" height=\"835\" class=\"wp-image-1001\" src=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_154059.png\" alt=\"basysKom, HMI Dienstleistung, Qt, Cloud, Azure\" srcset=\"https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_154059.png 1600w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_154059-300x157.png 300w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_154059-1024x534.png 1024w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_154059-768x401.png 768w, https:\/\/www.basyskom.de\/wp-content\/uploads\/2019\/02\/Screenshot_20181205_154059-1536x802.png 1536w\" sizes=\"(max-width: 1600px) 100vw, 1600px\" \/><\/figure>\n<p><\/p>\n<h3 class=\"wp-block-heading\" id=\"Initialsupportforserverswithhistoricaldataaccessinopen62541-Conclusion&amp;futurework\">Conclusion &amp; future work<\/h3>\n<p><\/p>\n<p>It is now possible to create open62541-based servers which support the gathering and reading of historical data values. A number of plugin interfaces has been defined which can be used to implement functionality such as support for additional databases (e.g. sqlite). There is additional work to be done to support other history read details such as &#8220;read event&#8221;, &#8220;read modified&#8221;, &#8220;read processed&#8221; or &#8220;read at a time&#8221;. Also the history update service still needs to be implemented.<\/p>\n<p><\/p>\n<p>In addition to being a contributor to the project, basysKom also provides commercial support for the open62541 OPC UA stack.\u00a0<a href=\"mailto:info@basyskom.com\">Talk to us<\/a>\u00a0if you are interested in project\/application support, the implementation of missing features or bugfixing.<\/p>\n<p><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>An OPC UA server supporting historical access allows clients to access historical data or historical events. Such a server can act as a process or event historian. open62541-based servers were till recently completely missing the ability to support these use cases. basysKom has extended the server API to support access to historical data using the &#8220;read raw&#8221; functionality specified in OPC UA part 11. This allows to create a simple process historian. This article provides an overview about this API and a short tutorial how to use it.<\/p>","protected":false},"author":6,"featured_media":1953,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[2,230,183],"tags":[122],"class_list":["post-988","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","category-opc-ua","category-open62541","tag-open62541"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/988","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/comments?post=988"}],"version-history":[{"count":10,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/988\/revisions"}],"predecessor-version":[{"id":11184,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/posts\/988\/revisions\/11184"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/media\/1953"}],"wp:attachment":[{"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/media?parent=988"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/categories?post=988"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.basyskom.de\/en\/wp-json\/wp\/v2\/tags?post=988"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}