Qt使用QOpcUa类_qtopcua-程序员宅基地

技术标签: qt  Qt+OpcUa  

目录

前言:

一:测试软件安装与使用

1.opc服务端程序:kepserverex 

2.opc客户端程序:uaexpert   提取码:0kpmuaexpert   提取码:

3.使用KEPServerv6进行OPC_UA的服务器搭建:服务器搭建

4. 使用KEPServerv6添加仿真:此链接第五步或者此链接前两步

5.通过uaexpert访问kepservere

二:Qt搭建客户端

总结:


前言:

        本文章介绍如何使用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);

}



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xiaominggege_/article/details/123759129

智能推荐

相机成像原理以及旋转_摄像机平移旋转的原理-程序员宅基地

摘要:相机成像原理涉及点在不同坐标系中的矩阵变换,包括世界、相机、像平面和像素平面坐标系。具体变换关系可用矩阵表达,可求得单位向量。

Android 13中的 Open Mobile API_sim trasmit apdu-程序员宅基地

文章浏览阅读4.4k次,点赞4次,收藏12次。SE 也就是 Secure Element,译为 “安全元素”主要应用场景在 手机手表交通卡、门禁、虚拟钱包、虚拟SIM卡,以及其他身份认证的且对安全级别有一定要求的业务。_sim trasmit apdu

【Flutter混编】InAppWebView常见配置&相册问题处理-程序员宅基地

文章浏览阅读5.1k次。Flutter自带WebView不想说啥了,就这样吧。反正一番周折之后选择使用第三方的InAppWebView。看源码可以看出本质上是用了Platform调回原生平台的webview,但是xing nen_inappwebview

springboot ControllerAdvice 类似上传超出文件大小异常无法捕获问题详解及解决方式_handlemaxuploadsizeexceededexception-程序员宅基地

文章浏览阅读6.7k次,点赞2次,收藏10次。spring boot/mvc通过@RestControllerAdvice或者@ControllerAdvice配合@ExceptionHandler实现全局异常统一处理在spring web项目开发中,我们经常会遇到各种exception,这些exception根据业务或者场景不同抛出不同的信息和返回类型,有的exception需要返回json数据格式的错误,有的exceptio..._handlemaxuploadsizeexceededexception

推荐开源项目:iOS-General-Tools - iOS 开发者的全能工具箱-程序员宅基地

文章浏览阅读365次,点赞3次,收藏5次。推荐开源项目:iOS-General-Tools - iOS 开发者的全能工具箱项目地址:https://gitcode.com/YouXianMing/iOS-General-ToolsiOS-General-Tools 是一个强大的、开源的 iOS 开发工具集合,由开发者 YouXianMing 维护。它旨在简化 iOS 应用开发过程中的各种任务,提高效率,并提供了一站式的解决方案。下面我...

获取access_token_获取accesstoken json-程序员宅基地

文章浏览阅读220次。access_token用户执行微信公众号操作的凭证将appid和APPSECRET拼接到指定的url发送给微信服务器private static final String URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRE..._获取accesstoken json

随便推点

Scrapy实战:爬取知乎用户信息_运用分布式框架抓取知乎网站用户的信息,包括用户的姓名(昵称)、一句话介绍、部分-程序员宅基地

文章浏览阅读1.5k次,点赞2次,收藏8次。思路:从一个用户(本例为“张佳玮”)出发,来爬取其粉丝,进而爬取其粉丝的粉丝…先来观察网页结构:审查元素:可以看到用户“关注的人”等信息在网页中用json格式保存在data中。当把鼠标移到列表中的某个名字上时,可以看到浏览器产生了一个Ajax请求:请求的url后面加上了很长的一串查询字符串。并且json中也请求了许多详细的信息。这与该用户的主页基本是对应的:实战我们..._运用分布式框架抓取知乎网站用户的信息,包括用户的姓名(昵称)、一句话介绍、部分

23种设计模式——装饰者模式-程序员宅基地

文章浏览阅读3.9k次,点赞8次,收藏35次。文章目录23种设计模式——装饰者模式1、装饰者模式概述2、装饰者模式的结构3、装饰者模式的实现4、装饰者模式的应用场景23种设计模式——装饰者模式1、装饰者模式概述背景有些人为了早上多睡一会,就会用方便的方式解决早餐问题。有些人早餐可能会吃煎饼,煎饼中可以加鸡蛋,也可以加香肠,但是不管怎么“加码”,都还是一个煎饼。在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框、咖啡加调料等,都是装饰器模式。装饰者模式的定义装饰者(Decorator)模式的定义:指在不改_装饰者模式

html css的参考文献,网页制作论文参考文献大全 网页制作参考文献有哪些-程序员宅基地

文章浏览阅读6.2k次。【100个】关于网页制作论文参考文献大全汇总,作为大学生的毕业生应该明白了网页制作参考文献有哪些,收集好参考文献后的网页制作论文写作起来会更轻松!一、网页制作论文参考文献范文[1]开展电脑社团活动培养学生信息素养——中学生网页制作社团活动报告.童宇阳,2009第九届中国教育信息化创新与发展论坛[2]项目教学法在《网页制作基础》课程中的应用.胡永刚,20072007无锡职教教师论坛[3]基于SVG的..._计算机网页制作相关参考文献

生信学习过程中遇到的问题_couldn't build a bowtie2.index from hg38.fa-程序员宅基地

文章浏览阅读1.7k次。前言:记录在自学生信过程中所遇到的一些问题,如何去解决的。希望我的经验可以对他人有帮助。 注意:不要复制代码,因软件版本更新等问题,命令会变化的。重点学习怎么去解决问题。 一:执行zcat cz2_1.fq.gz,屏幕出现了群魔乱舞,想要恢复到正常的命令行模式下。 1、直接终止正在运行的程序,使用ctrl+c。 2、让程序进入后台运行,使用ctrl+z,进..._couldn't build a bowtie2.index from hg38.fa

【转】Angularjs Controller 间通信机制-程序员宅基地

文章浏览阅读84次。在Angularjs开发一些经验总结随笔中提到我们需要按照业务却分angular controller,避免过大无所不能的上帝controller,我们把controller分离开了,但是有时候我们需要在controller中通信,一般为比较简单的通信机制,告诉同伴controller我的某个你所关心的东西改变了,怎么办?如果你是一个javascript程序员你会很自然的想到异步回调响应...

5.C++内存池、内存分配_c++ 申请内存池用于接管内存分配-程序员宅基地

文章浏览阅读9.5k次。C++重要语言基础1.语言基础1.1空间的配置与释放--std:alloc(SGI实现)1.2内存池1.语言基础1.1空间的配置与释放–std:alloc(SGI实现)SGI标准模版库:设计时需要考虑的问题:从堆区申请内存空间;考虑多线程;考虑内存不足时的应对措施;考虑大量小区块可能造成的内存碎片问题;SGI的alloc类是使用了双层配置器:分别处理大内存请求和小内存请..._c++ 申请内存池用于接管内存分配

推荐文章

热门文章

相关标签