使用 OPC UA 檢測和轉換自定義方法輸入參數

使用 OPC UA 檢測和轉換自定義方法輸入參數

本文將深入探討如何在使用 OPC UA 客戶端(例如 asyncua)調用自定義方法時,解決動態檢測和轉換輸入參數數據類型的問題。核心在于理解如何利用 OPC UA 協議提供的元數據信息,動態地獲取方法參數的類型,并將其轉換為客戶端可用的 python 類,從而實現靈活且類型安全的方法調用。

在 OPC UA 中,方法節點的 “0:InputArguments” 屬性包含了方法參數的詳細信息,包括參數名稱、數據類型等。通過讀取這個屬性的值,我們可以獲得一個 Argument 對象的列表,每個對象描述一個輸入參數。

以下代碼展示了如何從 Argument 對象中提取數據類型,并將其轉換為相應的 Python 類:

from asyncua.ua import ObjectIds from asyncua import ua  base_type_list = {     ua.NodeId(ObjectIds.Null): None,     ua.NodeId(ObjectIds.Boolean): bool,     ua.NodeId(ObjectIds.SByte): ua.SByte,     ua.NodeId(ObjectIds.Byte): ua.Byte,     ua.NodeId(ObjectIds.Int16): ua.Int16,     ua.NodeId(ObjectIds.UInt16): ua.UInt16,     ua.NodeId(ObjectIds.Int32): ua.Int32,     ua.NodeId(ObjectIds.UInt32): ua.UInt32,     ua.NodeId(ObjectIds.Int64): ua.Int64,     ua.NodeId(ObjectIds.UInt64): ua.UInt64,     ua.NodeId(ObjectIds.Float): ua.Float,     ua.NodeId(ObjectIds.Double): ua.Double,     ua.NodeId(ObjectIds.String): ua.String,     ua.NodeId(ObjectIds.DateTime): ua.DateTime,     ua.NodeId(ObjectIds.Guid): ua.Guid,     ua.NodeId(ObjectIds.ByteString): ua.ByteString,     ua.NodeId(ObjectIds.XmlElement): ua.XmlElement,     ua.NodeId(ObjectIds.NodeId): ua.NodeId,     ua.NodeId(ObjectIds.ExpandedNodeId): ua.ExpandedNodeId,     ua.NodeId(ObjectIds.StatusCode): ua.StatusCode,     ua.NodeId(ObjectIds.QualifiedName): ua.QualifiedName,     ua.NodeId(ObjectIds.LocalizedText): ua.LocalizedText,     ua.NodeId(ObjectIds.Structure): ua.ExtensionObject,     ua.NodeId(ObjectIds.DataValue): ua.DataValue,     ua.NodeId(ObjectIds.BaseVariableType): ua.Variant,     ua.NodeId(ObjectIds.DiagnosticInfo): ua.DiagnosticInfo, }  def get_class_from_nodeid(datatype_nodeid):    """    從 NodeId 獲取對應的 Python 類。     Args:        datatype_nodeid (ua.NodeId): 數據類型的 NodeId。     Returns:        type: 對應的 Python 類,如果找不到則返回 None。    """    # 檢查所有類型字典    sources = [base_type_list, ua.basetype_by_datatype, ua.extension_objects_by_datatype, ua.enums_by_datatype]    cls = None    for src in sources:        cls = src.get(datatype_nodeid, None)        if cls is not None:           return cls    return cls

使用方法:

  1. 讀取 “0:InputArguments” 屬性: 使用 read_value() 方法讀取目標方法的 “0:InputArguments” 屬性。這將返回一個 Argument 對象的列表。
  2. 提取數據類型 NodeId: 遍歷 Argument 列表,對于每個參數,提取其 dataType 屬性,該屬性是一個 NodeId 對象,表示參數的數據類型。
  3. 轉換為 Python 類: 使用 get_class_from_nodeid() 函數將 NodeId 轉換為對應的 Python 類。
  4. 創建參數實例: 使用轉換后的 Python 類,根據實際的參數值創建參數實例。
  5. 調用方法: 將創建的參數實例作為參數傳遞給 node.call_method() 方法。

示例:

假設我們有一個名為 MyMethod 的方法,它接受一個自定義數據類型 MyDataType 和一個整數作為輸入參數。

# 假設已經連接到 OPC UA 服務器并獲取了 MyMethod 節點的句柄 method_node  # 讀取 "0:InputArguments" 屬性 input_arguments = await method_node.read_value()  # 遍歷參數 args = [] for arg in input_arguments:     data_type_nodeid = arg.dataType     cls = get_class_from_nodeid(data_type_nodeid)      if cls is not None:         # 假設第一個參數是 MyDataType,第二個參數是整數         if arg == input_arguments[0]:             # 創建 MyDataType 實例 (假設 MyDataType 有 ID, Value1, Value2 屬性)             param_value = cls(ID=99, Value1=100, Value2=199)         else:             param_value = 10 # 第二個參數是整數         args.append(param_value)     else:         print(f"未找到數據類型 {data_type_nodeid} 對應的 Python 類")  # 調用方法 try:     result = await method_node.call_method(*args)     print(f"方法調用結果: {result}") except Exception as e:     print(f"方法調用失敗: {e}")

注意事項:

  • get_class_from_nodeid() 函數需要維護一個包含所有可能的數據類型 NodeId 到 Python 類映射的字典。確保該字典包含了你所使用的自定義數據類型。
  • 對于復雜的數據類型(例如結構體),可能需要根據數據類型的定義,手動創建相應的 Python 類。
  • 錯誤處理至關重要。確保捕獲可能發生的異常,例如未找到數據類型對應的 Python 類,或者方法調用失敗等。

總結:

通過讀取方法的 “0:InputArguments” 屬性,并使用 get_class_from_nodeid() 函數將數據類型 NodeId 轉換為 Python 類,我們可以實現動態地檢測和轉換 OPC UA 方法的輸入參數。這種方法提高了客戶端的靈活性和可擴展性,使其能夠處理各種自定義數據類型,并調用不同的方法。 重要的是要維護一個完整的數據類型映射字典,并進行適當的錯誤處理,以確保程序的穩定性和可靠性。

? 版權聲明
THE END
喜歡就支持一下吧
點贊14 分享