使用gopcua读取OPC UA未知扩展对象遇StatusBadDataTypeIdUnknown错误求助
解决OPC UA读取未知数据类型的问题
一、OPC UA协议的数据类型发现方式
OPC UA本身支持通过节点浏览获取服务器上的所有数据类型:
- 直接浏览服务器的DataType根节点(标准NodeId为
i=22),通过HasSubtype引用遍历所有子节点,就能拿到服务器包含的标准和自定义数据类型的NodeId、名称等信息。 - 对于自定义数据类型,还可以读取其
DataTypeDefinition属性,获取具体的结构字段、字段类型等完整定义。用gopcua实现的示例代码如下:
// 浏览DataType根节点下的所有数据类型 browseResp, err := client.Browse(ctx, &ua.BrowseRequest{ NodesToBrowse: []*ua.BrowseDescription{{ NodeID: ua.NewNumericNodeID(0, 22), // DataType根节点的NodeId BrowseDirection: ua.BrowseDirectionForward, ReferenceTypeId: ua.NewNumericNodeID(0, 45), // HasSubtype引用类型的NodeId IncludeSubtypes: true, NodeClassMask: ua.NodeClassDataType, }}, }) if err != nil { // 处理浏览错误 } // 遍历返回的节点,提取数据类型信息 for _, res := range browseResp.Results { for _, ref := range res.References { fmt.Printf("数据类型NodeId: %s, 名称: %s\n", ref.NodeID, ref.DisplayName.Text) } }
二、在gopcua中注册自定义数据类型
拿到数据类型的结构定义后,需要在gopcua中注册对应的序列化/反序列化逻辑,才能正确解析数据:
- 定义与OPC UA数据类型结构完全匹配的Go结构体
- 使用
ua.RegisterExtensionObjectType方法,将该数据类型的NodeId和结构体的创建函数绑定。示例如下:
// 假设WinCC Binary Tag对应的自定义数据类型NodeId是ns=2;i=1001 type WinCCBinaryTag struct { // 根据DataTypeDefinition定义的字段,比如原始二进制数据 RawData []byte `ua:"RawData"` } // 在初始化时注册类型 func init() { ua.RegisterExtensionObjectType(ua.NewNumericNodeID(2, 1001), func() interface{} { return &WinCCBinaryTag{} }) }
完成注册后,再执行原本的Read请求,gopcua就能自动反序列化该类型的数据。
三、读取未知扩展对象的临时方案
如果暂时无法获取数据类型的完整定义,可以直接读取原始二进制数据:
- 读取返回结果中的
ExtensionObject,直接提取其Body字段(原始二进制字节数组),后续可以自行解析或保存分析。示例代码:
resp, err := o.client.Read(ctx, &ua.ReadRequest{ MaxAge: 2000, NodesToRead: []*ua.ReadValueID{{NodeID: nodeID}}, TimestampsToReturn: ua.TimestampsToReturnBoth, }) if err != nil { return domain.NodeValue{}, err } for _, result := range resp.Results { if result.StatusCode != ua.StatusOK { // 处理状态错误 continue } // 尝试转为ExtensionObject if extObj, ok := result.Value.Value.(*ua.ExtensionObject); ok { // 获取原始二进制数据 rawBytes := extObj.Body // 这里可以对rawBytes进行自定义解析,或者保存到文件 } }
WinCC Binary Tag的额外提示
WinCC的Binary Tag属于自定义扩展对象,你可以通过WinCC的OPC UA配置界面直接查看该标签对应的数据类型NodeId;另外部分WinCC项目会导出XML格式的数据类型定义文件,用它可以快速生成对应的Go结构体。
内容的提问来源于stack exchange,提问作者Hassan Raza Warraich
相关产品推荐
相关产品推荐

