-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PubSub Publisher example, not setting the DataSetMetaData #2800
Comments
@andreasebner Can you comment on this? |
@cpipero said: `But in truth, a true PubSub publisher should also inform potential susbcribers/clients/configurators of its configuration. That's why we have the PubSub information model and methods.' Let me recall a well-known definition: Publisher-subscriber communication patternPublish-subscribe is a messages distribution scenario where senders of messages, called publishers, do not send them directly to specific receivers, called subscribers, but instead categorize published messages into classes without knowledge of which subscribers if any, there may be. Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers, if any, there are. In the publish-subscribe model, subscribers typically receive only a subset of the total messages published. The process of selecting messages for reception and processing is called filtering. There are two common forms of filtering: topic-based and content-based. Read the full story OPC UA PubSub Main Technology Features I hope you may be also interested to read: Underlying Transport over Ethernet Hope it helps. |
Thank you @jpfr . We are getting closer. I now have to understand if there is anything I should add in my code. Let me explain details (sorry for the lengthy description, but I hope it helps). Adding the FixI added the changes in #2802 . That basically exposes the Here's a screenshot: However, the In this screenshot you see the comparison between the .NET server and the tutorial_pubsub_publish, where the Additional Improvements NeededThis part of the PubSub information model is important because it gives the potential subscribers the needed info to map the DataSetWriter's fields. Look at the .NET Sample Config UI that now can successfully navigate to the remote writer dataset (now it doesn' t crash). But if I want to configure the DataReader, I am missing the necessary metadata: Possible Next StepsI looked at the code in the When the client browses to the PublishedData property (around line 136) the following code maps the data from the published variable to the PublishedData fields. That's why we can see that info correctly in the client: [...]
case UA_NS0ID_PUBLISHEDDATAITEMSTYPE: {
UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, *myNodeId);
if(!publishedDataSet)
return;
switch(nodeContext->elementClassiefier) {
case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA: {
UA_PublishedVariableDataType *pvd = (UA_PublishedVariableDataType *)
UA_calloc(publishedDataSet->fieldSize, sizeof(UA_PublishedVariableDataType));
size_t counter = 0;
UA_DataSetField *field;
LIST_FOREACH(field, &publishedDataSet->fields, listEntry) {
pvd[counter].attributeId = UA_ATTRIBUTEID_VALUE;
pvd[counter].publishedVariable = field->config.field.variable.publishParameters.publishedVariable;
//UA_NodeId_copy(&field->config.field.variable.publishParameters.publishedVariable, &pvd[counter].publishedVariable);
counter++;
}
UA_Variant_setArray(&value, pvd, publishedDataSet->fieldSize,
&UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
break;
}
[...] However, when the client requests the DataSetMeta data (hence switching the //publishedDataSet->dataSetMetaData is EMPTY at this point so nothing will happen
case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_DATASETMETADATA: {
UA_Variant_setScalarCopy(&value, &publishedDataSet->dataSetMetaData, &UA_TYPES[UA_TYPES_DATASETMETADATATYPE]);
break;
} I don't have time now to attempt to fix this, but I figured I write this and later I keep looking at it while someone might be seeing this and get some ideas. Thank you again for the tremendous help. |
Small UpdateUpon more investigation of the following code (copied from above, repeated for convenience) [...]
case UA_NS0ID_PUBLISHEDDATAITEMSTYPE: {
UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, *myNodeId);
if(!publishedDataSet)
return;
switch(nodeContext->elementClassiefier) {
case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA: {
UA_PublishedVariableDataType *pvd = (UA_PublishedVariableDataType *)
UA_calloc(publishedDataSet->fieldSize, sizeof(UA_PublishedVariableDataType));
size_t counter = 0;
UA_DataSetField *field;
LIST_FOREACH(field, &publishedDataSet->fields, listEntry) {
pvd[counter].attributeId = UA_ATTRIBUTEID_VALUE;
pvd[counter].publishedVariable = field->config.field.variable.publishParameters.publishedVariable;
//UA_NodeId_copy(&field->config.field.variable.publishParameters.publishedVariable, &pvd[counter].publishedVariable);
counter++;
}
UA_Variant_setArray(&value, pvd, publishedDataSet->fieldSize,
&UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
break;
}
[...] the This is something that I think the UA_PubSubManager should do... I'm now looking at the |
@jpfr would you have any idea on this? It might make it for a great Interop week if I can fix this. If you look at my last comment, I'm either very close or way off track. Thanks in advance, Cos |
Hey Cos, you are looking at the right code to set the content during reading.
The But the We might have to extend the public API so that the user can fill in more MetaData information. |
@cpipero thanks for your feedback and detailed reports. As you already recognized, the pubsub metadata field is currently not supported. The DataSetMetaData should be created and updated by the pubsub core without any configuration. One short comment to your example code: The OPC UA PubSub Standard defines four methods to add published informations (AddPublishedDataItems 9.1.4.5.2., AddPublishedDataItemsTemplate 9.1.4.5.4., AddPublishedEvents 9.1.4.5.3. and AddPublishedEventsTemplate 9.1.4.5.5). The so called 'Template' methods allow to inject a complete pubsub configuration into the server including the metadata. The non template methods create the metadata (if supported) on the fly. The union 'itemsTemplate' within the UA_PublishedDataSetConfig is used to provide the template functionalty by the open62541 PubSub API. If the 'standard' PublishedDataItems are used you will not need to configure the 'itemTemplate'. We are currently working on a PubSub feature list, which will contain supported/partly supportet and currently not supported aspects of the pubsub standard. I assume the finialization and release of this list next week. I agree with your statement about the importance of the PubSub-metadata for the subscribers. We will work on this feature and try to provide a first implementation as soon as possible. |
Thank you guys, In reality, as you are probably saying, things should start happening when the server adds datafields. But in the meanwhile, I tried to modify the OnRead call in the I'm not successful yet, because I don't have much time left and I'm just shooting in the dark. The following code (very ugly and should NEVER be user) does succeed on the server side, but the client doesn't like it and eventually leads to bad outcomes. But I put it here for you to look at and see if it can be easily "steered" in the right direction. I'm making up the field name (using the tutorial sample I will only have one field all the times). Aagin, this is just for you to see if modifying the OnRead this way makes sense. Clearly it needs to be improved. static void
onRead(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
const UA_NodeId *nodeid, void *context,
const UA_NumericRange *range, const UA_DataValue *data) {
UA_Variant value;
UA_Variant_init(&value);
const UA_NodePropertyContext *nodeContext = (const UA_NodePropertyContext*)context;
const UA_NodeId *myNodeId = &nodeContext->parentNodeId;
switch(nodeContext->parentClassifier){
case UA_NS0ID_PUBSUBCONNECTIONTYPE: {
UA_PubSubConnection *pubSubConnection =
UA_PubSubConnection_findConnectionbyId(server, *myNodeId);
switch(nodeContext->elementClassiefier) {
case UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID:
if(pubSubConnection->config->publisherIdType == UA_PUBSUB_PUBLISHERID_STRING) {
UA_Variant_setScalar(&value, &pubSubConnection->config->publisherId.numeric,
&UA_TYPES[UA_TYPES_STRING]);
} else {
UA_Variant_setScalar(&value, &pubSubConnection->config->publisherId.numeric,
&UA_TYPES[UA_TYPES_UINT32]);
}
break;
default:
UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
"Read error! Unknown property.");
}
break;
}
case UA_NS0ID_WRITERGROUPTYPE: {
UA_WriterGroup *writerGroup = UA_WriterGroup_findWGbyId(server, *myNodeId);
if(!writerGroup)
return;
switch(nodeContext->elementClassiefier){
case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval,
&UA_TYPES[UA_TYPES_DURATION]);
break;
default:
UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
"Read error! Unknown property.");
}
break;
}
case UA_NS0ID_PUBLISHEDDATAITEMSTYPE: {
UA_PublishedDataSet *publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, *myNodeId);
if(!publishedDataSet)
return;
switch(nodeContext->elementClassiefier) {
case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA: {
UA_PublishedVariableDataType *pvd = (UA_PublishedVariableDataType *)
UA_calloc(publishedDataSet->fieldSize, sizeof(UA_PublishedVariableDataType));
size_t counter = 0;
UA_DataSetField *field;
LIST_FOREACH(field, &publishedDataSet->fields, listEntry) {
pvd[counter].attributeId = UA_ATTRIBUTEID_VALUE;
pvd[counter].publishedVariable = field->config.field.variable.publishParameters.publishedVariable;
//UA_NodeId_copy(&field->config.field.variable.publishParameters.publishedVariable, &pvd[counter].publishedVariable);
counter++;
}
UA_Variant_setArray(&value, pvd, publishedDataSet->fieldSize,
&UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
break;
}
//HERE's WHAT I ADDED
case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_DATASETMETADATA: {
UA_DataSetMetaDataType *dsmd = UA_DataSetMetaDataType_new();
UA_DataSetMetaDataType_init(dsmd);
dsmd->configurationVersion = publishedDataSet->dataSetMetaData.configurationVersion;
dsmd->dataSetClassId = publishedDataSet->dataSetMetaData.dataSetClassId;
dsmd->name = publishedDataSet->config.name;
dsmd->fieldsSize++;
dsmd->fields =
(UA_FieldMetaData *) UA_realloc(dsmd->fields, dsmd->fieldsSize * sizeof(UA_FieldMetaData));
for (size_t i = 0; i < dsmd->fieldsSize; ++i) { //TODO:of course, here I should use the List access methods
//against the publishedDataSet.fields LIST
// so I can get all the attributes from those
//but for now I'm just testing something
UA_FieldMetaData_init(&dsmd->fields[i]);
UA_NodeId_copy (&UA_TYPES[UA_TYPES_DATETIME].typeId,
&dsmd->fields[i].dataType);
dsmd->fields[i].builtInType = UA_NS0ID_DATETIME;
dsmd->fields[i].dataSetFieldId = UA_Guid_random(); //TODO: gotta figure this one out
UA_String strTmp = UA_STRING ("DateTime");
UA_String_copy (&strTmp, &dsmd->fields[0].name);
dsmd->fields[i].valueRank = -1; /* scalar */
}
UA_Variant_setScalarCopy(&value, dsmd, &UA_TYPES[UA_TYPES_DATASETMETADATATYPE]);
break;
}
case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_CONFIGURATIONVERSION: {
UA_Variant_setScalarCopy(&value, &publishedDataSet->dataSetMetaData.configurationVersion,
&UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE]);
break;
}
default:
UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
"Read error! Unknown property.");
}
break;
}
default:
UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
"Read error! Unknown parent element.");
}
UA_StatusCode retval = UA_Server_writeValue(server, *nodeid, value);
if (retval != UA_STATUSCODE_GOOD) UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER, "Read error! %s", UA_StatusCode_name(retval));
} Sorry I am doing this in a rush. I will look at it more this weekend with more time. EDITED: improved version after @jpfr hints (still not decoding correctly). |
This is not big enough. |
And then you can just say |
Thanks @jpfr , that was a silly one... I know I'm implementing all this one level above where it should be but it helps understanding. We probably need to add some good documentation on this whole pub-sub. Let me know if I can help |
Just capturing a note from our release meeting. Cross reference Pull Request #3052 that starts fixing this. |
Description
I'm running the
tutorial_pubsub_publish.c
example and everything works fine, as long as I sue the sample code for the subscriber.But in truth, a true PubSub publisher should also inform potential susbcribers/clients/configurators of its configuration. That's why we have the PubSub information model and methods.
Take as an example the .NET reference implementation from the OPC Foundation, and look at the DataSet configuration in its address space.
And look at the same property using the open62541 example:
This prevents those 3rd parties to interact with my publisher.
Testing attempts
I have been poking around the issues and the test code and the best I could some up was to try code the DataSetMetaData using the available facilities, but so far I have no luck. I don't get any error, but the property does not get set.
Here the complete example with the added Metadata code in the
addPublishedDataSet()
function of thetutorial_pubsub_publish.c
example (just cut&paste to replace the sample code):Used CMake options:
Checklist
Please provide the following information:
UA_LOGLEVEL
set as low as necessary) attachedThe text was updated successfully, but these errors were encountered: