Reputation: 5152
I have a Qt6 console application that runs on Ubuntu 22.04.
The application connects to several OpcUa-enabled PLCs. The goal is to monitor some node values (all of class variable
).
Please note: I try to show you my code, of course I cannot provide a "complete" example since there is no way to simulate the actual remote machine. Of course, feel free to ask any further details that may help.
First my struct to handle the nodes:
typedef struct
{
QOpcUaNode *node; // the actual OpcUa node
QVariant value; // some internal variables,
bool updated; // not important for the question
bool enableRead;
} Node_t;
void MyOpcUa::insertNode(QString key, QString id, bool enableRead)
{
Node_t node; // my internal struct
node.node = _opcUaClient->node(id); // retrieve the actual node
node.value = QVariant();
node.updated = false;
node.enableRead = enableRead;
Q_ASSERT(node.node); // check the node is valid
_mapOpcNodes.insert(key, node);
connect(node.node, &QOpcUaNode::attributeRead, this, &MyOpcUa::handleAttributes);
connect(node.node, &QOpcUaNode::attributeUpdated, this, &MyOpcUa::handleAttributes);
// when it reads the attributes I expect `handleAttributes` is called
}
Here how I connect to the remote machine:
void MyOpcUa::createClient()
{
if (_opcUaClient)
{
delete _opcUaClient;
_opcUaClient = nullptr;
}
Q_ASSERT(_opcUaClient == nullptr);
if (_opcUaClient == nullptr)
{
_opcUaClient = _opcUaProvider->createClient(OPC_UA_BACKEND);
if (!_opcUaClient)
{
qInfo() << ID << _name << "Connection to server failed:" << _opcUaClient->error();
return;
}
connect(_opcUaClient, &QOpcUaClient::connectError, this, &MyOpcUa::connectError);
_opcUaClient->setApplicationIdentity(_identity);
_opcUaClient->setPkiConfiguration(*_pkiConfig);
if (_opcUaClient->supportedUserTokenTypes().contains(QOpcUaUserTokenPolicy::TokenType::Certificate))
{
QOpcUaAuthenticationInformation authInfo;
authInfo.setCertificateAuthentication();
_opcUaClient->setAuthenticationInformation(authInfo);
}
connect(_opcUaClient, &QOpcUaClient::connected, this, &MyOpcUa::clientConnected);
connect(_opcUaClient, &QOpcUaClient::disconnected, this, &MyOpcUa::clientDisconnected);
connect(_opcUaClient, &QOpcUaClient::errorChanged, this, &MyOpcUa::clientError);
connect(_opcUaClient, &QOpcUaClient::stateChanged, this, &MyOpcUa::clientState);
connect(_opcUaClient, &QOpcUaClient::endpointsRequestFinished, this, &MyOpcUa::getEndpointsComplete);
connect(_opcUaClient, &QOpcUaClient::findServersFinished, this, &MyOpcUa::findServersComplete);
}
}
Then, after the connection, I enable the monitoring of the list of nodes:
void MyOpcUa::enableMonitoring()
{
QMapIterator<QString, Node_t> i(_mapOpcNodes);
while (i.hasNext())
{
i.next();
Node_t node = i.value();
if (node.enableRead)
{
qDebug() << node.node->enableMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters(1000));
}
}
}
I checked the returned value of enableMonitoring
calls and all are true
.
The problem is only one node is actually read periodically. I know this since this is the handler:
void MyOpcUa::handleAttributes()
{
QOpcUaNode *node = qobject_cast<QOpcUaNode*>(sender());
QString key = retrieveNode(node->nodeId());
if (key.isEmpty())
{
qWarning() << ID << "Key not found" << key;
}
QVariant value = node->attribute(QOpcUa::NodeAttribute::Value);
qDebug() << key; // print which node has been read
if (_mapOpcNodes.contains(key))
{
_mapOpcNodes[key].updated = true;
_mapOpcNodes[key].value = value;
emit valueChanged(key, value);
}
}
and only one key
is printed. Of course, if I manually trigger a read I can read them all.
Using an OpcUa viewer I inspected some of the desired nodes:
and I didn't find any difference among them. By the way, the only node I can successfully monitoring is udiActualOrderLengthRT
.
I searched for other questions and I found this one. But, honestly I'm not sure if the answer is applicable to my framework as well.
I also read the QOpcUaNode::enableMonitoring and QOpcUaMonitoringParameters documentation and if I understand correctly I can live with the default SubscriptionType::Shared
mode since I want all the data to be read with the same interval.
Is there any evidence of error in my code or in my approach? What can cause such a behavior?
I also checked the enableMonitoringFinished
signal:
void MyOpcUa::enableMonitoringFinished(QOpcUa::NodeAttribute attr, QOpcUa::UaStatusCode statusCode)
{
qDebug() << attr << statusCode;
}
and it is a success:
QOpcUa::NodeAttribute::Value QOpcUa::Good
Upvotes: 0
Views: 194
Reputation: 1134
OPC UA Subscriptions are only update, after the initail value, if the value has changed. Otherwise there would be no advantage of polling the variables.
Upvotes: 1