Historizing a variable

226 views
Skip to first unread message

Jacky Bek

unread,
Nov 8, 2020, 9:51:03 AM11/8/20
to open62541
I read that it is possible to create a node and make it 'history-capable'.
Is there any sample code?

Jan Hecht

unread,
Nov 9, 2020, 2:30:04 AM11/9/20
to open62541
I haven't tried it yet, but maybe you have a look into this:

BR,
Jan

Jacky Bek

unread,
Dec 2, 2020, 7:03:31 AM12/2/20
to open62541
Hi Jan,
There are 2 compile error which i don't quite understand:

1.
In file included from myNewServer.c:25:
/usr/include/open62541/plugin/history_database.h:20:19: error: expected declaration specifiers or ‘...’ before ‘UA_HistoryDatabase’
     void (*clear)(UA_HistoryDatabase *hdb);
                   ^~~~~~~~~~~~~~~~~~
2.
myNewServer.c: In function ‘ConnectToAirgard’:
myNewServer.c:2226:10: error: ‘UA_ServerConfig’ {aka ‘struct UA_ServerConfig’} has no member named ‘historyDatabase’
    config->historyDatabase = UA_HistoryDatabase_default(HistoryDataGathering);

In the 2nd error, config is declared as UA_ServerConfig *config = UA_Server_getConfig(server) which is from the standard build.
For the historizing tutorial, it makes a reference to an element 'historyDatabase' which is non existent.

Is there a new structure defined somewhere that inherits the properties from?

Many thanks.


Jacky Bek

unread,
Dec 2, 2020, 9:46:17 AM12/2/20
to open62541
Hi,
I thought it would be easier to show you my codes and order of the header files as follows.
Initially, I got a compile error complaining : UA_HistoryDatabase not defined.

I then tried to modify open62541.h by adding :
struct UA_HistoryDatabase;
typedef struct UA_HistoryDatabase UA_HistoryDatabase;

it then complain : expected specifier-qualifier-list before typedef.
(see left bottom screen).

The funny thing is further down the file in open62541.h, a similar declaration but it did not complain error:
struct UA_Server;
typedef struct UA_Server UA_Server;

HistorizingCompileError.PNG



Jacky Bek

unread,
Dec 2, 2020, 9:54:28 AM12/2/20
to open62541
sorry, the last statement should be:

The funny thing is further down the file in open62541.h, a similar declaration but it did not complain error:
struct UA_Client;
typedef struct UA_Client UA_Client;

I tried to move the header files around (e.g. move historydatabase.h before open62541.h but it introduced more errors).
Please advise how I can go about resolving this circular reference error.

Jacky Bek

unread,
Dec 24, 2020, 9:48:58 PM12/24/20
to open62541
I manage to compile my code that contains historizing capabilities.

However, I am still getting the following messages within UAExpert when i add a historizing node:
- found session for ServerId 0
- HistoryReadRawModified succeeded
- HistoryReadDataResults[0] has bad status BadHistoryOperationInvalid
- No history values received for node 'NS1|Numeric|10302'

i combed through the documentations relating to Historizing function.  See below:
Did i miss anything?

***********************************************************************************************************************

in SV_StartOPCUAServer.c:, i have the following functions declared:
=========
static UA_Boolean allowHistoryUpdateUpdateData(UA_Server *server, UA_AccessControl *ac,
                const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeId,
                UA_PerformUpdateType performInsertReplace,
                const UA_DataValue *value) {
return true;
}

static UA_Boolean allowHistoryUpdateDeleteRawModified(UA_Server *server, UA_AccessControl *ac,
                const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeId,
                UA_DateTime startTimestamp,
                UA_DateTime endTimestamp,
                bool isDeleteModified) {
return true;
}
=========
In my main() function, i have:

main()
{
UA_Server myServer;
UA_ServerConfig config1;
...

                config1.accessHistoryDataCapability = true;
                config1.maxReturnDataValues = 0 ;  // 0 means unlimited size
                config1.accessHistoryEventsCapability = true;
                config1.maxReturnEventValues = 0;  // 0 means unlimted size
                config1.insertDataCapability = true;
                config1.insertEventCapability = true;
                config1.insertAnnotationsCapability = true;
                config1.replaceDataCapability = true;
                config1.replaceEventCapability = true;
                config1.updateDataCapability = true;
                config1.updateEventCapability = true;
                config1.deleteRawCapability = true;
                config1.deleteEventCapability = true;
                config1.deleteAtTimeDataCapability = true;

                config1.accessControl.allowHistoryUpdateUpdateData = allowHistoryUpdateUpdateData;
                config1.accessControl.allowHistoryUpdateDeleteRawModified = allowHistoryUpdateDeleteRawModified;

CreateOPCUANodes(myServer); // verified ok
CreateServerMethodItems(myServer); // verified ok
CreateServerHistorizingItems(myServer); // error messages shown in UAExpert
CreateServerMonitoredItems(myServer); // server log shows successful
}
==================
In CreateOPCUANodes() function::
---------------------
// In SV_CreateOPCUANodes.c

extern UA_NodeId outIgramPP_Id;
CreateOPCUANodes(myServer)
{
...
UA_VariableAttributes vIgramPPAttr = UA_VariableAttributes_default;
        vIgramPPAttr.description = UA_LOCALIZEDTEXT("en-US", "IgramPPInfo");
        vIgramPPAttr.displayName = UA_LOCALIZEDTEXT("en-US", "01. Igram PP");
        vIgramPPAttr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD;
        vIgramPPAttr.historizing = true;
        //UA_Float IgramPP = (UA_Float) XMLIgramPP;     // value is set in print_element_names
        UA_Variant_setScalar(&vIgramPPAttr.value, &IgramPP, &UA_TYPES[UA_TYPES_FLOAT]);
        UA_Server_addVariableNode(uaServer, UA_NODEID_NUMERIC(1, 10301),        // 1 refers to namespace : NS1
            r2_airgard_diagnostics_Id,
            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
            UA_QUALIFIEDNAME(1, "Igram PP"),
            UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
            vIgramPPAttr, NULL, &outIgramPP_Id);
        //vIgramPPAttr, NULL, &ds1IgramPPId);
}
---------------------
In CreateServerHistorizingItems() function::
// In SV_Historizing.c

extern UA_NodeId outIgramPP_Id;
..

void CreateServerHistorizingItems(UA_Server *server)
{
                       size_t initialNodeIdStoreSize = 100000;

                        UA_HistoryDataGathering HistoryDataGathering = UA_HistoryDataGathering_Default(initialNodeIdStoreSize); // initial NodeStore Size = 1
                        UA_ServerConfig *config = UA_Server_getConfig(server);
                        config->historyDatabase = UA_HistoryDatabase_default(HistoryDataGathering);

                        UA_HistorizingNodeIdSettings HistorizingSetting;
                        HistorizingSetting.historizingBackend = UA_HistoryDataBackend_Memory(21, 20); // 21 nodes, 20 values
                        HistorizingSetting.maxHistoryDataResponseSize = 20;

                        HistorizingSetting.pollingInterval = 100;
                        HistorizingSetting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_POLL;

                        int retval;
                        retval = HistoryDataGathering.registerNodeId(server, HistoryDataGathering.context, &outIgramPP_Id, HistorizingSetting);
                        retval = HistoryDataGathering.registerNodeId(server, HistoryDataGathering.context, &outIgramDC_Id, HistorizingSetting);
                        retval = HistoryDataGathering.registerNodeId(server, HistoryDataGathering.context, &outLaserPP_Id, HistorizingSetting);
                        retval = HistoryDataGathering.registerNodeId(server, HistoryDataGathering.context, &outLaserDC_Id, HistorizingSetting);
                        retval = HistoryDataGathering.registerNodeId(server, HistoryDataGathering.context, &outSingleBeamAt900_Id, HistorizingSetting);
====================

Jacky Bek

unread,
Dec 24, 2020, 9:56:21 PM12/24/20
to open62541
see attached for easy reference.
1. HistorizingError3.txt - code snippets
2. HistorizingChart.png - screen capture of UAExpert showing error message
HistorizingChart.PNG
HistorizingError3.txt

Jacky Bek

unread,
Dec 25, 2020, 9:34:36 PM12/25/20
to open62541
I made some changes to my server code:

Now there is no more errors relating to the instantiation of historizing nodes.
I also added a rand() function to my code to force a change to the value set in the Node in every data update cycle.
I verified using UAExpert that in the 'data access view', the nodeId is correct and the value changes.

But when i drag and drop the same Node to the HistoryTrend View in UAExpert,  the log shows:
1. History Plugin - Found session for ServerId 1
2. History Plugin - HistoryReadRawModified succeeded
3. History Plugin - No history values received for node 'NS1|Numeric|10301'

See the attached code snippets.
For your advice please.
Thanks.
HistorizingError4.txt

Jacky Bek

unread,
Dec 30, 2020, 7:01:05 PM12/30/20
to open62541
resolved.
Reply all
Reply to author
Forward
0 new messages