You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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中注册对应的序列化/反序列化逻辑,才能正确解析数据:

  1. 定义与OPC UA数据类型结构完全匹配的Go结构体
  2. 使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 10:53:17