2

I am currently trying to publish a datetime value AND a temperature value with the OPC UA implementation called open62541.

For this, I have been using the test example from the open62541 github repository as it is already publishing the current datetime. I have tried to add another DSF(DataSetField) for the temperature value like it was shown with the datetime. But it won't publish it.

The following code snippet shows how I define methods for adding the DataSetFields:

/**
 * **DataSetField handling**
 *
 * The DataSetField (DSF) is part of the PDS and describes exactly one published
 * field. */
static void
addDataSetField(UA_Server *server) {
    /* Add a field to the previous created PublishedDataSet */
    UA_NodeId dataSetFieldIdent;
    UA_DataSetFieldConfig dataSetFieldConfig;
    memset(&dataSetFieldConfig, 0, sizeof(UA_DataSetFieldConfig));
    dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
    dataSetFieldConfig.field.variable.fieldNameAlias = UA_STRING("Server localtime");
    dataSetFieldConfig.field.variable.promotedField = UA_FALSE;

    dataSetFieldConfig.field.variable.publishParameters.publishedVariable =
                  UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
    dataSetFieldConfig.field.variable.publishParameters.attributeId = 
                  UA_ATTRIBUTEID_VALUE;
    UA_Server_addDataSetField(server, publishedDataSetIdent,
                          &dataSetFieldConfig, &dataSetFieldIdent);
}

static void
addDataSetFieldTemperature(UA_Server *server) {
    /* Add a field to the previous created PublishedDataSet */
    UA_NodeId dataSetFieldIdent;
    UA_DataSetFieldConfig dataSetFieldConfig;
    memset(&dataSetFieldConfig, 0, sizeof(UA_DataSetFieldConfig));
    dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
    dataSetFieldConfig.field.variable.fieldNameAlias = UA_STRING("Temperature");
    dataSetFieldConfig.field.variable.promotedField = UA_FALSE;
    dataSetFieldConfig.field.variable.publishParameters.publishedVariable =
                                      UA_NODEID_NUMERIC(0, 50);
    dataSetFieldConfig.field.variable.publishParameters.attributeId =
                                      UA_ATTRIBUTEID_VALUE;
    UA_Server_addDataSetField(server, publishedDataSetIdent, 
                                      &dataSetFieldConfig,
                                      &dataSetFieldIdent);
}

In the main function, I then call both methods to add them to the PDS (PublishedDataSet):

addPubSubConnection(server, transportProfile, networkAddressUrl);
addPublishedDataSet(server);
addDataSetFieldTemperature(server);
addDataSetField(server);
addWriterGroup(server);
addDataSetWriter(server);

The temperature value is a simple double value, so what am I doing wrong here? Maybe the error is within the subscribed client application?

For subscribing to the values published, I have also used the example on github (the file is called tutorial_pubsub_subscribe.c) and I am trying to parse the values as followed:

/* Loop over the fields and print well-known content types */
for(int i = 0; i < dsm->data.keyFrameData.fieldCount; i++) {
    const UA_DataType *currentType = dsm->data.keyFrameData.dataSetFields[i].value.type;
    if(currentType == &UA_TYPES[UA_TYPES_BYTE]) {
        UA_Byte value = *(UA_Byte *)dsm->data.keyFrameData.dataSetFields[i].value.data;
        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                    "Message content: [Byte] \tReceived data: %i", value);
    } else if (currentType == &UA_TYPES[UA_TYPES_DATETIME]) {
        UA_DateTime value = *(UA_DateTime *)dsm->data.keyFrameData.dataSetFields[i].value.data;
        UA_DateTimeStruct receivedTime = UA_DateTime_toStruct(value);
        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                    "Message content: [DateTime] \t"
                    "Received date: %02i-%02i-%02i Received time: %02i:%02i:%02i",
                    receivedTime.year, receivedTime.month, receivedTime.day,
                    receivedTime.hour, receivedTime.min, receivedTime.sec);
    } else if(currentType == &UA_TYPES[UA_TYPES_UINT16]) {
        UA_UInt16 receivedTemp =
            *(UA_UInt16 *)dsm->data.keyFrameData.dataSetFields[i].value.data;

        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                    "Message content: [UA_UInt16] \t"
                    "Received temperature: %i",
                    receivedTemp);
    }

Any suggestions? Thank you so much in advance, if you need any further details on this issue, please let me know and I will further edit the question!

EDIT: If you want to have a look to the whole sample code, please have a look at the links below: For the publish application: https://github.com/open62541/open62541/blob/master/examples/pubsub/tutorial_pubsub_publish.c

For the subscribe application: https://github.com/open62541/open62541/blob/master/examples/pubsub/tutorial_pubsub_subscribe.c

user7335295
  • 401
  • 2
  • 7
  • 31
  • perhaps you can link the files you took as base for your code. I found this one already if it's the right one: https://github.com/open62541/open62541/blob/master/examples/pubsub/tutorial_pubsub_subscribe.c – David Apr 03 '19 at 05:35
  • Thank you @David , I edited my question and added two links. One to the publish code and one to the subscribe code. – user7335295 Apr 03 '19 at 06:36
  • can you debug the temperature-values (as part of a collection of all values) above the loop? Are the temperature values there in the data? If so, perhaps some condition in the loop is wrong. – David Apr 03 '19 at 06:48
  • hello @David , I can see that the fieldCount = 2. So the loop repeats 2 times. The first time, the currentType is NULL, so none of the if/if else is getting executed. On the second time, the currentType is Datetime, so the datetime-if is getting executed and the timestamp is parsed. – user7335295 Apr 03 '19 at 07:15
  • I don't know where you get the data and where they are stored, but the pubsub example is for multicast network, so perhaps you better orientate on datasource: https://github.com/open62541/open62541/blob/master/examples/tutorial_server_datasource.c – David Apr 03 '19 at 08:04
  • @David , I currently use a hardcoded value as test temperature value. As you can see in the code snippet, my current temperature value is always 50. dataSetFieldConfig.field.variable.publishParameters.publishedVariable = UA_NODEID_NUMERIC(0, 50); – user7335295 Apr 03 '19 at 08:13
  • I suspect there is a function missing perhaps, or some functionality in another existing function. I can't test it and never work with c / c++. But I propose to insert debugging in the functions step by step / line by line, that you see where your variables are known or missing. – David Apr 03 '19 at 11:26

1 Answers1

0

you need to call addDataSetFieldTemperature before addPubSubConnection
See this for more detail on how to update variable
https://stackoverflow.com/questions/58855146/opcua-open62541-pubsub-how-to-publish-value-change/58882085#58882085

chuong vo
  • 71
  • 6