QtOpcUa subscriptions timeout only when using multiple connections

51 Views Asked by At

Here I learnt that the subscription parameters (MaxKeepAliveCount and LifetimeCount mainly) should be selected keeping in mind the ratio of change of the monitored variables.

In my scenario I have 4 nodes to monitor. One of them changes quite fast (< 1 s), the others change very rarely (> 1 hour). I have 20+ PLCs all the same.

My code is heavily based on the QtOpcUaViewer example. Here the code I use to enable a subscription:

void MyOpcUa::enableMonitoring()
{
    QMapIterator<QString, Node_t> i(_mapOpcNodes);
    while (i.hasNext())
    {
        i.next();
        Node_t node = i.value();
        if (node.enableRead)
        {
            QOpcUaMonitoringParameters params(POLLING_INTERVAL); // tested between 100 and 10000 ms
            //params.setMaxKeepAliveCount(1000); // tested between 100 and 100000
            //params.setLifetimeCount(3000); // MaxKeepAliveCount * 3
            //params.setPriority(0);
            bool ret = node.node->enableMonitoring(QOpcUa::NodeAttribute::Value, params);
        }
    }
}

I wrapped the whole logic inside a class (MyOpcUa):

#include <QObject>
#include <QOpcUaProvider>
#include <QOpcUaClient>
#include <QOpcUaNode>

class MyOpcUa : public QObject
{
    Q_OBJECT

public:
    typedef struct
    {
        QOpcUaNode *node;
        QVariant value;
        bool updated;
        bool enableRead;
    } Node_t;

    explicit MyOpcUa(QObject *parent = nullptr);
    ~MyOpcUa();

    void setConfiguration(QOpcUaPkiConfiguration *pkiConfig);
    void discoverHost(QUrl url);
    bool discoverComplete() { return _endpointList.size(); }
    bool isConnected() { return _clientConnected; }
    bool isError() { return _clientError; }
    void reconnect() { connectToServer(0); }
    void clearNodes();
    void insertNode(QString key, QString id, bool enableRead);
    bool writeNodeValue(QString key, QVariant value, QOpcUa::Types type);
    void enableMonitoring();
    void disableMonitoring();

private:
    QOpcUaProvider *_opcUaProvider;
    QOpcUaClient *_opcUaClient = nullptr;
    QList<QOpcUaEndpointDescription> _endpointList;
    QOpcUaApplicationIdentity _identity;
    QOpcUaPkiConfiguration *_pkiConfig;
    QOpcUaEndpointDescription _endpoint;

    QMap<QString, Node_t> _mapOpcNodes;

    void createClient();

private slots:
    void connectToServer(int idxEndpoint);
    void findServersComplete(const QList<QOpcUaApplicationDescription> &servers, QOpcUa::UaStatusCode statusCode);
    void getEndpoints(QString server);
    void getEndpointsComplete(const QList<QOpcUaEndpointDescription> &endpoints, QOpcUa::UaStatusCode statusCode);
    void clientConnected();
    void clientDisconnected();
    void namespacesArrayUpdated(const QStringList &namespaceArray);
    void clientError(QOpcUaClient::ClientError);
    void clientState(QOpcUaClient::ClientState);
    void connectError(QOpcUaErrorState *errorState);
    void handleAttributes();
};

so I can create an instance for each connection. The behavior I experience seems really odd to me:

  • if I have only one connection I can subscribe to my nodes with the default parameters and all works as expected. I get the notifications and every now and then the channel is renewed

  • if I have more than one connection, no matter the subscription parameters every few minutes I get these errors:

    [20231003 10:37:23 I] unknown:0 - "The ServiceResult has the StatusCode BadTimeout"
    [20231003 10:37:23 W] unknown:0 - "Received Timeout for Publish Response"
    [20231003 10:37:23 I] unknown:0 - "The ServiceResult has the StatusCode BadNoSubscription"
    [20231003 10:37:38 I] unknown:0 - "Client Status: ChannelState: Closed, SessionState: Closed, ConnectStatus: Good"

and the connections are closed. This happens to all the connections but not at the same time. I connect to all the PLCs on startup (almost at the same time) but the errors above happens randomly among all the machines.

  • if I have more than one connection, but with no subscriptions the connections are kept open and the secure channels are renewed.

  • I also tried to subscribe to only one node: no matter if it changes every second or every hour the behavior is exactly the same, regardless the QOpcUaMonitoringParameters

I'm having a hard time to understand what's happening here. Do you see any flaw in my approach?

0

There are 0 best solutions below