diff --git a/asyncua/ua/uatypes.py b/asyncua/ua/uatypes.py index 120a0c017..0960d15da 100644 --- a/asyncua/ua/uatypes.py +++ b/asyncua/ua/uatypes.py @@ -2,6 +2,7 @@ implement ua datatypes """ +import binascii import sys from typing import Optional, Any, Union, Generic, List import collections @@ -12,6 +13,7 @@ import itertools from datetime import datetime, timedelta, timezone from dataclasses import dataclass, field +from base64 import b64encode, b64decode # hack to support python < 3.8 if sys.version_info.minor < 10: @@ -548,9 +550,15 @@ def _from_string(string): elif k == "b": ntype = NodeIdType.ByteString if v[0:2] == '0x': + # our custom handling, normaly all bytestring nodes are base64 identifier = bytes.fromhex(v[2:]) else: - identifier = v.encode() + try: + # this should be the default case base64 + identifier = b64decode(v.encode("ascii")) + except (binascii.Error, ValueError): + # fallback for backwards compatiblity just use the bytestring + identifier = v.encode('ascii') elif k == "srv": srv = int(v.strip()) elif k == "nsu": @@ -579,7 +587,7 @@ def to_string(self): ntype = "g" elif self.NodeIdType == NodeIdType.ByteString: ntype = "b" - identifier = '0x' + identifier.hex() + identifier = b64encode(identifier).decode('ascii') string.append(f"{ntype}={identifier}") return ";".join(string) diff --git a/tests/test_common.py b/tests/test_common.py index e31f30787..2e344e9b3 100644 --- a/tests/test_common.py +++ b/tests/test_common.py @@ -12,7 +12,7 @@ import tempfile from datetime import datetime, timedelta from pathlib import Path - +from base64 import b64encode import pytest from asyncua import Node, ua, uamethod @@ -182,6 +182,8 @@ async def test_node_bytestring(opc): ) node = opc.opc.get_node("ns=2;b=VarByteString") assert node == var + node = opc.opc.get_node(f"ns=2;b={b64encode(b'VarByteString').decode()}") + assert node == var node = opc.opc.get_node(f"ns=2;b=0x{b'VarByteString'.hex()}") assert node == var