目录
2.opc客户端程序:uaexpert 提取码:0kpmuaexpert 提取码:
3.使用KEPServerv6进行OPC_UA的服务器搭建:服务器搭建
4. 使用KEPServerv6添加仿真:此链接第五步或者此链接前两步
前言:
本文章介绍如何使用Qt搭建客户端并并和服务端完成简单的读写操作
一:测试软件安装与使用
1.opc服务端程序:kepserverex
2.opc客户端程序:uaexpert 提取码:0kpm
3.使用KEPServerv6进行OPC_UA的服务器搭建:服务器搭建
4. 使用KEPServerv6添加仿真:此链接第五步或者此链接前两步
5.通过uaexpert访问kepservere
(1)先给KEPServerv6添加仿真
(2)让uaexpert访问kepservere
点击OK即可连接成功,然后按下面步骤找到对应节点的信息
双击s1得到下面方框中的信息,这里面包含节点的信息,其中NodeId用于后面Qt访问
二:Qt搭建客户端
1.打开Qt,并在.pro文件和.h文件中分别加入:
QT += opcua
#include <QOpcUaClient>
#include <QOpcUaNode>
#include <QtOpcUa>
#include <QDebug>
2.在.ui文件里面加入三个按钮,并如下命名
三个按钮的槽函数分别如下:
void MainWindow::on_btn_requestEndpoints_clicked()
{
client->requestEndpoints(QUrl("opc.tcp://127.0.0.1:49320"));
}
void MainWindow::on_btn_readnode_clicked()
{
node->readAttributes(QOpcUa::NodeAttribute::Value);
qDebug()<<"readnode"<<node->nodeId();
}
void MainWindow::on_btn_writeAttribute_clicked()
{
QOpcUa::NodeAttribute attribute ;
attribute = QOpcUa::NodeAttribute::Value;
QVariant var=12;
//node->writeAttribute(attribute,QString("ssss"),QOpcUa::Types::String);
node->writeAttribute(attribute,var);
}
3.创建QOpcUaClient对象,官方例子如下
QOpcUaProvider provider;
if (provider.availableBackends().isEmpty())
return;
QOpcUaClient *client = provider.createClient(provider.availableBackends()[0]);
if (!client)
return;
// Connect to the stateChanged signal. Compatible slots of QObjects can be used instead of a lambda.
QObject::connect(client, &QOpcUaClient::stateChanged, [client](QOpcUaClient::ClientState state) {
qDebug() << "Client state changed:" << state;
if (state == QOpcUaClient::ClientState::Connected) {
QOpcUaNode *node = client->node("ns=0;i=84");
if (node)
qDebug() << "A node object has been created";
}
});
QObject::connect(client, &QOpcUaClient::endpointsRequestFinished,
[client](QList<QOpcUaEndpointDescription> endpoints) {
qDebug() << "Endpoints returned:" << endpoints.count();
if (endpoints.size())
client->connectToEndpoint(endpoints.first()); // Connect to the first endpoint in the list
});
client->requestEndpoints(QUrl("opc.tcp://127.0.0.1:4840")); // Request a list of endpoints from the server
创建 QOpcUaClient 使用 QOpcUaProvider , request a list of endpoints from the server using requestEndpoints 和调用 connectToEndpoint () to connect to one of the available endpoints. After the connection is established, a QOpcUaNode object for the root node is requested.
接下来按官方例子创建QOpcUaClient对象,并连接到服务器
(1)在.h文件中输入下面代码
public slots:
void on_btn_requestEndpoints_clicked();
void on_btn_readnode_clicked();
void on_btn_writeAttribute_clicked();
void SLOT_endpointsRequestFinished (QVector<QOpcUa::QEndpointDescription> endpoints , QOpcUa::UaStatusCode statusCode);
void SLOT_attributeRead ( QOpcUa::NodeAttributes attributes );
void SLOT_stateChanged (QOpcUaClient::ClientState state );
private:
Ui::MainWindow *ui;
QOpcUaClient *client;
QOpcUaProvider* provider;
QOpcUaNode* node;
(2)创建QOpcUaClient对象,并像例子中一样连接槽
provider = new QOpcUaProvider(this);
client = provider->createClient(QString("open62541"));
connect(client,&QOpcUaClient::endpointsRequestFinished,this,&MainWindow::SLOT_endpointsRequestFinished);
connect(client,&QOpcUaClient::stateChanged,this,&MainWindow::SLOT_stateChanged);
(3)按下按钮requestEndpoints,如果请求成功会跳到槽函数SLOT_endpointsRequestFinished
void MainWindow::SLOT_endpointsRequestFinished(QVector<QOpcUa::QEndpointDescription> endpoints, QOpcUa::UaStatusCode statusCode)
{
qDebug()<<endpoints.at(0).endpointUrl();
qDebug()<<statusCode;
qDebug() << "Endpoints returned:" << endpoints.count();
qDebug()<<endpoints.size();
if (endpoints.size())
client->connectToEndpoint(endpoints.at(0).endpointUrl()); // Connect to the first endpoint in the list
}
(4)跳到该槽函数后,会让创建的客户端对象连接到服务器,如果连接成功,会跳到槽函数SLOT_stateChanged
void MainWindow::SLOT_stateChanged(QOpcUaClient::ClientState state)
{
qDebug() << "Client state changed:" << state;
if (state == QOpcUaClient::ClientState::Connected) {
//QOpcUaNode定义
node = client->node("ns=2;s=my.plc.s1");
if (node)
qDebug() << "A node object has been created";
}
connect(node,&QOpcUaNode::attributeRead,this,&MainWindow::SLOT_attributeRead);
}
当创建的客户端对象连接到服务端之后,会进入到这个槽函数中,在这里面定义一个节点,其中节点的名字为在uaexpert中得到的nodeid,然后连接槽,如果读到节点属性后,就转到槽,官方创建节点例子如下
QOpcUaNode *rootNode; // Created before, see QOpcUaClient documentation.
// Connect to the attributeRead signal. Compatible slots of QObjects can be used instead of a lambda.
QObject::connect(rootNode, &QOpcUaNode::attributeRead, [rootNode, client](QOpcUa::NodeAttributes attr) {
qDebug() << "Signal for attributes:" << attr;
if (rootNode->attributeError(QOpcUa::NodeAttribute::BrowseName) != QOpcUa::UaStatusCode::Good) {
qDebug() << "Failed to read attribute:" << rootNode->attributeError(QOpcUa::NodeAttribute::BrowseName);
client->disconnectFromEndpoint();
}
qDebug() << "Browse name:" << rootNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>().name();
});
rootNode->readAttributes(QOpcUa::NodeAttribute::BrowseName); // Start a read operation for the node's BrowseName attribute.
这里面定义的节点没有赋值,我在操作的时候提示错误,所以我上面提前定义的时候就赋值了
(5)按下按钮readnode,转到槽SLOT_attributeRead,开始读节点内容
void MainWindow::SLOT_attributeRead(QOpcUa::NodeAttributes attributes)
{
qDebug() << "Signal for attributes:" << attributes;
qDebug()<<"value:"<<node->attribute(QOpcUa::NodeAttribute::Value);
}
节点的属性很多,在按钮readnode中,读的是Value,因此这里输出的就是Value,如果读的是其他值,这里可以得到其他值。(初值可以在KEPServerv6的客户端中更改)
(6)按下按钮writeAttribute,就可以对节点写入所定义的属性,这里属性可以参考:属性
总结:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
provider = new QOpcUaProvider(this);
//if (provider.availableBackends().isEmpty())
client = provider->createClient(QString("open62541"));
connect(client,&QOpcUaClient::endpointsRequestFinished,this,&MainWindow::SLOT_endpointsRequestFinished);
connect(client,&QOpcUaClient::stateChanged,this,&MainWindow::SLOT_stateChanged);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_btn_requestEndpoints_clicked()
{
client->requestEndpoints(QUrl("opc.tcp://127.0.0.1:49320"));
}
void MainWindow::on_btn_readnode_clicked()
{
node->readAttributes(QOpcUa::NodeAttribute::Value);
qDebug()<<"readnode"<<node->nodeId();
}
void MainWindow::on_btn_writeAttribute_clicked()
{
QOpcUa::NodeAttribute attribute ;
attribute = QOpcUa::NodeAttribute::Value;
QVariant var=12;
//node->writeAttribute(attribute,QString("ssss"),QOpcUa::Types::String);
node->writeAttribute(attribute,var);
}
void MainWindow::SLOT_endpointsRequestFinished(QVector<QOpcUa::QEndpointDescription> endpoints, QOpcUa::UaStatusCode statusCode)
{
qDebug()<<endpoints.at(0).endpointUrl();
//qDebug() <<endpoints.first().endpointUrl();
qDebug()<<statusCode;
qDebug() << "Endpoints returned:" << endpoints.count();
qDebug()<<endpoints.size();
if (endpoints.size())
client->connectToEndpoint(endpoints.at(0).endpointUrl()); // Connect to the first endpoint in the list
}
void MainWindow::SLOT_attributeRead(QOpcUa::NodeAttributes attributes)
{
qDebug() << "Signal for attributes:" << attributes;
// if (node->attributeError(QOpcUa::NodeAttribute::BrowseName) != QOpcUa::UaStatusCode::Good) {
// qDebug() << "Failed to read attribute:" << node->attributeError(QOpcUa::NodeAttribute::BrowseName);
// client->disconnectFromEndpoint();
// }
//qDebug() << "Browse name:" << node->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUa::QQualifiedName>().name();
qDebug()<<"value:"<<node->attribute(QOpcUa::NodeAttribute::Value);
}
void MainWindow::SLOT_stateChanged(QOpcUaClient::ClientState state)
{
qDebug() << "Client state changed:" << state;
if (state == QOpcUaClient::ClientState::Connected) {
//QOpcUaNode定义
node = client->node("ns=2;s=my.plc.s1");
if (node)
qDebug() << "A node object has been created";
}
connect(node,&QOpcUaNode::attributeRead,this,&MainWindow::SLOT_attributeRead);
}