Files
open62541/examples/client_historical.c
Andreas Ebner 918f2cfd4b fix(docs): typos in comments, docs and messages
Fix misspellings found with codespell across headers, sources, examples,
tests and the documentation, including "propably" in the nodeset
compiler docs. Identifiers, companion spec names and generated code are
left untouched.
2026-09-28 16:20:44 +02:00

187 lines
6.4 KiB
C

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef UA_ENABLE_EXPERIMENTAL_HISTORIZING
static void
printUpdateType(UA_HistoryUpdateType type) {
switch (type) {
case UA_HISTORYUPDATETYPE_INSERT:
printf("Insert\n");
return;
case UA_HISTORYUPDATETYPE_REPLACE:
printf("Replace\n");
return;
case UA_HISTORYUPDATETYPE_UPDATE:
printf("Update\n");
return;
case UA_HISTORYUPDATETYPE_DELETE:
printf("Delete\n");
return;
default:
printf("Unknown\n");
return;
}
}
#endif
static void
printTimestamp(char *name, UA_DateTime date) {
UA_DateTimeStruct dts = UA_DateTime_toStruct(date);
if (name)
printf("%s: %02u-%02u-%04u %02u:%02u:%02u.%03u, ", name,
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
else
printf("%02u-%02u-%04u %02u:%02u:%02u.%03u, ",
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
}
static void
printDataValue(UA_DataValue *value) {
/* Print status and timestamps */
if (value->hasServerTimestamp)
printTimestamp("ServerTime", value->serverTimestamp);
if (value->hasSourceTimestamp)
printTimestamp("SourceTime", value->sourceTimestamp);
if (value->hasStatus)
printf("Status 0x%08x, ", value->status);
if (value->value.type == &UA_TYPES[UA_TYPES_UINT32]) {
UA_UInt32 hrValue = *(UA_UInt32 *)value->value.data;
printf("Uint32Value %u\n", hrValue);
}
if (value->value.type == &UA_TYPES[UA_TYPES_DOUBLE]) {
UA_Double hrValue = *(UA_Double *)value->value.data;
printf("DoubleValue %f\n", hrValue);
}
}
static UA_Boolean
readRaw(const UA_HistoryData *data) {
printf("readRaw Value count: %lu\n", (long unsigned)data->dataValuesSize);
/* Iterate over all values */
for (UA_UInt32 i = 0; i < data->dataValuesSize; ++i)
{
printDataValue(&data->dataValues[i]);
}
/* We want more data! */
return true;
}
#ifdef UA_ENABLE_EXPERIMENTAL_HISTORIZING
static UA_Boolean
readRawModified(const UA_HistoryModifiedData *data) {
printf("readRawModified Value count: %lu\n", (long unsigned)data->dataValuesSize);
/* Iterate over all values */
for(size_t i = 0; i < data->dataValuesSize; ++i) {
printDataValue(&data->dataValues[i]);
}
printf("Modification Value count: %llu\n",
(long long unsigned)data->modificationInfosSize);
for(size_t j = 0; j < data->modificationInfosSize; ++j) {
if(data->modificationInfos[j].userName.data)
printf("Username: %s, ", data->modificationInfos[j].userName.data);
printTimestamp("Modtime", data->modificationInfos[j].modificationTime);
printUpdateType(data->modificationInfos[j].updateType);
}
/* We want more data! */
return true;
}
static UA_Boolean
readEvents(const UA_HistoryEvent *data) {
printf("readEvent Value count: %lu\n", (long unsigned)data->eventsSize);
for (size_t i = 0; i < data->eventsSize; ++i) {
printf("Processing event: %lu\n", (long unsigned)i);
for (size_t j = 0; j < data->events[i].eventFieldsSize; ++j) {
printf("Processing %lu: %s\n", (long unsigned)j, data->events[i].eventFields[j].type->typeName);
}
}
return true;
}
#endif
static UA_Boolean
readHist(UA_Client *client, const UA_NodeId *nodeId,
UA_Boolean moreDataAvailable,
const UA_ExtensionObject *data, void *unused) {
printf("\nRead historical callback:\n");
printf("\tHas more data:\t%d\n\n", moreDataAvailable);
if (data->content.decoded.type == &UA_TYPES[UA_TYPES_HISTORYDATA]) {
return readRaw((UA_HistoryData*)data->content.decoded.data);
}
#ifdef UA_ENABLE_EXPERIMENTAL_HISTORIZING
if (data->content.decoded.type == &UA_TYPES[UA_TYPES_HISTORYMODIFIEDDATA]) {
return readRawModified((UA_HistoryModifiedData*)data->content.decoded.data);
}
if (data->content.decoded.type == &UA_TYPES[UA_TYPES_HISTORYEVENT]) {
return readEvents((UA_HistoryEvent*)data->content.decoded.data);
}
#endif
return true;
}
int main(int argc, char *argv[]) {
UA_Client *client = UA_Client_new();
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
/* Connect to the Unified Automation demo server */
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840/");
if(retval != UA_STATUSCODE_GOOD) {
printf("Could not connect\n");
UA_Client_delete(client);
return EXIT_SUCCESS;
}
/* Read historical values (uint32) */
printf("\nStart historical read (1, \"myUintValue\"):\n");
UA_NodeId node = UA_NODEID_STRING(2, "MyLevel");
retval = UA_Client_HistoryRead_raw(client, &node, readHist,
UA_DateTime_fromUnixTime(0), UA_DateTime_now(), UA_STRING_NULL,
false, 10, UA_TIMESTAMPSTORETURN_BOTH, (void *)UA_FALSE);
if (retval != UA_STATUSCODE_GOOD) {
printf("Failed. %s\n", UA_StatusCode_name(retval));
}
#ifdef UA_ENABLE_EXPERIMENTAL_HISTORIZING
printf("\nStart historical modified read (1, \"myUintValue\"):\n");
retval = UA_Client_HistoryRead_modified(client, &node, readHist,
UA_DateTime_fromUnixTime(0), UA_DateTime_now(), UA_STRING_NULL,
false, 10, UA_TIMESTAMPSTORETURN_BOTH, (void *)UA_FALSE);
if (retval != UA_STATUSCODE_GOOD) {
printf("Failed. %s\n", UA_StatusCode_name(retval));
}
printf("\nStart historical event read (1, \"myUintValue\"):\n");
UA_EventFilter filter;
UA_EventFilter_init(&filter);
UA_NodeId eventNode = UA_NODEID_NUMERIC(0, 2253);
retval = UA_Client_HistoryRead_events(client, &eventNode, readHist,
UA_DateTime_fromUnixTime(0), UA_DateTime_now(), UA_STRING_NULL,
filter, 10, UA_TIMESTAMPSTORETURN_BOTH, (void *)UA_FALSE);
if (retval != UA_STATUSCODE_GOOD) {
printf("Failed. %s\n", UA_StatusCode_name(retval));
}
#endif
UA_Client_disconnect(client);
UA_Client_delete(client);
return 0;
}