OPC UA服务器连接断开后二次迭代取值报BadAttributeIdInvalid错误求助
OPC UA二次循环获取节点值报错BadAttributeIdInvalid的排查与解决
可能的原因
- 首次循环后节点对象失效:连接断开或重新初始化后,之前获取的Node对象已无法复用,二次请求时触发属性不支持错误。
- 属性ID传递错误:部分客户端库在循环中可能默认请求了节点不支持的属性,而非
Value属性。 - 连接状态管理混乱:循环中未正确维护连接状态,断开后未重新建立连接或重新获取节点。
解决方案
1. 每次循环重新获取节点对象
不要复用首次循环的Node实例,每次轮询前重新通过节点路径获取节点:
from opcua import Client import time # 配置PLC端点和节点路径 plc_endpoints = ["opc.tcp://phoenix_plc:4840", "opc.tcp://bachmann_plc:4840"] target_node_paths = ["ns=2;s=DataPoint1", "ns=2;s=DataPoint2"] while True: for endpoint in plc_endpoints: try: # 每次循环重新创建客户端并连接 client = Client(endpoint) client.connect() # 重新获取节点 target_nodes = [client.get_node(path) for path in target_node_paths] # 获取节点值 node_values = client.get_values(target_nodes) print(f"{endpoint} 数据: {node_values}") client.disconnect() except Exception as e: print(f"{endpoint} 操作失败: {str(e)}") time.sleep(10)
2. 显式指定请求Value属性
如果客户端库默认请求的属性不是Value,显式指定属性ID:
from opcua.ua import AttributeIds # 获取值时明确指定属性为Value node_values = client.get_values(target_nodes, attribute_id=AttributeIds.Value)
3. 维护持久连接(避免频繁重连)
如果频繁重连引发问题,可保持连接长期打开,循环内仅执行数据获取:
from opcua import Client import time plc_endpoints = ["opc.tcp://phoenix_plc:4840", "opc.tcp://bachmann_plc:4840"] target_node_paths = ["ns=2;s=DataPoint1", "ns=2;s=DataPoint2"] active_clients = [] # 初始化所有连接 for endpoint in plc_endpoints: try: client = Client(endpoint) client.connect() active_clients.append((client, endpoint)) print(f"已连接 {endpoint}") except Exception as e: print(f"初始化 {endpoint} 失败: {str(e)}") try: while True: for client, endpoint in active_clients: try: # 检查连接状态,断开则重连 if not client.is_connected(): client.reconnect() print(f"重新连接 {endpoint}") # 重新获取节点(避免节点对象失效) target_nodes = [client.get_node(path) for path in target_node_paths] node_values = client.get_values(target_nodes) print(f"{endpoint} 数据: {node_values}") except Exception as e: print(f"{endpoint} 获取数据失败: {str(e)}") time.sleep(10) finally: # 程序退出时统一断开所有连接 for client, _ in active_clients: if client.is_connected(): client.disconnect() print("已断开连接")
4. 提前验证节点属性支持性
首次获取节点时,检查是否支持Value属性,排除节点本身问题:
from opcua.ua import AttributeIds node = client.get_node(target_node_paths[0]) # 请求Value属性 attr_result = node.get_attributes([AttributeIds.Value])[0] if attr_result.StatusCode.is_good(): print("节点支持Value属性") else: print(f"节点不支持Value属性: {attr_result.StatusCode}")
内容的提问来源于stack exchange,提问作者amanie11
相关产品推荐
相关产品推荐

