使用QOpcUaClient接收OPC UA服务器事件失败求助
问题解决:QOpcUaClient事件订阅失败及indexRange说明
一、事件订阅失败(BadInternalError)的修复方案
1. 移除无效的indexRange设置
你的代码中monitoringParams.setIndexRange("0:20");是错误操作:EventNotifier是单值枚举属性,不支持indexRange参数,该参数仅适用于数组/字符串类型的属性。移除这一行代码可消除部分内部错误。
2. 修正EventFilter的属性操作数
OPC UA的事件过滤器要求明确指定属性所属的事件类型节点(如标准的BaseEventType),否则服务器无法解析属性路径。修改后的过滤器代码如下:
m_eventNode.reset(mOpcUaClient->node("ns=2;s=testObject")); QOpcUaMonitoringParameters monitoringParams(1000); QOpcUaMonitoringParameters::EventFilter filter; // 构造Select Clause:指定BaseEventType下的Message属性 QOpcUaSimpleAttributeOperand messageOperand; messageOperand.setNodeId(QOpcUa::nodeIdFromNumeric(0, QOpcUa::BaseEventType)); // 标准BaseEventType的NodeId messageOperand.setAttributeId(QOpcUa::NodeAttribute::Value); messageOperand.setBrowsePath({QStringLiteral("Message")}); filter << messageOperand; // 构造Where Clause:Severity >=10 QOpcUaContentFilterElement condition; condition << QOpcUaContentFilterElement::FilterOperator::GreaterThanOrEqual; QOpcUaSimpleAttributeOperand severityOperand; severityOperand.setNodeId(QOpcUa::nodeIdFromNumeric(0, QOpcUa::BaseEventType)); severityOperand.setAttributeId(QOpcUa::NodeAttribute::Value); severityOperand.setBrowsePath({QStringLiteral("Severity")}); condition << severityOperand; condition << QOpcUaLiteralOperand(10, QOpcUa::Types::UInt16); filter << condition; monitoringParams.setFilter(filter); // 检查enableMonitoring的返回值,确认订阅是否成功 bool success = m_eventNode->enableMonitoring(QOpcUa::NodeAttribute::EventNotifier, monitoringParams); qDebug() << "订阅事件结果:" << success; QObject::connect(m_eventNode.data(), &QOpcUaNode::eventOccurred, [](const QOpcUaEventData &eventData) { qDebug() << "OPC UA Event occurred"; // 可打印事件详情,比如Message和Severity qDebug() << "事件消息:" << eventData.value(QStringLiteral("Message")).toString(); qDebug() << "事件等级:" << eventData.value(QStringLiteral("Severity")).toUInt(); });
3. 确认节点的EventNotifier权限
用UA Expert检查ns=2;s=testObject节点的EventNotifier属性,确保其值包含SubscribeToEvents(十六进制0x01)。如果该属性值为0,则节点不允许订阅事件,需要修改服务器配置。
二、indexRange参数说明
setIndexRange()用于指定数组、字符串或字节串类型节点属性的读取/订阅范围,格式为start:end(0起始索引):
0:20:表示读取数组第0到第20个元素(包含两端)5::表示读取从第5个元素到末尾的所有元素:3:表示读取从开头到第3个元素的所有元素- 仅当节点属性是数组、字符串或字节串时,该参数才有效;对于单值类型(如EventNotifier、普通数值),设置此参数会引发错误。
内容的提问来源于stack exchange,提问作者AnttiAspi
相关产品推荐
相关产品推荐

