коиент
return f"ns={namespace_index};s={ost_name}{stand_name}:{address}.{suffix}"
async def _discover_endpoint_url(opc_url: str, timeout: float = OpcConst.DISCOVERY_TIMEOUT_S) -> str:
"""
Получает полный endpoint URL через GetEndpoints.
"""
try:
endpoints = await asyncio.wait_for(Client.get_endpoints(opc_url), timeout=timeout)
if endpoints and getattr(endpoints[0], "EndpointUrl", None):
logger.info("[OPC] Discovery: найден endpoint %s", endpoints[0].EndpointUrl)
return endpoints[0].EndpointUrl
except Exception as error:
logger.warning("[OPC] Discovery не удался (%s), используем исходный URL %s", error, opc_url)
return opc_url
def read_data_value_sync(
opc_url: str,
node_id: str,
timeout: float = OpcConst.CONNECT_TIMEOUT_S,
) -> ua.DataValue:
"""
Синхронное подключение и чтение DataValue тега. Используется в setup-части
(синхронный контекст pytest), чтобы понять, что OPC UA сервер жив и отдаёт данные.
"""
async def _read() -> ua.DataValue:
endpoint_url = await _discover_endpoint_url(opc_url)
client = Client(url=endpoint_url, timeout=timeout)
try:
await client.connect()
logger.info("[OPC] Подключено к endpoint %s", endpoint_url)
return await client.get_node(node_id).read_data_value()
finally:
await client.disconnect()
return asyncio.run(_read())
class OpcUaClient:
арх констант
OPERATION_TIMEOUT_S: float = 5.0
# Таймаут discovery (GetEndpoints) перед подключением.
DISCOVERY_TIMEOUT_S: float = 5.0
стенд сет
data_value = read_data_value_sync(opc_url, probe_node_id)
except Exception as error:
logger.error(
"[SETUP] [ERROR] OPC UA проверка не удалась. URL=%s node=%s\n%s",
opc_url,
probe_node_id,
traceback.format_exc(),
)
raise RuntimeError(
f"[SETUP] [ERROR] OPC UA сервер недоступен ({opc_url}): {type(error).__name__}: {error}"
) from error
status = data_value.StatusCode
конфтест удалить:
allure.attach(msg, name="OPC сервер недоступен", attachment_type=allure.attachment_type.TEXT)
OPERATION_TIMEOUT_S: float = 5.0
# Таймаут discovery (GetEndpoints) перед подключением.
DISCOVERY_TIMEOUT_S: float = 5.0